ESP8266でシリアルからWiFiとBlynk設定をしてEEPROMに保存し、割り込みでパルスを数えてBlynkで送信してみた。

ESP8266を用いて、WiFi経由Blynkに接続する場合、WiFiの設定やBlynkのAuthentication情報を、プログラム内に直接書き込む例が多く掲載されているが、多くのデバイスを接続する際など、すべてのデバイスに別々のプログラムを開発して書き込むのは大変手間であり、間違いのもとになる。ここでは、ブートのモードを切り替えることにより、設定モードで立ち上げたときは、シリアル通信経由で、SSID等を入力してEEPROMに書き込み、ノーマルモードで立ち上げたときに、その情報を用いて、WiFiやBlynkに接続して動作をするようにした。このようにすることで、多くのデバイスに同様に処理をさせる場合や、WiFi環境、Blynk設定が変わった際に、プログラムを一切修正することなく、対応ができるようになる。 ネット上では、自分自身のSoftAPでアクセスポイントにして、Web経由で設定情報を入力する例もいくつか見られるが、シリアルを使う方法は、それよりもシンプルだと思う。 ただし、設定時に、何らからのシリアルターミナルは必要になる(Arduino IDEを使っても良いし、TeraTerm等のターミナルソフトを使っても良い)

ピン設定および機能

GPIO IO function 説明

5

Input

Pull Up

モード選択

リセット後のBoot時に一度だけ読み、Highの場合はノーマル起動、Lowの場合には、設定モードで起動する。

内蔵Pullupを使っており、何も接続しなければノーマル起動する。設定モードで起動したいときは、GNDに接続する。

12

Input

Interrupt

パルス計測入力1 パルスカウント1の入力ピン。Pullupはなし。内部で割り込みを使って、Falling Edgeのカウントをする。1秒間に入力されたパルス数を計測してBlynkのV0に1秒毎に出力する。
13

Input

No Pullup

CdS入力

(単純なデジタル入力として)

本来はADCで電圧を読んで、CdS(光量検出)をすべきだが、ESP8266にはADCが一つしかなく、また少し特殊なので、今回は単純に抵抗分割したCdS出力をGPIOのデジタルしきい値を用いて判別する目的で使用している。正確なしきい値は設定できないが、回路が単純なのでここはよしとする。毎秒、ポート値を読んで、BlynkのV2に出力する。

14

Input

Interrupt

パルス計測入力2

パルスカウント2の入力ピン。Pullupはなし。内部で割り込みを使って、Falling Edgeのカウントをする。1秒間に入力されたパルス数を計測してBlynkのV1に1秒毎に出力する。

EEPROMメモリ配置

本来であれば、セキュリティーのため、暗号化した上でEEPROMに保存すべきであろうが、ここでは簡易的にそのままプレーンで書き込んである。

EEPROMエリア全体としては、コード上で1024バイト確保した。(ESP8266の最大EEPROMサイズは、4096バイトらしい)

構造体として宣言し、EEPROM領域への書き込み、読み出しは確保した全体(1024バイト)に対して行い、バッファに対する構造体メンバーとしてそれぞれの値へアクセスしている。構造体の形として、EEPROMから読み書きする関数として、EEPROM.getと EEPROM.putがあるが、どちらも、特殊な記述方法(EEPROM.put<CONFIG>(0, buf)のような方法で、アドレスゼロから、bufのサイズを、構造体CONFIGの形状で、get, putすることができる。バイト列を必要な形で取り出せるので大変便利。

name

バイト数 タイプ 内容
ssid 64 文字列 SSIDを保持
pass 64 文字列 WiFi パスワード
dev 64 文字列 デバイス名
auth 64 文字列 Blynk Authenticationキー
hostip 64 文字列 ソケット接続時のサーバーIPアドレス
port 64 文字列 ソケット接続時のポート番号

シリアルポート設定

ESP8266はリセット時に、内部のファームウエアからシリアルポートに文字列が出力されるが、このボーレート(スピード)が74880に固定されていて変更できない。文字化けするのは気持ちが悪いので、PC側のターミナルソフトのスピードをこれに合わせることにする。そのうえで、setup()の中で行う Serial.beginも、この速度に合わせ Serial.begin(74880)で設定する。

Arduino IDEのシリアルモニタには、このスピードは選択肢にあるからそれを選べば良いが、TeraTermのスピード選択肢の中には無いため、TeraTermのシリアルポート設定の画面のスピードの項目に、直接数字で 74880と入力する必要がある。(以下参照)

image

パルスカウント

ピンに入力されるパルスの数を数えるために、割り込みを使用する。割り込みは、attachInterrupt関数でピンと処理関数、検出エッジ選択を紐つける。割り込み処理ルーチン内でブロッキング処理をさせると不具合のリスクが増えるので、割り込み内では最小の処理だけに留める。ここでは、カウンターのIncrementのを行う。割り込み内で変更する変数は、volatile宣言が必須。

割り込み処理ルーチンの頭に、ICACHE_RAM_ATTRと記述してあるのは、ネット情報によるとバグ対策(ボードマネジャーで登録したESP8266 by ESP8266 Communityのライブラリにおいて、バージョン2.5.1以降は、このおまじないが必要っぽい)。これを記述しないと、コンパイルは通るが実行時にエラーが発生する。

割り込みでカウントした数値を、1秒毎にBlynkへ送るが、1秒の計測は、BlynkTimerを使っている。ただ、BlynkTimerも割り込みを使っているので、その中では 1秒フラグだけを設定して、実際にBlynkに送る処理はメインループの中で行うようにしている。割り込み処理ルーチンは、「一刻も早く抜けること」が鉄則。

コード

/*
   config mode:
     read SSID, password, device name, Blynk authentiation
     data via Serial port one by one. Store them into EEPROM
     using CONFIG structure.


  normal mode:
     read configration data from EEPROM using CONFIG structure
     and use them for connecting to Blynk via WiFi configuration.


    count the pulse using interrupts,
     and read the CdS value (GPIO)/
     Send the data to Blynk every one seconds.


  mode pin : 5
   Pulse input pin : 14, 12
   CdS input pin : 13 (GPIO)


  2019/8/4 17:20 Yoshihiro Yasuda


*/


#include <EEPROM.h>
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>


struct CONFIG {
   char ssid[64];
   char pass[64];
   char dev[64];
   char auth[64];
   char hostip[64];
   char port[64];
};


CONFIG buf;
uint8_t seq = 0;


volatile int ctr1 = 0;
volatile int ctr2 = 0;
const uint8_t modePin = 5;
const uint8_t pulsePin1 = 14; //interrupt input pin
const uint8_t pulsePin2 = 12;
const uint8_t cdsPin1 = 13;
boolean f_1sec = false;
boolean f_bootmode = HIGH;


BlynkTimer timer;


ICACHE_RAM_ATTR void isr_pulse1() {
   ctr1 ++;
}


ICACHE_RAM_ATTR void isr_pulse2() {
   ctr2 ++;
}


void everyInterval() {
   f_1sec = true;
}


void setup() {
   Serial.begin(74880);
   while (!Serial);
   Serial.println(“”);


  pinMode(modePin, INPUT_PULLUP);
   f_bootmode = digitalRead(modePin);//H:Normal


  EEPROM.begin(1024);
   EEPROM.get<CONFIG>(0, buf);
   Serial.print(“Device Name:”);
   Serial.println(buf.dev);
   Serial.print(“SSID:”);
   Serial.println(buf.ssid);


  if (f_bootmode) { //Normal mode
     Serial.print(“Connecting to Blynk via WiFi…\n”);
     Blynk.begin(buf.auth, buf.ssid, buf.pass);
     pinMode(pulsePin1, INPUT);
     pinMode(pulsePin2, INPUT);
     pinMode(cdsPin1, INPUT);
     attachInterrupt(pulsePin1, isr_pulse1, FALLING);
     attachInterrupt(pulsePin2, isr_pulse2, FALLING);
     timer.setInterval(1000L, everyInterval);
   } else { //Config mode
     Serial.print(“Password:”);
     Serial.println(buf.pass);
     Serial.print(“Blynk Authentication:”);
     Serial.println(buf.auth);
     Serial.print(“SSID >”);
   }
}


void loop() {
   if (f_bootmode) loop_normal();
   else loop_config();
}


//—————————-
/// main loop for normal mode
//—————————-
void loop_normal() {
   uint8_t result1, result2, cds1;
   Blynk.run();
   timer.run();
   if (f_1sec) {
     f_1sec = false;
     result1 = ctr1;
     ctr1 = 0;
     result2 = ctr2;
     ctr2 = 0;
     cds1 = digitalRead(cdsPin1);
     Serial.print(result1);
     Serial.print(“,”);
     Serial.print(result2);
     Serial.print(“,”);
     Serial.println(cds1);
     Blynk.virtualWrite(V0, result1);
     Blynk.virtualWrite(V1, result2);
     Blynk.virtualWrite(V2, cds1 * 255);
   }
}
//———————————–
/// main loop for configuration mode
//———————————–
void loop_config() {
   if (seq <= 3) {
     if (Serial.available() > 0)
     {
       String ss = Serial.readStringUntil(‘\n’);
       ss.trim();//remove CR,LF,Spaces
       char str[129];
       int len = ss.length();
       ss.toCharArray(str, len + 1); //zero at the end.
       Serial.println(str);
       switch (seq) {
         case 0:
           strcpy(buf.ssid, str);
           seq += 1;
           Serial.print(“Password > “);
           break;
         case 1:
           strcpy(buf.pass, str);
           seq += 1;
           Serial.print(“Device Name > “);
           break;
         case 2:
           strcpy(buf.dev, str);
           seq += 1;
           Serial.print(“Blynk Authentication > “);
           break;
         case 3:
           strcpy(buf.auth, str);
           seq += 1;
           Serial.println(“Done.”);
           EEPROM.put<CONFIG>(0, buf);
           EEPROM.commit();
           break;
         default:
           break;
       }
     }
   }
}