はじめに
前回 ESP32を使って学習リモコンを作る(71) ソフトウェア 本機のプロジェクト で説明したプロジェクトの勘所を説明します。
ソフトウェアの要素技術
ソフトウェアの要素技術についてはこれまでに説明してきた内容を参照ください。
ESP32を使って学習リモコンを作る(3) ソフトウェア 赤外線リモコン受信( irReceive )
ESP32を使って学習リモコンを作る(4) ソフトウェア 赤外線リモコン送信( irSend )
ESP32を使って学習リモコンを作る(5) ソフトウェア webserver
ESP32を使って学習リモコンを作る(6) ソフトウェア Flash 読書き(SPIFFS)
本項ではクライアント(Webブラウザ)とサーバー(ESP32 main.cpp)間の相互関係や関数とのデータ受け渡しおよび関数の有効、無効の制御方法を中心に説明をして Smart Remote Controller 全体のシステム動作の理解に役立てればと思います。
グローバル変数(データ)
データの受け渡しに使用するグローバル変数を表1 にまとめました。
グローバル変数にしなくてもデータの受け渡しはできると思いますが、あえてグローバル変数として受け渡しに使用することを意識するようにしました。
表1 グローバル変数(データ)
| 変数名 |
型 |
説明 |
| status_information |
String |
main.cpp で発生した制御状態の変化を任意の文字列で表現してこの変数に代入することで、クライアント側に文字列情報が伝達されてブラウザ画面に表示されます。 |
| wrfolder |
String |
SPIFFS を使用して Flash に書込む際のフォルダ名として書込み、読出しで使用します。 |
| wrfile |
String |
SPIFFS を使用して Flash に書込む際のファイル名として書込み、読出しで使用します。 |
| writeStr |
String |
取込んだ赤外線リモコン信号(hex)を文字列として格納します。receive_IR_process()を実行すると戻り値 writeStr を返します。
信号登録が許可されると store_Flash() は writeStr を引数として Flash に書込みます。 |
| readStr |
String |
restore_IR_proicess() を実行すると赤外線リモコン信号が読出されて戻り値 readStr を返します。
send_IR_process() は readStr を引数として赤外線リモコン信号を送信します。 |
| num_reg |
int |
リモコン送信ボタンに登録する赤外線リモコン信号の登録数カウンタです。 |
| bt_id |
String |
赤外線リモコン信号を複数登録中にリモコン送信ボタンが変更されたかを識別するために使用します。 |
| num_period |
int |
リピート周期(初期値 108ms) |
| hex_repeat |
String |
リピート信号(hex) |
グローバル変数(フラグ)
制御のためにフラグとして使用する bool 型グローバル変数を表2 にまとめました。
表2 グローバル変数(フラグ)
| 変数名 |
型 |
説明 |
| ena_send |
bool |
赤外線リモコン信号送信関数 send_IR_process(); の有効/無効フラグとして使用します。 |
| ena_store |
bool |
Flash への書込み関数 store_Flash(); の有効/無効フラグとして使用します。 |
| ena_restore |
bool |
Flash からの読出し関数 restore_Flash(); の有効/無効フラグとして使用します。 |
| ena_assign |
bool |
信号登録の有効/無効フラグとして使用します。 |
| is_triggered |
bool |
周期実行関数をトリガーするフラグとして使用します。 |
| is_cancelled |
bool |
周期実行関数をキャンセルするフラグとして使用します。 |
| stop_requested |
bool |
周期実行関数を停止するフラグとして使用します。 |
| Repeat_flag |
bool |
リピート信号を送信するフラグとして使用します。 |
主要関数とグローバル変数(フラグ)の関係
主要関数とグローバル変数(フラグ)の関係を表3 にまとめました。
この表から主要関数の有効/無効の条件および引数/戻り値を一覧できます。
表3 主要関数とグローバル変数(フラグ)の関係
| 機能 |
関数名 |
有効条件
(値) |
無効条件
(値) |
引数
(型) |
引数
(型) |
戻り値
(型) |
赤外線
信号受信 |
receive_IR_process() |
33PIN
(HIGH) |
33PIN
(LOW) |
|
|
writeStr
(String) |
赤外線
信号送信 |
send_IR_process() |
ena_send
(true) |
ena_send
(false) |
readStr
(String) |
|
|
Flash
書込み |
store_Flash() |
ena_store
(true) |
ena_store
(false)* |
wrfile
(String) |
writestr
(String) |
|
Flash
読出し |
restore_Flash |
ena_restore
(true) |
ena_restore
(false) |
wrfile
(String) |
readStr
(String) |
|
* ena_store のみ store_Flash 関数から抜ける時に false に設定されます。
表4 に周期実行関数 periodicLoop() とグローバル変数(フラグ)の関係をまとめました。
表4 周期実行関数とグローバル変数(フラグ)の関係
| 状態 |
is_triggered |
is_cancelled |
stop_requested |
待受け |
false |
false |
false |
キャンセル |
X |
true |
X |
周期処理開始 |
true |
false |
false |
周期処理終了 |
X |
true または |
true |
X は Dont’care を示します。
ブラウザ画面に表示されるボタン
ボタンの動作を説明することでクライアント(Webブラウザ)とサーバー(ESP32)間の相互関係が明らかになります。ここでは Web ブラウザに表示されるボタンの定義を再掲します。(図1)

図1 Web ブラウザのボタン定義
モード切換ボタン(Smart Remote Controller)
ブラウザ画面下寄りの Smart Remote Controller の文字がモード切換ボタンで、モード切換が有効な場合は赤色、無効の場合は青色で表示されています。(図1 ③)
index.html
57 <!– モード切換ボタンの定義( ボタンの輪郭は消しているので文字だけに見える)–>
58 <divclass=“bt_mode”>
59 <input type=“checkbox” id=“bt_mode” name=“bt_mode” onclick=“bt_modeClick();”>
60 <label id=“bt_mode_label” for=“bt_mode”>Smart Remote Controller</label>
61 </div>
57~61 モード切換ボタンを定義しています。
checkbox 属性を使用して id と name 両方に bt_mode を設定しています。
js.js
265 function bt_modeClick(){
266 var xhr = new XMLHttpRequest();
267 xhr.open(“GET”, “/mode”, true);
268 xhr.send(null);
269 }
265~269 モード切換ボタン bt_mode を押した時サーバーへメソッド GET、 URL /mode のリクエストを送信します。
main.cpp
301 server.on(“/mode”, HTTP_GET, [](AsyncWebServerRequest *request){
302 Serial.println(“モード切換ボタンが押されました。”); //ターミナルにメッセージ出力
303 status_information = “モード切換ボタンが押されました。”; //クライアント側で情報を表示する
304 request->send_P(200, “text/plain”, getMsg_information().c_str());
305 });
301~305 URL /mode によりモード切換ボタン bt_mode からの GET リクエストと認識されて処理が行われます。
302 ターミナルにメッセージを出力します。
303~304 内部変数 status_information にメッセージを設定してクライアント側に text/plane として送信してブラウザ画面に表示します。
js.js
上記処理とは別にモード切換ボタンにイベントリスナを付加してボタンの状態が true か false かによって異なる動作を定義しています。
16 control_bt_mode_status();
16 モード切換ボタンの動作を定義した関数 control_bt_mode_status(); を呼び出します。
19 setInterval(getCurTime, 500);
19 関数呼び出しは 500ms 周期で実行されます。
356 function control_bt_mode_status(){
357 const ev_SRC = document.getElementById(‘bt_mode’);
358 ev_SRC.addEventListener(‘click’,
359 function(event){
360 enable_all_of_TX_keys();
361 const btSRC = document.getElementById(‘bt_mode’);
362 if ( btSRC.checked ){ /** bt_mode が true の場合制御ボタンを有効にして画面上で見えるようにする */
.
.
372 } else { /** bt_mode が false の場合制御ボタンを無効にして画面上で見えなくする */
.
.
382 }
383 }
384 );
385 }
356~385 モード切換ボタンの動作を関数 function control_bt_mode_status(){} で定義します。
357 const ev_SRC = document.getElementById(‘bt_mode’);
358 ev_SRC.addEventListener(‘click’,
357~358 モード切換ボタン bt_mode にイベントリスナを付加します。
359 クリックされたら関数 function(event){} を実行します。
346 function enable_all_of_TX_keys(){
347 /* 16個の「リモコン送信ボタン」bt_1 から bt_16 を有効にする */
348 for (let i = 1; i < 17; i++){
349 buf_btc2 = “bt_” + i ;
350 enable_button(buf_btc2);
351 }
352 }
346~352 bt_1 から bt_16 のリモコン送信ボタン 16個全てを有効にします。
337 async function enable_button(button_id){
338 try{
339 document.getElementById(button_id).removeAttribute(“disabled”);
340 } catch (err){
341 console.error(err);
342 }
343 }
337~343 button_id で指定したボタンの Atribute “disabled” を削除して有効にします。
361 const btSRC = document.getElementById(‘bt_mode’);
361 モード切換ボタン bt_mode をインスタンス化します。
bt_mode が true の場合(制御ボタン有効)
362 if ( btSRC.checked ){ /** bt_mode が true の場合制御ボタンを有効にして画面上で見えるようにする */
363 enable_button(“bt_c1”);
364 enable_button(“bt_c2”);
365 enable_button(“bt_c3”);
366 enable_button(“bt_c4”);
367 bt_standby(‘bt_c1_label’);
368 bt_standby(‘bt_c2_label’);
369 bt_standby(‘bt_c3’);
370 bt_standby(‘bt_c4_label’);
371 document.getElementById(“msg_information”).innerHTML = “赤外線リモコン信号取込機能が有効になりました。 “;
362~371 ボタン bt_c1 ~ bt_c4 を有効にします。
関数 enable_button(); が “disabled” Atribute を削除してボタンを有効にします。(337~343行目)
367~370 ボタン bt_c1 ~ bt_c4 が見えるようにします。
関数 bt_standby(); が文字、背景、境界を見える色に変更します。(396~401行目)
371 ブラウザの情報表示窓に表示するためのメッセージを設定します。
bt_mode が false の場合(制御ボタン無効)
372 } else { /** bt_mode が false の場合制御ボタンを無効にして画面上で見えなくする */
373 disabale_button(“bt_c1”);
374 disabale_button(“bt_c2”);
375 disabale_button(“bt_c3”);
376 disabale_button(“bt_c4”);
377 bt_hidden(‘bt_c1_label’);
378 bt_hidden(‘bt_c2_label’);
379 bt_hidden(‘bt_c3’);
380 bt_hidden(‘bt_c4_label’);
381 document.getElementById(“msg_information”).innerHTML = “赤外線リモコン信号取込機能を終了しました。\n通常の赤外線リモコン送信機として機能します。”;
382 }
372~382 ボタン bt_c1 ~ bt_c4 を無効にします。
関数 disable_button(); が “disabled” Atribute を付加してボタンを無効にします。(328~334行目)
377~380 ボタン bt_c1 ~ bt_c4 が見えないようにします。
関数 bt_hidden(); が文字、背景、境界を見えない色に変更します。(403~408行目)
381 ブラウザの情報表示窓に表示するためのメッセージを設定します。
取込ボタン(bt_c1)
index.html
64 <div class=”bt_c1″>
65 <input type=”checkbox” id=”bt_c1″ name=”bt_c1″onclick=”bt_c1Click();”>
66 <label id= “bt_c1_label” for=”bt_c1″>取込</label>
67 </div>
64~67 取込ボタン bt_c1 を定義しています。checkbox 属性を使用して id と name 両方に bt_c1 を設定しています。
js.js
273 functionbt_c1Click(){
.
.
288 }
273~288 取込ボタン bt_c1 が押された時の処理を定義します。
274 var xhr = new XMLHttpRequest();
275 xhr.open(“GET”, “/capture”, true);
276 xhr.send(null);
274~276 取込ボタンが押された時サーバーへメソッド GET、URL /capture のリクエストを送信します。
277 const b11 = document.getElementById(‘bt_c1’);
278 const b12 = document.getElementById(‘bt_c2’);
279 b11.checked = true; /* 「取込」ボタンONを保持する */
280 b12.checked = false; /* 「登録」ボタンをOFFする */
281 bt_active(‘bt_c1_label’); /* 「取込」ボタンをアクティブ色に変更 */
282 bt_standby(‘bt_c2_label’); /* 「登録」ボタンをスタンバイ色に変更 */
277~278 取込ボタン bt_c1 、登録ボタン bt_c2 をインスタンス化します。
279~280 取込ボタン ON を保持し、登録ボタン OFF を保持します。
281 関数 bt_active(); がボタンの背景色をトマト色、文字色を白に変更します。(389~394行目)
282 関数 bt_standby(); がボタンの背景色を水色に、文字色を黒色に変更します。(396~401行目)
284 for (leti = 1; i < 17; i++){
285 buf_btc1 = “bt_” + i ;
286 disabale_button(buf_btc1);
287 }
284~287 リモコン送信ボタン bt_1~bt_16 全てを無効にします。
main.cpp
306 //capture 「取込」ボタン bt_c1 に対するレスポンス
307 server.on(“/capture”, HTTP_GET, [](AsyncWebServerRequest*request){
308 Serial.println(“\n「取込」ボタンが押されました。”); //ターミナルにメッセージ出力
309 digitalWrite(ena_receive_PIN, HIGH); //irReceive レベルシフト回路の動作を開始
310 status_information=“「取込」を開始します。リモコン送信機のボタンを押してください。”; //クライアント側で情報を表示する
311 request->send_P(200, “text/plain”, getMsg_information().c_str());
312 });
306~312 URL /capture により取込ボタン bt_c1 からの GET リクエストと認識されます。
308 ターミナルにメッセージを出力します。
309 ena_receive_PIN を HIGH レベルにして赤外線信号受信回路の動作を許可します。
310 内部変数 status_information にメッセージを設定します。
311 クライアント側に text/plane として送信してブラウザ画面に表示します。
437 String receive_IR_process() {
.
.
510 return writeStr;
511 }
437~511 赤外線リモコン信号の受信を処理する関数です。
この関数は Loop 内 357行目で呼び出されて常に動作状態になっています。
取込ボタン bt_c1 が押された時のレスポンスの 309行目で ena_receive_PIN を HIGH レベルに設定することで赤外線リモコン信号受信回路の動作が有効になります。
このとき被学習リモコンのボタンが押されると、赤外線リモコン信号を受信したリモコン受光 IC の出力信号が ESP32 モジュールに入力されることになります。
関数 String receive_IR_process(){} で処理されることにより文字列 writeStr が戻り値として得られます。
登録ボタン(bt_c2)
index.html
68 <divclass=“bt_c2”>
69 <inputtype=“checkbox”id=“bt_c2”name=“bt_c2”onclick=“bt_c2Click();”>
70 <labelid= “bt_c2_label”for=“bt_c2”>登録</label>
71 </div>
68~71 登録ボタン bt_c2 を定義しています。checkbox 属性を使用して id と name 両方に bt_c2 を設定しています。
js.js
197 functionbt_c2Click(){
198 varxhr = newXMLHttpRequest();
199 xhr.open(“GET”, “/memory”, true);
200 xhr.send(null);
201 constb11 = document.getElementById(‘bt_c1’);
202 constb12 = document.getElementById(‘bt_c2’);
203 b11.checked = false; /* 「取込」ボタンをOFFする */
204 b12.checked = true; /* 「登録」ボタンONを保持する */
205 bt_standby(‘bt_c1_label’); /* 「取込」ボタンをスタンバイ色に変更 */
206 bt_active(‘bt_c2_label’); /* 「登録」ボタンをアクティブ色に変更 */
207 enable_all_of_TX_keys(); /* 16個の「リモコン送信ボタン」をすべて許可する */
208 }
197~208 登録ボタン bt_c2 の動作を定義しています。
197~200 登録ボタン bt_c2 を押した時サーバーへメソッド GET、URL /memory のリクエストを送信します。
201~202 取込ボタン bt_c1 と登録ボタン bt_c2 をインスタンス化します。
203~204 取込ボタンを OFF に、登録ボタンを ON に保持します。
205~206 取込ボタンをスタンバイ色(水色)に、登録ボタンをアクティブ色(トマト色)に変更します。
207 16個のリモコン送信ボタンをすべて有効にします。
main.cpp
314 server.on(“/memory”, HTTP_GET, [](AsyncWebServerRequest*request){
315 Serial.println(“\n「登録」ボタンが押されました。”); //ターミナルにメッセージ出力
316 digitalWrite(ena_receive_PIN, LOW); //irReceive レベルシフト回路の動作を停止
317 ena_store = true;
318 num_reg = num_reg + 1; //「リモコン送信」ボタンに登録する登録数を加算する
319 status_information=“登録を開始します。\n登録する「任意」のボタンを押してください。”; //クライアント側で情報を表示する
320 request->send_P(200, “text/plain”, getMsg_information().c_str());
321 });
314~321 URL /memory により登録ボタン bt_c2 からの GET リクエストと認識されます。
315 ターミナルにメッセージを出力します。
316 ena_receive_PIN を LOW レベルにして赤外線リモコン信号受信回路の動作を停止します。
317 ena_store = true; 有効に設定して Flash への書込みを許可します。
318 リモコン送信ボタンに登録する赤外線リモコン信号の登録数を加算します。
319 内部変数 status_information にメッセージを設定します。
320 クライアント側に text/plane として送信してブラウザ画面に表示します。
終了ボタン(bt_c3)
index.html
72 <button class=‘bt_c3’ onclick=‘bt_c3Clicked(this)’ id=‘bt_c3’>終了</button>
72 終了ボタンを定義しています。終了ボタンは状態を保持する必要が無いので属性には checkbox は使わずに button を使用します。
js.js
305 functionbt_c3Clicked(element) {
306 varxhr = newXMLHttpRequest();
307 xhr.open(“GET”, “/finish”, true);
308 xhr.send(null);
309 constb11 = document.getElementById(‘bt_c1’);
310 constb12 = document.getElementById(‘bt_c2’);
311 b11.checked = false; /* 「取込」ボタンをOFFする */
312 b12.checked = false; /* 「登録」ボタンをOFFする */
313 bt_standby(‘bt_c1_label’); /* 「取込」ボタンをスタンバイ色に変更 */
314 bt_standby(‘bt_c2_label’); /* 「登録」ボタンをスタンバイ色に変更 */
315 enable_all_of_TX_keys(); /* 16個の「リモコン送信ボタン」をすべて許可する */
316 }
305~316 終了ボタン bt_c3 の動作を定義しています。
305~308 終了ボタン bt_c3 を押した時サーバーへメソッド GET、 URL /finish のリクエストを送信します。
309~310 取込ボタン bt_c1 と登録ボタン bt_c2 をインスタンス化します。
311~312 取込ボタンと登録ボタンを OFF にします。
313~314 取込ボタンと登録ボタンをスタンバイ色(水色)にします。
315 16個のリモコン送信ボタンすべてを有効にします。
main.cpp
323 server.on(“/finish”, HTTP_GET, [](AsyncWebServerRequest*request){
324 Serial.println(“\n「終了」ボタンが押されました。”); //ターミナルにメッセージ出力
325 digitalWrite(ena_receive_PIN, LOW); //irReceive レベルシフト回路の動作を停止。
326 ena_send = false; //irsend を禁止
327 ena_store = false; //Flash 書込みを禁止
328 ena_restore = false; //Flash 読出しを禁止
329 ena_assign = false; //信号登録禁止
330 status_information=“取込、登録を終了しました。”; //クライアント側で情報を表示する
331 num_reg = 0; //登録数カウンタをリセットする
332 request->send_P(200, “text/plain”, getMsg_information().c_str());
333 });
323 URL /FINISH により終了ボタン bt_c3 からの GET リクエストと認識されます。
324 ターミナルにメッセージを出力します。
325 ena_receive_PIN を LOW レベルに設定して赤外線リモコン信号受信回路の動作を停止します。
326~329 ena_send、ena_store、ena_restore、ena_assign の各フラグを false に設定して赤外線リモコン信号送信、Flash 書込み、Flash 読出し、登録を禁止します。
330 内部変数 status_information にメッセージを設定します。
331 登録数カウンタ num_reg = 0; をリセットします。
332 クライアント側に text/plane として送信してブラウザ画面に表示します。
リモコン送信ボタン(bt_1 ~ bt_16)
リモコン送信ボタン bt_1 ~ bt_16 の動作を説明します。
index.html
18<p>TV</p>
19 <div class=”inline_1″>
20 <button class=”bt_1″ onpointerdown=”bt_1Down(this)” onpointerup=”bt_1Up(this)” id=”bt_1″>電源</button>
.
23 <button class=”bt_4″ onpointerdown=”bt_4Down(this)” onpointerup=”bt_4Up(this)” id=”bt_4″></button>
24 </div>
25 <br>
.
39 <p>BOSE</p>
40 <div class=”inline_4″>
.
45 </div>
46 <br>
18 ~ 46 リモコン送信ボタン bt_1 ~ bt_16 を定義しています。
18 、 39 TV と BOSE の2つのグループに分類するラベルを付けています。
19、26、33、40 ボタンを4個ずつ横並びにするので inline_1~inline_4 のクラス名を付けて分類しています。
各ボタンは button 属性を使って class と id に bt_1 ~ bt_16 を設定しています。
20 ボタン bt_1 を定義していま
onpointerdown=”bt_1Down(this)” によりボタンを押下した瞬間に js.js 38~43 行目で定義した bt1_Down() 関数を実行します。
onpointerup=”bt_1Up(this)” によりボタンを離した瞬間に js.js 44~49 行目で定義した bt1_Up() 関数を実行します。
ボタンが押下されると bt1_Down() によりリモコン信号の送信を開始します。そしてリモコン信号の送信が終了した後はボタンが離されて bt1_Up() までリピート送信を繰り返すことになります。
js.js
38 functionbt_1Down(element){
39 if (document.getElementById(‘bt_c1’).checked == false){
40 varxhr = newXMLHttpRequest();
41 xhr.open(“GET”, “/bt_1_on”, true);
42 xhr.send(null); }
43 }
44 functionbt_1Up(element){
45 if (document.getElementById(‘bt_c1’).checked == false){
46 varxhr = newXMLHttpRequest();
47 xhr.open(“GET”, “/bt_1_off”, true);
48 xhr.send(null); }
49 }
38~49 リモコン送信ボタン bt_1 が押されたときと離されたときの動作を定義しています。
39 取込ボタン bt_c1 が押されていない、つまりチェックが false の場合に以下を実行します。
40~42 リモコン送信ボタンが押された時サーバーへメソッド GET、URL /bt_1_on のリクエストを送信します。
45 取込ボタン bt_c1 が押されていない、つまりチェックが false の場合に以下を実行します。
46~48 リモコン送信ボタンが離された時サーバーへメソッド GET、URL /bt_1_off のリクエストを送信します。
リモコン送信ボタン bt_2_on~bt_16_on、bt_2_off~bt_16_off にはそれぞれ URL を設定しています。
main.cpp
160 server.on(“/bt_1_on”, HTTP_GET, [](AsyncWebServerRequest*request){
161 //タイマー開始、ボタンの番号とラベルを渡す。
162 startTimer(num_period,“1“,”TV電源“);
163 request->send(200, “text/plain”, getMsg_information().c_str());
164 server.on(“/bt_1_off”, HTTP_GET, [](AsyncWebServerRequest*request){
165 stopTimer() //タイマー停止
166 request->send(200, “text/plain”, “OFF”); });
160 URL /bt_1_on によりボタン bt_1 が押された時の GET リクエストと認識されます。
162 関数 startTimer( ); を実行します。
163 クライアント側に text/plane メッセージを送信してブラウザ画面に表示します。
164 URL /bt_1_off によりボタン bt_1 が離された時の GET リクエストと認識されます。
165 関数 stopTimer( ); を実行します。
166 クライアント側に text/plane メッセージを送信してブラウザ画面に表示します。
648 void bt_response(String bt_label, String bt_name){
649 wrfolder = “/bt_” + bt_label; //フォルダ名生成(bt_label の値は 1-16)
650 wrfile = “/bt_” + bt_label; //ファイル名生成
.
.
672 }
648~672 リモコン送信ボタンが押された時の処理になります。
649~650 引数 bt_label を使ってフォルダ名とファイル名を生成します。
この関数は受信した赤外線リモコン信号を Flash に書込んで登録する場合と、登録した赤外線リモコン信号を Flash から読出して送信する場合の2種類の動作に分かれます。
リモコン送信ボタンに登録する場合
取込んだ赤外線リモコン信号を登録する場合は登録ボタン bt_c2 に対するレスポンス 317行目で ena_store = true; に設定されるので、次の内容が実行されます。
653 if (ena_store == true){ //「取込」、「登録」に続けて「リモコン送信」ボタンを押した場合、
654 if ( bt_id!=bt_label){ //複数「登録」で異なる「リモコン送信」ボタンを押した場合、
655 num_reg = 1; //リモコン送信ボタンに登録するリモコン信号の数を 1 に戻しておく。
656 }
657 ena_assign = true; //信号登録許可
658 delay(1000); //Flash 書込みを待ってから次の処理へ進める。
659 Stringstr_buf = dtostrf(num_reg,2,0,m_buf); //整数を文字列に変換
660 //クライアント側で情報を表示する
661 status_information=bt_name+” ボタンに”+str_buf+” つめのリモコン信号を「登録」しました。”;
662 //複数登録中にリモコン送信ボタンが変更されたか識別用 bt_id に bt_label (1-16) を初期値として設定する。
663 bt_id=bt_label;
664 }
653~664 当該リモコン送信ボタンに登録する場合を定義しています。
654~656 複数登録で異なるリモコン送信ボタンを押した場合は登録数カウンタ num_reg を 1 に戻します。
657 信号登録許可フラグを有効 ena_assign = true; にします。Loop 内 361行目で ena_store == true、かつ ena_assign == true の条件が成立したので、Flash への書込み登録が開始されます。
658 Flash への書込みが終わるまで 1000ms 待ちます。
659~661 クライアント側で情報を表示するための文字列を生成します。
663 複数登録中にリモコン送信ボタンが変更されたかを識別するための変数 bt_id に引数で受け取った bt_label を設定します。
361 if ((ena_store == true) && (ena_assign == true)){ //Flash 書込み許可、信号登録許可 の場合
.
368 wrfile=wrfolder+wrfolder+“_”+num_reg+“.txt”;
369 store_Flash( wrfile, writeStr ); //受信した信号を Flash に書込む
.
374 wrfile=wrfolder+“/num_reg.txt”;
375 Stringstr_buf = dtostrf(num_reg,2,0,m_buf); //整数を文字列に変換
.
378 ena_store = true; //Flash 書込み許可
379 store_Flash( wrfile, str_buf ); //登録数カウンタ値を Flash に書込む
380 ena_assign = false; //信号登録禁止
381 }
361~381 登録ボタンに続けてリモコン送信ボタンが押された時の処理です。
368 649行目で生成したフォルダ名と登録数カウンタから赤外線リモコン信号を格納するファイル名を生成します。
369 生成したファイル名 wrfile と 493行目で取込んだ赤外線リモコン信号 writeStr を引数として Flash に書込みます。
374 649行目で生成したフォルダ名と登録数カウンタから登録数カウンタを格納するファイル名を生成します。
305 整数 num_reg を文字列に変換して Flash に書込む準備をします。
378 書込みフラグを有効にします。
379 374行目で生成したファイル名と375行目で変換した文字列を引数として Flash に書込みます。
例えばリモコン送信ボタン bt_1 に 2 つのリモコン信号を登録した場合に生成されるファイル名と Flash に書込まれる内容は次のようになります。
フォルダ名 ファイル名
/bt_1 —–|—–bt_1_1.txt (リモコン信号1:hex文字列)
|—–bt_1_2.txt (リモコン信号2:hex文字列)
|—–num_reg.txt (2:文字列)
リモコン信号を読出して送信する場合
ena_store が false の時にリモコン送信ボタンが押されると以下の動作をします。
666 elseif ((ena_store == false)){
667 ena_restore = true; //Flash 読出しを許可
668 ena_send = true; //irSend リモコン信号送信を許可
669 //クライアント側で情報を表示する
670 status_information=bt_name+” リモコン信号を送信しました。”;
671 }
666~671 リモコン送信ボタンが押された時の処理になります。
667 Flash 読出し許可フラグを有効にします。
668 リモコン信号送信許可フラグを有効にします。
670 クライアント側で情報を表示するための文字列を生成します。
420 if ( Repeat_flag == true){ // リピート信号開始フラグが true の場合
421 ena_send = true; //irSend 許可
422 send_IR_process(hex_repeat, 1); //リピート信号送信
423 //send_IR_process(readStr, 1); //リモコン信号送信を繰り返すことも可能
424 Repeat_flag = false;
425 }
420~425 Frame 信号送出後もリモコン送信ボタンが押されている( Repaeat_flag == true)場合は、ボタンが離されるまでリピート信号を繰り返し送信します。
421 リモコン信号送信許可フラグが有効
422 第一引数を hex_repeat、第二引数を 1 にするとリピート信号が送信されます。
423 第一引数を readStr にすればリモコン信号(フレーム)を繰り返すこともできます。
424 繰り返しフラグを無効にします。
タイマースレッドを使って繰り返し送信する
動作概要

*図2 ボタンを押した時のタイミングチャート
ボタンを長く押した時は、ボタン押下と同時にタイマーを待機状態で立上げます。 赤外線リモコン信号(Frame)の送信が終わった段階でボタンが押されていると is_triggered = true となりタイマーのカウントがが開始されます。そしてボタンが離されたとき stop_requested = true によりタイマーが終了します。
ボタンを短く押した時は、ボタン押下と同時にタイマーを待機状態で立上げます。 赤外線リモコン信号(Frame)の送信が終わるまでにボタンが離されていると、stop_requested = true によりタイマーが終了します。
ボタンに何も登録されていないときは、赤外線リモコン信号(Frame)は送信されず、is_cancelled = true によりタイマーをキャンセルしています。
バックグラウンドで周期実行される関数
677 void periodicLoop(void *parameter){
678 uint32_t interval = (uint32_t)parameter;
679
680 // is_triggered または is_cancelled になるまで待つ
681 while (!is_triggered && !is_cancelled && !stop_requested) {
682 vTaskDelay(pdMS_TO_TICKS(1));
683 }
684
685 // キャンセル
686 if (is_cancelled) {
687 worker_task = NULL;
688 vTaskDelete(NULL);
689 return;
690 }
691
692 // 周期処理開始
693 TickType_t lastWakeTime = xTaskGetTickCount();
694 while (!stop_requested && !is_cancelled) {
695 // ★ 周期的に実行する処理
696 Repeat_flag = true; // 繰り返しフラグを true にする
697 vTaskDelayUntil( &lastWakeTime, pdMS_TO_TICKS( interval ));
698 }
699
700 // 終了
701 worker_task = NULL;
702 vTaskDelete(NULL);
703 }
677~703 バックグラウンドで周期実行される関数 periodicLoop を定義します。 パラメータ *parameter の値で周期 [ms] を指定します、
678 ポインタを整数値に変換します。
681~683 タイマーの開始を is_triggered、is_cancelled、または stop_requested が true になるまで待ちます。
682 FreeRTOS が提供する関数で Ticks 数の間現在のタスクをウエイトします。 ミリ秒単位の時間を FreeRTOS システムの最小時間単位 Ticksに変換するマクロ pdMS_TO_TICKS(1) を引数としています。 1 ミリ秒だけこの関数を実行することでウォッチドックタイマーの作動による強制リブートを防ぐことができます。
686~690 キャンセル is_cancelled の場合タイマーを終了します。
693 Ticks 数を表す整数型 TickType_t に、システム起動から現在までの総 Ticks を取得する xTaskGetTickCount() を
最後にタスクが実行された時刻として保存します。
694~698 stop_requested = false かつ is_cancelled = false の場合周期処理を開始します。 ここでは Repeat_flag = true の処理を周期的に実行しています。loop 処理内の 420行目から始まるリピート信号送信処理が実行されます。
697 第 1 引数に基準とする前回起動時刻、第 2 引数に繰り返し周期を設定して正確な周期でタスクを実行します。
タイマー開始
707 void startTimer(uint32_t interval, String name,String label){
708 if (worker_task != NULL) {
709 return;
710 }
711
712 is_triggered = false;
713 is_cancelled = false;
714 stop_requested = false;
715 bt_response (name.c_str(), label.c_str());
716
717 xTaskCreate( periodicLoop, “periodicLoop”, 4096, (void *)interval, 1, &worker_task );
718 }
707~718タイマーを開始する関数を定義します。
繰り返し周期 interval、ボタンの名前 name、ラベル label をパラメータとして指定します。
708~710 すでにタイマーが動作しているときは関数を抜けます。
712~714 is_triggered、is_cancelled、stop_requested 各フラグをリセットします。
715 ボタンの名前 name、ラベル label を引数としてボタンを押した時の処理を行う関数 bt_response を実行します。
717 FreeRTOSで新しいタスク(スレッド)を作成して起動する関数です。
第 1 引数 : 実行する関数名、第 2 引数 : タスク識別名、第 3 引数 : スタックメモリのサイズ、第 4 引数 : 関数に渡すポインタ型引数、第 5 引数 : タスクの優先度、第 6 引数 : タスクハンドルを受け取る引数。
タイマー終了
722 void stopTimer(){
723 stop_requested = true;
724 }
723 stop_requested = true により 694~698 行の周期処理を終了します。
待機中のタイマースレッドの起動トリガ
728 void triggerPeriodicLoop() {
729 is_triggered = true; // 起動トリガセット
730 }
729 待機中のタイマースレッドの起動トリガ is_triggered = true により 681~683行目の while ループを抜けて周期処理を開始します。
タイマースレッドのキャンセルトリガ
734 void cancelPeriodicLoop() {
735 is_cancelled = true; // キャンセルフラグセット
736 }
735 キャンセルフラグを is_cancelled = true に設定することにより 694~698 行目の周期処理ループを抜けてタイマーをキャンセルします。
おわりに
コメント