Ⅶ. ESP32によるAirMonitor

 今回はまだESP-WROOM-32開発ボードをブレッドボードに組み付けたままですが、すでにESP32AirMonitorのハードウェアは完成しています。あとは計測・記録・サーバーなどの機能を統合して、所定の計測条件にしたがって計測を継続しながら、ブラウザからの要求に応答するソフトを仕上げるだけです。

   ※スケッチのダウンロードは右側の[Download]ボタンをクリックしてください。    

1.開発テーマの再整理

 ここでESP8266版AirMonitorで掲げた開発テーマを再整理しておきます。
(1)動作条件の設定・変更機能の装備

 AirMonitorの動作条件を弾力的に変更できるように、測定処理条件をSDカード上のファイル「AIRMON.PRM」に保持させます。必要に応じてその内容をメンテナンスできるように保守画面を新設します。
 保守画面を表示するために、コマンド入力画面に「mainte:動作条件を変更する」を追加しています。
 コマンド入力画面の入力欄で「mainte」と入力して、[実行]ボタンをクリックするか[Enter]キーをたたくと動作条件設定画面に切り替わります。条件設定画面ではSSIDやPasswordも変更できますが、入力内容が間違っていると次回の起動ができなくなるので注意が必要です。
 変更した内容は直ちにファイルに書き込まれますが、MCUボードのリセットスイッチを押した時点で有効になります。


(2)自動計測記録処理とサーバーの並行動作の実現

 AirMonitorを起動すると、システムクロックの「分」が「計測開始分」で設定した値になるまで待って計測を開始します。以後は設定された時間間隔ごとに測定して、測定値をSDカード上のファイル(logfile32.txt)に記録します。さらに、指定された時間間隔でNTPサーバーと通信してシステムクロックの時刻合わせを行います。
 これらの自動化された処理と並行して、起動後はいつでもWebサーバーとして機能させる必要があります。計測中でも計測開始前でも、リアルタイム計測や動作条件の変更、記録されている計測データの検索表示ができなければなりません。ただし、動作条件変更後のシステムリセットについては、当面は手操作(ESP32開発ボード上の[RESET]ボタン押下)によることとします。

2.全体の配線について

 次にMCUボードと計測ボードの配線を掲載します。ESP-WROOM-32開発ボード内の配線は省略しているので、開発ボード上の2つのスイッチやUSBシリアル変換などの記載はありません。MCUボード内のマイクロSDカード装置との配線、MCUボードと計測ボード間の配線だけに限定されていることに注意して下さい。またセンサーボードの詳細については『超小型格安チップ「ESP-WROOM-02(ESP8266)」はどこまで使えるか?』の「Ⅲ. I2Cバスと複数センサー」を参照してください。

 開発中のMCUボードの電源は、PCに接続したUSBケーブルから供給されます。計測ボードの電源は専用電源の3.3Vと5Vのラインから供給します。Ⅳ章と重複しますが、以下にもう一度ハードウェア全体の写真を掲載しておきましょう。


3.汎用MCUボードの製作

 ここまでブレッドボードに組み付けていた開発ボードとミニSDカード装置を、さらに利用しやすいようにユニバーサル基板に組み付けてみました。両者の配線は基板裏面でハンダ付けしています。またジャンパーワイヤーで接続利用できるよう、ピンソケットでESP-WROOM-32の大半のピンを引き出しています(FLASH接続に使用されて利用できない6つのピンを除くすべて)。
 使用したパーツは次のとおりです(秋月電子通商で購入)。
   ・ガラスコンポジット・ユニバーサル基板(72x47mm、25x15穴) 1枚 60円
   ・ピンソケット(10P) 2個  20円/個
   ・ピンソケット(6P)  2個  40円/個
   ・3mmプラネジと14mm六角スペーサー 4本 1セット 50円
   ・配線(手持ちのもの少々)

 マイクロSDカード装置との接続は上の配線図を見ていただくことにして、参考までにESP-WROOM-32からピンソケットへの引き出し図を掲げておきます。

 写真右上のように、計測ボードとの接続はきわめてシンプルになります。写真はパソコンとUSB接続した状態ですが、スケッチ完成後はUSBケーブルを外して、ピンソケット「CN-3の左端」を専用電源の3.3Vラインに接続すれば実行を開始します。


4.ソフト開発のポイント

(1)基幹部の処理

 最終的なスケッチのサイズは1,200行を超えますが、setup()とloop()で構成される基幹部の処理はコンパクトです。
 以下にそのフローチャートを示します。


 今回はESP8266との対比と移行を中心に説明してきたため、フローチャートで分からない部分があるかも知れません。不明点については、『超小型格安チップ「ESP-WROOM-02(ESP8266)」はどこまで使えるか?』の該当する部分を適宜参照してください。
 ブルーの「外部設定条件を読み込む(readParameterFile)」は、文字通りSDカード上のファイルから設定条件を読み取る処理です。子細はソースコードをダウンロードしていただき、readParameterFile()の部分をご覧ください。以下では割込処理とWebサーバー関連の要点だけを取り上げます。
 まず割込処理用グローバル変数定義、続いてISR関数、初回設定処理(InitialProcess)と割込処理のコードを眺め、Webサーバー関連部分を再度確認します。


(1)割込処理用グローバル変数

 定時計測と定時時刻調整の割り込みを扱うために、2組の割込検知用カウンターとタイマー設定用ポインターを設置し、同期用変数timerMuxを定義しています。
// Timer interruption control
volatile int timeCounter1;    // For measurement
volatile int timeCounter2;    // For time adjustment
hw_timer_t *timer1 = NULL;    // For measurement
hw_timer_t *timer2 = NULL;    // For time adjustment
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

(2)割込処理ISR関数

 計測と時刻調整用の2組のISR関数onTimer1とonTimer2を記述しています。どちらも割り込み発生時に、クリティカルセクション内で割込検知用カウンターをインクリメントするだけです。
/*****************************************************************************
 *                          Interrupt Service Routin                         *
 *****************************************************************************/
void IRAM_ATTR onTimer1(){
  // Increment the counter and set the time of ISR
  portENTER_CRITICAL_ISR(&timerMux);
  timeCounter1++;
  portEXIT_CRITICAL_ISR(&timerMux);
}

void IRAM_ATTR onTimer2(){
  // Increment the counter and set the time of ISR
  portENTER_CRITICAL_ISR(&timerMux);
  timeCounter2++;
  portEXIT_CRITICAL_ISR(&timerMux);
}

(3)初回設定処理

 初回設定処理は、初期化処理ブロックsetupにおいて、計測開始時刻が到来した時に1回だけ呼び出される処理です。kickRoutineWorkで初回の計測処理を行わせた後、2組の割込タイマーを以下の手順で設定しています。ここでtimer1が計測用に、timer2が時刻補正用に対応づけられます。
  ・使用タイマーの指定と初期化処理
  ・割込処理関数(ISR)の設定
  ・タイマー動作間隔の指定
  ・タイマーの有効化
/*
 * Run only once at the beginning.
 */
void InitialProcess()
{
  Serial.println(">> InitialProcess()");
    // 1st measuement
    kickRoutineWork();

    // Timer: interrupt time and event setting.
    timer1 = timerBegin(0, 80, true);
    timer2 = timerBegin(1, 80, true);

    // Attach onTimer function.
    timerAttachInterrupt(timer1, &onTimer1, true);
    timerAttachInterrupt(timer2, &onTimer2, true);

    // Set alarm to call onTimer function every second (value in microseconds).
    timerAlarmWrite(timer1, (iIntervalTime * 1000000), true);
    timerAlarmWrite(timer2, iNtpInterval * 1000000, true);

    // Start an alarm
    timerAlarmEnable(timer1);
    timerAlarmEnable(timer2);
}

(4)割込処理のコード

 割込処理は繰り返し処理ブロックloop内に記述します。
 timer1で設定時間毎に割り込みが発生すると、対応するISR関数内でtimeCounter1がインクリメントされます。割込処理ではtimeCounter1の状態を監視して、インクリメントされたことが分かるとクリティカルセクション内で即デクリメントし、一連の計測処理制御kickRoutineWorkを呼んで計測を実行させます。
 これに続き、同様にtimer2のインクリメントを感知して、adjustTimeを呼んで時刻補正をさせています。
void loop() {
                    :
                    :
    /* [Timer interrupt process] */
    if (timeCounter1 > 0) {
      portENTER_CRITICAL(&timerMux);
      timeCounter1--;
      portEXIT_CRITICAL(&timerMux);
      kickRoutineWork();
    }
    if (timeCounter2 > 0) {
      portENTER_CRITICAL(&timerMux);
      timeCounter2--;
      portEXIT_CRITICAL(&timerMux);
      adjustTime();
    }

(5)サーバー・コールバック関数

 server.onはクライアントからの要求を受けて実行させるメソッド、つまりサーバーのコールバック関数を指定するものです。「HTTPリクエストヘッダーが'GET'で通信してきたら、コマンド入力画面を表示するsendCommandScreenを実行させる」、また「HTTPリクエストヘッダーが'GET'で通信してきたら、処理を切り分けるprocControlメソッドを実行させる」ことを、初期化処理ブロックsetupで指定しています。
void setup() {
					:
					:
    // Set server callback functions
    server.on("/", HTTP_GET, sendCommandScreen);
    server.on("/", HTTP_POST, procControl);
}
 繰り返し処理ブロックloop内では、handleClientでクライアントからの要求を待ち構えています。コマンド入力画面と動作条件設定画面は、それぞれHTML文のformタグでリクエストヘッダーに'POST'を指定しているので、要求があるとprocControlメソッドが呼び出されます。検索結果や計測結果、入力エラーなどの表示画面はリクエストヘッダーに'GET'を指定しているので、ボタンをクリックして要求を受けるとsendCommandScreenでコマンド入力画面が呼び出されます。
void loop() {
					:
					:
    server.handleClient();
}
 コールバック関数の詳細については、『超小型格安チップ「ESP-WROOM-02(ESP8266)」はどこまで使えるか?』の「Ⅶ. 完成品としての仕上げ」を参照してください。

(6)全体の制御構造について

 少し取っつきにくい割込処理ですが、こうやって眺めると定形コードを配置するだけで簡単に利用できることが分かります。そして何よりも、割り込み処理を利用すると複雑な手順制御が不要なので、スケッチのロジックを簡潔に組み立てることができます。また、割込処理は割り込み発生時だけ一時的に実行されるため、見かけ上マルチスレッドのような動作が可能になります。


5.終わりに

 以上で今回のプロジェクトは完了です。移行作業は比較的順調に進んだのですが、開発ボードに印刷された小さなピンの名称は老眼には厳しく苦労しました。○○○ルーペが必要かも、などと考えながらも手持ちの虫メガネでがんばり通しました。それこれで説明不足や言葉が足りない部分も多く、分かりにくい点につきましてはご容赦願います。
 さて、ESP32の使い方はある程度分かりましたが、この凄い性能を何にどう利用するか、応用分野についての課題検討が楽しみです。残された時間をどう使おうかと迷うところです。このプロジェクト記録がいささかでもお役に立てれば嬉しいです。長らくのお付き合い、ありがとうございました。

 
Copyright (C) 2011-2024 Marchan, All rights reserved.