山姆的編程實作分享。。。

Sam Blog, Sam Sharing, Sam Studio

2020年3月22日

[Arduino][ESP8266] ESP8266 Event-Driven & Callback Method


[Arduino][ESP8266]
ESP8266 Event-Driven & Callback Method
前言
在前篇” ESP8266 開發指南 – 軟體架構篇” 的文章末段,我針對ESP8266提出了
3點結論及4點撰寫程式碼( Coding ) 的建議,其目的就是告訴大家請用
“ callback function” 以及 “ event-driven”來撰寫ESP8266的程式碼。
所以,這篇文章就讓我來說明 “ Event-Driven Method”。

ESP8266 的Event-Driven & Callback Method
Event-driven 有各種作法,常見的有:
  • Flag 機制 : 就是透過設定Flag 來傳達 Event,這種做法一般多用在super-loop 的程式架構。
  • Event -Task : 這做法是架構在RTOS ,也就是透過Event的傳遞,來做到工作分派及Task的切換。
  • Event-Callback :  這做法是透過註冊 Callback function 來傳遞 Event,但這做法必須結合 (借助) 第一或第二做法。

ESP8266 的核心雖然可以處理3個Task,但WiFi-MAC, Timer Task以及User_Task
至少使用掉2個,所以,使用者能使用event-driven的方法就剩第一及第三的做法。
以下是我建議使用event-driven的流程:
Step1: 註冊 Callback function。
Step2: 透過Callback function 傳遞來的Event,然後設定Flag,或直接在Callback 處理(註1)。
Step3: 在User_Task (也就loop()迴圈) 判斷Flag狀態,適時機處理Event。
註1: 程式碼短小為佳,避免影響Task scheduling。

整個運作流程就如下圖所示:
範例:WiFi Event
瞭解了 ESP8266 event-driven 的做法後,這章節就讓我以實際的程式碼來做說明。
底下的程式碼是來自ESP8266內建的 WiFiEvent 範例,但是為了好說明,我修改了
部分的程式碼。
  1. /* 
  2.     This sketch shows how to use WiFi event handlers. 
  3.  
  4.     In this example, ESP8266 works in AP mode. 
  5.     Three event handlers are demonstrated: 
  6.     - station connects to the ESP8266 AP 
  7.     - station disconnects from the ESP8266 AP 
  8.     - ESP8266 AP receives a probe request from a station 
  9.  
  10.     Written by Markus Sattler, 2015-12-29. 
  11.     Updated for new event handlers by Ivan Grokhotkov, 2017-02-02. 
  12.     This example is released into public domain, 
  13.     or, at your option, CC0 licensed. 
  14. */  
  15.   
  16. #include   
  17. #include   
  18.   
  19. const char* ssid     = "esp8266";  
  20. const char* password = "12345678";  
  21.   
  22. WiFiEventHandler stationConnectedHandler;  
  23. WiFiEventHandler stationDisconnectedHandler;  
  24.   
  25. bool blinkFlag;  
  26.   
  27. void setup() {  
  28.   
  29.     Serial.begin(115200);  
  30.     pinMode(LED_BUILTIN, OUTPUT);  
  31.     digitalWrite(LED_BUILTIN, HIGH);  
  32.     blinkFlag = false;  
  33.   
  34.     // Don't save WiFi configuration in flash - optional  
  35.     WiFi.persistent(false);  
  36.   
  37.     // Set up an access point  
  38.     WiFi.mode(WIFI_AP);  
  39.     WiFi.softAP(ssid, password);  
  40.   
  41.     // Register event handlers.  
  42.     // Callback functions will be called as long as these handler objects exist.  
  43.     // Call "onStationConnected" each time a station connects  
  44.     stationConnectedHandler = WiFi.onSoftAPModeStationConnected(&onStationConnected);  
  45.   
  46.     // Call "onStationDisconnected" each time a station disconnects  
  47.     stationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(&onStationDisconnected);  
  48. }  
  49.   
  50. void onStationConnected(const WiFiEventSoftAPModeStationConnected& evt) {  
  51.     Serial.print("Station connected: ");  
  52.     Serial.println(macToString(evt.mac));  
  53.     // let LED blink  
  54.     blinkFlag = true;  
  55. }  
  56.   
  57. void onStationDisconnected(const WiFiEventSoftAPModeStationDisconnected& evt) {  
  58.     Serial.print("Station disconnected: ");  
  59.     Serial.println(macToString(evt.mac));  
  60.     blinkFlag = true;  
  61. }  
  62.   
  63. void loop() {  
  64.     if (blinkFlag) {  
  65.         // let LED blink twice  
  66.         blinkFlag = false;  
  67.         digitalWrite(LED_BUILTIN, LOW);  
  68.         delay(200);  
  69.         digitalWrite(LED_BUILTIN, HIGH);  
  70.         delay(200);  
  71.         digitalWrite(LED_BUILTIN, LOW);  
  72.         delay(200);  
  73.         digitalWrite(LED_BUILTIN, HIGH);  
  74.     }  
  75. }  
  76.   
  77. String macToString(const unsigned char* mac) {  
  78.     char buf[20];  
  79.     snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",  
  80.              mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);  
  81.     return String(buf);  
  82. }  
程式碼說明:
Line 16 : 為了使用ESP8266  WiFi Classes ,必須 include WiFi Library – ESP8266WiFi.h
Line 19, 20 : 在這範例裡,ESP8266會被設定成 AP mode (Access-Point),
這兩行是設定這AP 的名稱 (ssid) 及他的連接密碼 (password)
Line 22 : 宣告一個 WiFi class 的 Event Handler 名為”stationConnectdHandler”
Line 44 : 則是註冊 stationConnectdHandler 為onSoftAPModeStationConnected() 
函數的event handler,他的callback function 為 onStationConnected()
Line 22 及 Line 44 就是我在前面提到的 Step1: 註冊 Callback function
Line 23, 47 : 相同於 Line 22, 44,差異只是在一個是 connected 的 event handler / 
callback function, 另一個是disconnected 的 event handler / callback function
Line 25 : 宣告一個LED blink 的旗標,作為 LED 是否要閃爍的依據
Line 29 : 設定UART baudrate 為115200bps
Line 30~32 : 設定LED及旗標的初始狀態
Line 38, 39:設定ESP8266為 AP mode以及他的AP名稱 (ssid)和密碼 (password)
Line 50~55 : Connected 的callback function,也就是當有裝置連結上這AP時,
WiFi-MAC就會呼叫onStationConnected()這個函數,在這函數中只是簡單的列印
出連接上的裝置 mac address 以及設定blinkFlag 為 true
Line 50 ~ Line 55 就是我在前面提到的 Step2 : 透過Callback function 傳遞來的
Event,然後設定Flag
Line 63~75 :  loop() 函數,也就是User-Task的主程式,程式中就是簡單的判斷blinkFlag ,
若為true ,LED閃兩次,然後清掉旗標。
Line 63 ~ Line 75 就是我在前面提到的 Step3 : 在User_Task判斷Flag狀態,
適時機處理Event

Why use Event-Driven
瞭解了 ESP8266 event-driven 的做法,也看完了實際範例的說明,
想必大家會使用了吧!? 若有疑問或哪裡要加強說明,請留言給我。

另外,這時候你或許會問我底下這問題,
”若我不用event-driven 或 callback function 來寫ESP8266的程式碼,不行嗎? “
我的答案是 “ 可以的”, 但我也必須告訴你一個事實,就是你的ESP8266再呼叫WiFi Classes時 , CPU會一直在做虛功,這會讓你覺得ESP8266跑不動你的程式碼, 或甚至你會覺得你要換顆更強的CPU 了,例如雙核的ESP32 !

下一篇,就讓我以實際範例來告訴你這個事實吧 !
敬請期待!!!
延伸閱讀

熱門文章