Arduino自体のCPUはARMプロセッサーの様に強力ではなく、UNOレベルだとメモリも2K程度と非力ではあるが、Arduinoの可能性を無限に広げるシールドとライブラリの豊富さに驚かされる。
WiFiシールドもその一つで、Arduinoにさくっと乗せてソフトをちょこっと書くだけで無線LAN通信が出来、簡単ではあるがWebサーバーも出来てしまう。
今回使用するのはCC3000のチップを使用したWiFiシールド。AdafruitのCC3000 WiFiシールドと互換性がありライブラリもそのまま利用できる。
チップ自体が技適認証を取得済のため、国内使用も安心である。
まずはライブラリをインストール。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
では、echoサーバーをベースとして簡易Webサーバーを作ってみよう。
HTTP通信はポート80なので、LISTEN_PORTを80に変更する。そして、クライアントからのデータを一時バッファーに保管し、改行コードが来た時点でデータの中身を確認する。本互換ボードは6番PinがLEDライトになっているので、AP通信後とデータ通信時にオン・オフする様にして、通信状況が分かる様にしている。(緑が電源、オレンジが6番PIN制御)
行頭がGETの場合、その後に取得したいページの情報やCGIのGETメソッドのパラメーターが続く(HTTPの詳細についてはここでは割愛)。クライアントのデータは最後が連続した改行が二回続くので、改行が二回来た時点でWeb情報をクライアントに返信する(HTMLコードを返す)。
下記例ではCGIで数字入力のページを表示するサンプル。下記スケッチを実行後ブラウザからアクセスすると、入力エリアと送信ボタンが表示される。
適当な数値を入力してGoボタンを押すと、Arduinoの下記サンプルスケッチではreplypage関数のservo_param変数にその値が入る様にしているので、ここでサーボモーターを制御するコードやリレーを制御すれば、Webから操作できるArduino工作の出来上がりである。
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シールド自体ピンを多数使うのがやや難点ではある。
ありがたく記載されてる情報を参考にさせてもらっている者です。
実は、Arduino_UNOとCC3000を組み合わせて、そちらの内容に従ってモバイルWiFiルータとの間でbuildtestを行おうとしたところ、シリアル通信からの表示が”Initialising the CC3000 …”のところで静止してしまいます。一応PCによる無線LAN機能で”SSID”と”password”の確認は行っており、そちらでは問題なかったのですが・・。考えられる原因などありましたら、ご指導願えないでしょうか?
よろしくお願いいたします。
buildtestの場合、Initializingの次にFirmwareの情報が出ますので、Initializingで止まる場合、恐らく信号がシールドから来ずずっと待ち状態が続いていると考えられます
接続は半田不良等で上手くシールドと通信できていないか、シールドが異常かもしれません。シールドを抜差ししても改善しない様であれば他のArduinoがあれば差し替えてみて、それでもだめならシールド不良(ファームウェアかハード的な不良)かもしれません。
なるほどです。
確認したところ、ご指摘のとおりピンの半田に不良があったようです。(応力がかかると導通障害を起こしていたようで、基板単体での導通は問題なかったです。)修正を行ったところ、無事に通信しました。
ありがとうございました。