Program Resource

開発者向け各種コード、アルゴリズム、リソース情報ライブラリ もしくはねふぁの覚え書き

Arduino自体のCPUはARMプロセッサーの様に強力ではなく、UNOレベルだとメモリも2K程度と非力ではあるが、Arduinoの可能性を無限に広げるシールドとライブラリの豊富さに驚かされる。

WiFiシールドもその一つで、Arduinoにさくっと乗せてソフトをちょこっと書くだけで無線LAN通信が出来、簡単ではあるがWebサーバーも出来てしまう。

今回使用するのはCC3000のチップを使用したWiFiシールド。AdafruitのCC3000 WiFiシールドと互換性がありライブラリもそのまま利用できる。

DSC03475

チップ自体が技適認証を取得済のため、国内使用も安心である。

まずはライブラリをインストール。Adafruitのページからライブラリをダウンロードし、Arduino IDEでライブラリをインポートする。

https://github.com/adafruit/Adafruit_CC3000_Library/archive/master.zip

インポート後、スケッチの例を開くと色々なサンプルが出てくる。とりあえずはbuildtestのサンプルスケッチを開く。

スケッチを開いた後、下記行を編集し、接続したいアクセスポイントとパスワード、セキュリティ方式を記述する。

#define WLAN_SSID "myNetwork" // cannot be longer than 32 characters!
#define WLAN_PASS "myPassword"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY WLAN_SEC_WPA2

後はビルドして実行。シリアルポートモニターを開くと接続状況が表示される。(デフォルトは115200 baud)

最初にCC3000のファームバージョンやMACアドレス、次にスキャンしたアクセスポイントのリスト、アクセスポイント接続後にIPアドレス等の情報、最後にadafruitへのpingテストを行い終了している。

Hello, CC3000!

RX Buffer : 131 bytes
TX Buffer : 131 bytes
Free RAM: 1237

Initialising the CC3000 ...
Firmware V. : 1.24
MAC Address : 0x08 0x00 0x28 0xFF 0xFF 0xFF
Started AP/SSID scan
Networks found: 7
================================================
SSID Name : PRS300SE-123456789-1
RSSI : 36
Security Mode: 3

SSID Name : PRS300SE-123456789-2
RSSI : 36
Security Mode: 1

SSID Name : PS3-123456789
RSSI : 44
Security Mode: 2

SSID Name : espresso
RSSI : 61
Security Mode: 3

SSID Name : latte
RSSI : 53
Security Mode: 3

SSID Name : mocha
RSSI : 64
Security Mode: 3

================================================

Deleting old connection profiles

Attempting to connect to mocha
Started AP/SSID scan
Connecting to mocha...Waiting to connect...Connected!
Request DHCP

IP Addr: 192.168.1.178
Netmask: 255.255.255.0
Gateway: 192.168.1.30
DHCPsrv: 192.168.1.30
DNSserv: 192.168.1.30
www.adafruit.com -> 207.58.139.247

Pinging 207.58.139.247...5 replies
Ping successful!
Closing the connection

CC3000はSmartConfigと言う機能を持っており、接続先アクセスポイントの情報をiPhoneやAndroidのアプリから設定する事が出来る。SmartConfigCreateスケッチをArduinoに書き込みAP情報をスマホから設定するとCC3000に接続先情報が保存され、SmartConfigReconnectのスケッチを参考に接続を行うと、次回からCC3000に保存された情報を元にアクセスポイントに接続する様になる。詳細については割愛する(GoogleでCC3000 SmartConfigで検索)。

ライブラリには以下のサンプルスケッチが含まれているので、これらのサンプルをベースに大体の事は出来るのではないかと思う。Tweetのサンプルにはアカウント認証のコードも含まれている。

  • buildtest 基本接続テスト
  • ChatServer 受信データを全クライアントへ再配信
  • EchoServer 受信データをそのままエコー配信
  • GeoLocation freegeoip.netのサービスを使い、現在地情報を取得
  • InternetTime ntpサーバーから時刻を取得、一日一回同期を行う
  • ntptest ntpサーバーから時刻取得と表示(一回のみ)
  • SendTweet ツイートを書き込む
  • WebClient Webページを取得する

EchoServerのスケッチを開き、実行後telnetからポート7を開くと接続できるので、適当に入力すると一文字一文字エコーが返ってくる。(最近のWindowsは標準でtelnetが入っていないので、プログラムの追加と削除からtelnetクライアントを追加する)

IPアドレスはシリアルモニターで確認、Windowsのコマンドプロンプト等からtelnetでポート7に接続する。

telnet 192.168.1.5 7

cmd_telnet

では、echoサーバーをベースとして簡易Webサーバーを作ってみよう。

HTTP通信はポート80なので、LISTEN_PORTを80に変更する。そして、クライアントからのデータを一時バッファーに保管し、改行コードが来た時点でデータの中身を確認する。本互換ボードは6番PinがLEDライトになっているので、AP通信後とデータ通信時にオン・オフする様にして、通信状況が分かる様にしている。(緑が電源、オレンジが6番PIN制御)

DSC03476

行頭がGETの場合、その後に取得したいページの情報やCGIのGETメソッドのパラメーターが続く(HTTPの詳細についてはここでは割愛)。クライアントのデータは最後が連続した改行が二回続くので、改行が二回来た時点でWeb情報をクライアントに返信する(HTMLコードを返す)。

下記例ではCGIで数字入力のページを表示するサンプル。下記スケッチを実行後ブラウザからアクセスすると、入力エリアと送信ボタンが表示される。

browser_sample

適当な数値を入力してGoボタンを押すと、Arduinoの下記サンプルスケッチではreplypage関数のservo_param変数にその値が入る様にしているので、ここでサーボモーターを制御するコードやリレーを制御すれば、Webから操作できるArduino工作の出来上がりである。

browser_sample2

Webから情報を取得したり、ブラウザーから何かを制御したり、センサーの情報をブラウザーから確認出来る様にするなど、WiFiシールドを使う事で大幅にArduinoの可能性が広がる。

SwitchScienceさんの小型LCD表示を追加してみました

#include <Adafruit_CC3000.h>
#include <SPI.h>
#include "utility/debug.h"
#include "utility/socket.h"

#define ADAFRUIT_CC3000_IRQ   3  // MUST be an interrupt pin!
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT, SPI_CLOCK_DIV2);

#define WLAN_SSID       "ssidname"           // cannot be longer than 32 characters!
#define WLAN_PASS       "xxxxxxxx"
#define WLAN_SECURITY   WLAN_SEC_WPA2

#define LISTEN_PORT 80
char in_buffer[256];
int in_size = 0;
char req_page[64];
char in_ch;
char last_ch;
char subch[128];
char *cmd;

Adafruit_CC3000_Server httpServer(LISTEN_PORT);

void setup(void)
{
  pinMode(6, OUTPUT);
  Serial.begin(115200);
  Serial.println(F("Hello, CC3000!\n"));
  Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
  Serial.println(F("\nInitializing..."));
  if (!cc3000.begin()) {
    Serial.println(F("Couldn't begin()! Check your wiring?"));
    while (1);
  }
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while (1);
  }
  Serial.println(F("Connected!"));
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP()) {
    delay(100); // ToDo: Insert a DHCP timeout!
  }
  while (! displayConnectionDetails()) {
    delay(1000);
  }

  Serial.println(F("\r\nNOTE: This sketch may cause problems with other sketches"));
  Serial.println(F("since the .disconnect() function is never called, so the"));
  Serial.println(F("AP may refuse connection requests from the CC3000 until a"));
  Serial.println(F("timeout period passes.  This is normal behaviour since"));
  Serial.println(F("there isn't an obvious moment to disconnect with a server.\r\n"));

  httpServer.begin();

  Serial.println(F("Listening for connections..."));
  digitalWrite(6, HIGH);
}

void loop(void)
{
  Adafruit_CC3000_ClientRef client = httpServer.available();
  if (client) {
    digitalWrite(6, LOW);
    if (client.available() > 0) {
      in_ch = client.read();
      if (in_size < 255 && in_ch != '\r' && in_ch != '\n')
        in_buffer[in_size++] = in_ch;
      if (in_ch == '\r') {
        in_buffer[in_size] = '\0';
        Serial.println(in_buffer);
        cmd = getparam(in_buffer, ' ', 0);
        if (strcmp(cmd,"GET") == 0)
          strcpy(req_page,getparam(in_buffer, ' ', 1));
        in_size = 0;
        if (last_ch == '\r') //double linefeed, end of request
          replypage(&client);
      }
      if (in_ch == '\r' || in_ch == '\n')
        last_ch = '\r';
      else
        last_ch = ' ';
    }
    digitalWrite(6, HIGH);
  }
}

//return n-th char array separated with specified character
char *getparam(char *txt, char seperator, int index) {
  int strcnt = 0;
  int indcnt = 0;
  memset(subch, 0, 128);
  for (int i = 0; i < strlen(txt); i++) {
    if (txt[i] == seperator) {
      indcnt++;
      if (indcnt > index)
        break;
    } else if (indcnt == index) {
      subch[strcnt++] = txt[i];
    }
  }
  return &subch[0];
}

void replypage(Adafruit_CC3000_ClientRef *pclient) {
  Serial.print("[req]");
  Serial.println(req_page);
  if (strcmp(getparam(req_page,'=',0),"/?servo") == 0){
    int servo_param = atoi(getparam(req_page,'=',1));
    Serial.print("[Servo]");
    Serial.println(servo_param,DEC);
    //form input value stored to servo_param, do whatever needed here.
  }

  pclient->println("HTTP/1.1 200 OK");
  pclient->println("Content-Type: text/html");
  pclient->println(""); 
  pclient->fastrprint("<html><title>Arduino Web</title><body>");
  char buffer[128];
  sprintf(buffer,"Requested : %s",req_page);
  pclient->fastrprint(buffer);
  pclient->fastrprint("<BR><form method=\"GET\" action=\"/\">");
  pclient->fastrprint("<input type=\"number\" name=\"servo\"><input type=\"submit\" value=\"Go\"></form>");
  pclient->fastrprint("</body></html>");
  delay(1000);
  pclient->close();
}

bool displayConnectionDetails(void)
{
  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;

  if (!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv)){
    Serial.println(F("Unable to retrieve the IP Address!\r\n"));
    return false;
  }else{
    Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
    Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
    Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
    Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
    Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
    Serial.println();
    return true;
  }
}

WiFiシールド自体ピンを多数使うのがやや難点ではある。

[GPG] Arduino CC3000 WiFiシールド SDカードスロット付
[GPG] Arduino CC3000 WiFiシールド SDカードスロット付


Arduino用WiFiシールドで無線LAN通信と簡易Webサーバー」 に3件のコメント

  1. 技系のおっちゃん より:

    ありがたく記載されてる情報を参考にさせてもらっている者です。
    実は、Arduino_UNOとCC3000を組み合わせて、そちらの内容に従ってモバイルWiFiルータとの間でbuildtestを行おうとしたところ、シリアル通信からの表示が”Initialising the CC3000 …”のところで静止してしまいます。一応PCによる無線LAN機能で”SSID”と”password”の確認は行っており、そちらでは問題なかったのですが・・。考えられる原因などありましたら、ご指導願えないでしょうか?
    よろしくお願いいたします。

    • ねふぁ より:

      buildtestの場合、Initializingの次にFirmwareの情報が出ますので、Initializingで止まる場合、恐らく信号がシールドから来ずずっと待ち状態が続いていると考えられます

      接続は半田不良等で上手くシールドと通信できていないか、シールドが異常かもしれません。シールドを抜差ししても改善しない様であれば他のArduinoがあれば差し替えてみて、それでもだめならシールド不良(ファームウェアかハード的な不良)かもしれません。

      • 技系のおっちゃん より:

        なるほどです。
        確認したところ、ご指摘のとおりピンの半田に不良があったようです。(応力がかかると導通障害を起こしていたようで、基板単体での導通は問題なかったです。)修正を行ったところ、無事に通信しました。
        ありがとうございました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*