前に作成した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; //ボタンが押されたステータス発行
}
これで、コンパイルかけて、書き込み、実行させると、

正常に動作するようになりました。
お疲れ様でした。