前に作成したESP-WROOM-02による無線LANチャイムを改造していたら、なぜかハマってしまったので書きます。。
今回、やろうとしたところは「送信機と受信機のコネクションが切れたときに、わかるようにしよう」ということです。
もともとのプログラムにはシリアル出力で「DisConnect」のステータスを出す機能があるのですが、通常はPCに接続して使わないので、わかりません。
(略) void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) { switch(type) { case WStype_DISCONNECTED: Serial.printf("[WSc] Disconnected!\n");// <---------シリアルにしかDisConnect情報が行かない。 ConnectFlag = false; break; case WStype_CONNECTED: { (略)
こんな感じだったので、送信機についているLEDをDISCONNECTEDの時には、点滅させるようにしようと思いました。
(略) void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) { switch(type) { case WStype_DISCONNECTED: Serial.printf("[WSc] Disconnected!\n"); ConnectFlag = false; //ここから追加(LEDチカチカ) digitalWrite(led1, HIGH); delay(100); digitalWrite(led1, LOW); delay(100); digitalWrite(led1, HIGH); delay(100); digitalWrite(led1, LOW); delay(100); digitalWrite(led1, HIGH); delay(100); digitalWrite(led1, LOW); delay(2000); //ここまで追加 break; case WStype_CONNECTED: { (略)
こんな感じです。
で、前回から日数が経っていて、Arduino IDEも新しくなっていてVersionが1.8.9で、一方ESP8266のライブラリ(esp8266 by ESP8266 Community)もver.2.5.2にバージョンアップしています。
これを使ってコンパイル&インストールしてみました。
ところが、うまく動いてくれません。
Arduino IDEのシリアルモニタをみると、下のようになっています。
この"ISR not in IRAM"というのを、とりあえずググってみますと、ESP8266のライブラリを新しくすると出るようです。古いバージョンなら大丈夫だということ。
さらに調べると、Arduino Forumで、関係するスレッドがみつかりました。
端的に書きますと、この問題は「ESPのバージョン2.5.1以降で、割り込み処理を行う場合に発生する」、ということです。
新しいバージョンにおけるバグではなく、古いバージョンにおいてIRAMにISRがない(予測不可能なリスクを持っている)ことを回避するために必要だそうです。
解決策としては、ICACHE_RAM_ATTRを追加すればよいそうです。これを追加してプログラムを修正してみました。
void ICACHE_RAM_ATTR intFunc(); で、intFuncが割り込みルーチンです。
#include <ESP8266WiFi.h> #include <WebSocketsClient.h> //https://github.com/Links2004/arduinoWebSockets #include <Ticker.h> #define btn1 4 //スイッチ1のGPIO //LED #define led1 13 //LED1のGPIO //ServerIP const char* ServerIp("192.168.xx.xx"); //サーバーに割り当てるアドレス int ServerPort = 8000; //Ssid, pass const char* Ssid = "xxxx"; //ルータのID const char* Password = "xxxx"; //ルータのpassword int b; //ボタン状態 WebSocketsClient webSocket; //タイマ初期化 Ticker ticker; //Connected Flag 接続されるとtrue bool ConnectFlag = false; //Timer callback void doBlockingIO() { Serial.println(b); if(ConnectFlag){ if(b){ webSocket.sendTXT("1"); //Send Message b=0; digitalWrite(led1, HIGH); delay(500); digitalWrite(led1, LOW); delay(500); digitalWrite(led1, HIGH); delay(500); digitalWrite(led1, LOW); } else{ webSocket.sendTXT("0"); //Send Message } } } void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) { switch(type) { case WStype_DISCONNECTED: Serial.printf("[WSc] Disconnected!\n"); ConnectFlag = false; //DisConnect対策を追加 digitalWrite(led1, HIGH); delay(100); digitalWrite(led1, LOW); delay(100); digitalWrite(led1, HIGH); delay(100); digitalWrite(led1, LOW); delay(100); digitalWrite(led1, HIGH); delay(100); digitalWrite(led1, LOW); delay(2000); //DisConnect対策ここまで break; case WStype_CONNECTED: { Serial.printf("[WSc] Connected to url: %s\n", payload); ConnectFlag = true; } break; case WStype_TEXT: Serial.printf("[WSc]Recv: %s\n", payload); // send data to back to Server //webSocket.sendTXT(payload, lenght); break; case WStype_BIN: Serial.printf("[WSc] get binary lenght: %u\n", lenght); hexdump(payload, lenght); // echo data back to Server webSocket.sendBIN(payload, lenght); break; case WStype_ERROR: Serial.printf("We received an error \n"); break; default: break; } } void ICACHE_RAM_ATTR intFunc();// <-----------------これを追加する void setup() { pinMode(led1, OUTPUT); Serial.begin(115200); Serial.print("\nStart\n"); pinMode(btn1, INPUT_PULLUP); //btn1は入力でプルアップされている attachInterrupt(btn1,intFunc,FALLING); //btn1がHigh→Lowで割り込みルーチンへ WiFi.begin(Ssid, Password); while(WiFi.status() != WL_CONNECTED) { Serial.print('.'); delay(500); } Serial.println(); Serial.printf("Connected, IP address: "); Serial.println(WiFi.localIP()); //server ip webSocket.begin(ServerIp, ServerPort); webSocket.onEvent(webSocketEvent); Serial.println("Client started\n"); digitalWrite(led1, HIGH); delay(500); digitalWrite(led1, LOW); delay(500); digitalWrite(led1, HIGH); delay(500); digitalWrite(led1, LOW); delay(500); digitalWrite(led1, HIGH); delay(500); digitalWrite(led1, LOW); //set timer ticker.attach(2, doBlockingIO); //2sec } void loop() { webSocket.loop(); } void intFunc(){ b=1; //ボタンが押されたステータス発行 }
これで、コンパイルかけて、書き込み、実行させると、
正常に動作するようになりました。
お疲れ様でした。