2020年5月19日 星期二

六、5 存取點(AP)模式輸出輸入控制及應用---六、5-2 ESP8266輸出控制練習:多重輸出點控制


在前一節中我們示範了幾種方式去控制單一輸出點的開與關接下來示範如何去控制多重輸出點的開關乃至漸層或是類比的輸出並教導讀者如何善加利用網路上眾多好用且功能強大的第三方外掛函式庫

為了方便測試,本節的實驗都使用前面介紹過的ESP-202這塊模組板來實作,這塊模組板除了可以用來燒錄ESP-01之外,主要就用來實驗及測試ESP8266的一些功能;在這塊板子上載有一ESP-12E的郵票模組板,而且ESP8266的每一個可用的IO接腳都並接了一顆LED,【圖六、36】所示是 ESP-202 WiFi模組板的外觀和一些接腳名稱,其中標記1所圈起來的部分是並接在GPIO 0、2、4、5、14、16這六隻接腳的LED,在輸出狀態為low的時候會讓LED點亮;而標記2的部分則是並接在GPIO 12、13、15這三隻腳的三色LED模組(分別接在紅、藍、綠三種顏色),它們在輸出狀態為high的才會點亮。

在ESP-12E之後系列的模組板,雖然號稱多了許多IO腳可以使用,不過他們都必須在很特別的狀況之下才能正常使用,一般初學者是不建議拿來做其他的用途,否則會出現許多奇怪乃至當機的情形!如果會用到超過前面所提到的9隻IO腳,最好改用它們新推出的ESP32系列晶片。


圖六、36 ESP-202 WiFi模組板外觀接腳名稱


六、5-2.1 使用表單(form)語法控制3顆LED亮滅

本節是沿用《六、5-1.3》節使用html的表單(Form)語法方式控制單一LED,進而擴充為控制多顆LED(在此預設為3顆)當然這樣的動作方式也可以改為控制多組的繼電器模組進而控制許多不同的大型電器裝置

下面是我們系統預期的功能與動作:


範例程式功能與動作說明

1、使用三個表單(form)的提交按鈕控制ESP-202上並接在GPIO121315這三隻腳的三色LED模組(分別接在紅、藍、綠三種顏色)的亮滅

2、這些按鈕按一次會LED點亮再按一次則會讓LED熄滅而每一個LED亮滅的結果會回傳到連線裝置的瀏覽器螢幕上讓使用者知道LED目前亮滅的狀態


依前面的慣例,在真正開始設計程式之前,我們先規劃好使用者在手機瀏覽器上的操作介面,也就是先設計一html網頁程式,將我們所希望得到的操作畫面呈現出來後,再轉移到ESP8266上去實現我們所要的動作與功能。上面【圖六、36】所示的三個按鈕畫面,便是由【圖六、23a】的內容擴充而成的,它是執行《softAP_6_5_3Led1_form.html》這個html程式所產生的結果。


圖六、37 《softAP_6_5_3Led1_form.html》於電腦瀏覽器執行結果


如果我們比對《softAP_6_5_3Led1_form.html》和《softAP_6_5_1Led5_RY0.html》這兩個程式會發現它們前15行的程式碼是完全一樣的至於第16行的:


      <h3>3顆LED亮滅控制示範</h3>


只是這個範例的提示訊息文字而已。

接下來的17~25行則是實作出圖六、37】中的三組按鈕及配對的LED亮滅訊息它們的差別只在對應的按鍵LED編號及動作碼不同而已其他都一樣,請讀者自行參考。


 

<!DOCTYPE html>

<html>

  <head>

    <meta name='viewport' content='width=device-width, initial-scale=1.0'/>

    <meta charset='utf-8'>

    <style>body {font-size:120%;} #main {display:table; margin:auto;

      padding:0 10px 0 10px;} h3,{text-align:center;} h4,{text-align:center;} 

      .button {padding:10px 10px 10px 10px; width:100%; background-color: pink; font-size:120%;}

      .button2 {padding:10px 10px 10px 10px; width:100%; background-color: yellowgreen; font-size:120%;} 

    </style>

  </head>

  <body>

    <div id='main'>

     <h3>3顆LED亮滅控制示範</h3>

<h4>LED1目前狀態 : 熄滅</h4><br>

<form action='LedOn1'><input class='button'  type='submit' value='點亮LED1'>

</form><br>

<h4>LED2目前狀態 : 熄滅</h4><br>

<form action='LedOn2'><input class='button'  type='submit' value='點亮LED2'>

</form><br>

<h4>LED3目前狀態 : 熄滅</h4><br>

<form action='LedOn3'><input class='button'  type='submit' value='點亮LED3'>

</form><br>

    </div>

  </body>

</html>



程式名稱softAP_6_5_3Led_form.html 


以下是此範例程式的完整列表



 

#include  <ESP8266WiFi.h>

 

//----------------------------------------------

// 將我們的HTML 網頁程式內容直接建構在program memory內:

const char MAIN_page[] PROGMEM = R"=====(

<!DOCTYPE html>

<html>

  <head>

    <meta name='viewport' content='width=device-width, initial-scale=1.0'/>

    <meta charset='utf-8'>

    <style>body {font-size:110%;} #main {display:table; margin:auto;

      padding:0 10px 0 10px;} h3,{text-align:center;} h4,{text-align:center;} 

      .button {padding:10px 10px 10px 10px; width:100%; background-color:pink; font-size:120%;}

      .button2 {padding:10px 10px 10px 10px; width:100%; background-color:yellowgreen; font-size:120%;}    

    </style>

  </head>

  <body>

    <div id='main'>

      <h3>3顆LED亮滅控制示範</h3>

)=====";

//---------------------------------------------------

 

String softSsid = "ESP_softAP01";

const char* softPassword = "12345678";

const byte Led1=12,Led2=15,Led3=13;     

String  URI;

String  mainPage;

String  html_Led1On="<form action='Led1On'><input class='button' type='submit' value='點亮LED1'></form><br>";

String  html_Led1Off="<form action='Led1Off'><input class='button2' type='submit' value='熄滅LED1'></form><br>";

String  html_Led2On="<form action='Led2On'><input class='button' type='submit' value='點亮LED2'></form><br>";

String  html_Led2Off="<form action='Led2Off'><input class='button2' type='submit' value='熄滅LED2'></form><br>";

String  html_Led3On="<form action='Led3On'><input class='button' type='submit' value='點亮LED3'></form><br>";

String  html_Led3Off="<form action='Led3Off'><input class='button2' type='submit' value='熄滅LED3'></form><br>";

String  html_end="</div></body></html>";

String  html_Echo="";

 

String  ledState="<h3>LED目前狀態 : 熄滅</h3><br>";;

boolean led1State=false,led2State=false,led3State=false;

 

IPAddress local_IP(192,168,0,100);    // 設定新的伺服器IP位址

IPAddress gateway(192,168,0,1);   // 設定新的伺服器閘道位址

IPAddress subnet(255,255,255,0);    // 設定新的伺服器網路遮罩位址

 

WiFiServer  server(80); // 宣告一伺服器物件並設定通信埠號碼為網頁專用的80

WiFiClient  client;   // 宣告一客戶端物件

 

void setup() {

  // put your setup code here, to run once:

  pinMode(Led1,OUTPUT);   // 設定GPIO12,13,15三隻腳為輸出

  pinMode(Led2,OUTPUT);

  pinMode(Led3,OUTPUT);

  Serial.begin(115200);

  

  Serial.println();

  Serial.print("Setting soft-AP with configuratin... ");

  WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本地IP位址

  boolean result=WiFi.softAP(softSsid);

  if(result==true)

  {  // 初始化設定AP存取點成功

    Serial.println("soft-AP ready!");

    Serial.print("softAP = ");    // 在Arduino IDE串列監控視窗中顯示目前

    Serial.println(softSsid);         // 顯示SSID名稱

    Serial.print("softIP = ");      // 在Arduino IDE串列監控視窗中顯示目前使用的

    Serial.println(WiFi.softAPIP());    // 本地IP位址,在此為[ 192.168.0.100 ]

    server.begin();       // 啟動伺服器功能

  }  

  else

    Serial.println("soft-AP failed");

}

 

  // 主迴圈程式區:

void loop() {

  client=server.available();      // 測試是否有客戶端裝置連線

  if(!client)           // 

    return;           // 若無則結束迴圈

    

  // 有客戶端裝置連線上ESP8266 :

  URI=client.readStringUntil('\r');   // 取得第一行GET部分的內容

   Serial.println("Request end!");   // 送出提示訊息至Arduino IDE串列監控視窗中

  Serial.print("Uri = ");

  Serial.println(URI);

  if(URI.indexOf("/Led1On")>0)    // 測試URI是否為點亮LED1指令

  {    // URI為點亮LED1指令

    led1State=true;               // 設定LED1狀態為點亮

    digitalWrite(Led1,1);         // 點亮LED1

    Serial.println("LED1 is : On");

  }

  else if (URI.indexOf("/Led1Off")>0) // 測試URI是否為熄滅LED1指令

  {   // URI為熄滅LED1指令

    led1State=false;                // 設定LED1狀態為熄滅

    digitalWrite(Led1,0);           // 熄滅LED1

    Serial.println("LED1 is : Off");

  }

  else if(URI.indexOf("/Led2On")>0)   // 測試URI是否為點亮LED2指令

  {    // URI為點亮LED2指令

    led2State=true;               // 設定LED2狀態為點亮

    digitalWrite(Led2,1);         // 點亮LED2

    Serial.println("LED2 is : On");

  }

  else if (URI.indexOf("/Led2Off")>0) // 測試URI是否為熄滅LED2指令

  { // URI熄滅LED2指令

    led2State=false;                // 設定LED2狀態為熄滅

    digitalWrite(Led2,0);           // 熄滅LED2

    Serial.println("LED2 is : Off");

  }

  else if(URI.indexOf("/Led3On")>0)   // 測試URI是否為點亮LED3指令

  {    // URI點亮LED3指令

    led3State=true;                 // 設定LED3狀態為點亮

    digitalWrite(Led3,1);           // 點亮LED3

    Serial.println("LED3 is : On");

  }

  else if (URI.indexOf("/Led3Off")>0) // 測試URI是否為熄滅LED3指令

  { // URI為熄滅LED2指令

    led3State=false;                // 設定LED3狀態為熄滅

    digitalWrite(Led3,0);           // 熄滅LED3

    Serial.println("LED3 is : Off");

  }

  else if (URI.indexOf("/favicon")>0) // 測試是否為請求網頁小圖示URI

  {

    Serial.println("----> Get /favicon");

  }

  else if (URI.indexOf("/")>0)    // 測試是否為網頁首頁URI

  {

    led1State=false;                // 設定LED1狀態為熄滅

    digitalWrite(Led1,0);           // 熄滅LED1

    led2State=false;                // 設定LED2狀態為熄滅

    digitalWrite(Led2,0);           // 熄滅LED2

    led3State=false;                // 設定LED3狀態為熄滅

    digitalWrite(Led3,0);           // 熄滅LED3

    Serial.println("Web Home page!");

  }

  else

    handleNotFound();  // 若傳來的URI內容不在預期的指令中呼叫回傳錯誤提示副程式

  Serial.println();

  delay(5);

  mainPage=MAIN_page;               // 取得網頁首頁程式的前半部分

  if (led1State){                   // 測試LED1的設定狀態

    // LED1狀態為點亮

    mainPage+="<h3>LED1目前狀態 : 點亮</h3><br>";;

    mainPage+=html_Led1Off;   

  } else {

    // LED1狀態為熄滅

    mainPage+="<h3>LED1目前狀態 : 熄滅</h3><br>";;

    mainPage+=html_Led1On;    

  }

  if (led2State){                   // 測試LED2的設定狀態

    // LED2狀態為點亮

    mainPage+="<h3>LED2目前狀態 : 點亮</h3><br>";;

    mainPage+=html_Led2Off;   

  } else {

    // LED2狀態為熄滅

    mainPage+="<h3>LED1目前狀態 : 熄滅</h3><br>";;

    mainPage+=html_Led2On;    

  }

  if (led3State){                   // 測試LED3的設定狀態

    // LED3狀態為點亮

    mainPage+="<h3>LED3目前狀態 : 點亮</h3><br>";;

    mainPage+=html_Led3Off;   

  } else {

    // LED3狀態為熄滅

    mainPage+="<h3>LED3目前狀態 : 熄滅</h3><br>";;

    mainPage+=html_Led3On;    

  }

  mainPage+=html_end;     // 加上網頁結束html語法

  client.print(mainPage); // 送出回應網頁html檔案

  client.println();       

  client.flush();         // 將客戶端裝置傳送來的資料清空

  delay(10);

}

 

// 處理客戶請求錯誤的事件對應函式:

void handleNotFound(){

    String s=MAIN_page;

  s+="<h3>動作錯誤! ==> ";

  s+=URI;

  s+="</h3><br>";

  s+=html_end;

  client.print(s);

  Serial.print("URI not found -->");

  Serial.println(URI);

  Serial.println();

}



程式名稱softAP_6_5_3Led1.ino


程式說明

本範例程式是前面【六、5-1.4】小節中之softAP_6_5_1Led6_RYO.ino》程式的擴充版,前面的5~22行是在實作《softAP_6_5_3Led_form.html》這個html網頁程式的前半段(1~16行),第27行則定義了3顆LED所使用的腳位(GPIO 12,13,15)然後把三組表單按鈕的html語言部分以30~41行的6個字串變數(即“html_LedOn1”~ “html_LedOn3”和”html_LedOff1”~”html_LedOff3”)來取代

此外為了簡化程式,在第46行定義了三個用來表示三個LED或是說IO輸出腳的狀態的布林變數


boolean led1State=false,led2State=false,led3State=false;


接下來的程式一直到初始化(setup())區塊結束(第77行)為止和前面不同之處只有57~59行的設定3隻LED輸出腳指令

而主迴圈(loop())程式部分在86行


  URI=client.readStringUntil('\r');   // 取得第一行GET部分的內容


取得客戶端傳來得URI後,便由90~139行的程式進行一串的測試及判斷,看看此URI請求內容是否為“Led1On”~ “Led3On”和” Led1Off”~” Led3Off”之一,如果是的話,除了依內容分別控制對應LED的亮滅之外,就是去設定在第46行定義的三個代表三顆LED狀態的布林變數,以供後面設計回應客戶端的html網頁程式之用。如果URI內容是首頁請求”/則除了將三顆LED都熄滅,並且把三個代表三個LED的狀態的布林變數都重置為”false”若傳來的URI內容不在預期的指令中則呼叫回傳錯誤提示副程式《handleNotFound()》(第141行)

後面144~172行的程式會依三個代表LED狀態的布林變數內容去組合回應給客戶端的html網頁程式碼,然後直接將它回傳,以便將目前系統(ESP8266)處理的結果顯示在手機瀏覽器的螢幕上,供使用者參考


◎ 執行結果:

【圖六、38】是手機連線後瀏覽器螢幕畫面,和前面的【圖六、37】一樣,從最上面的網址輸入欄位列的內容是[ 192.168.0.100 ]可看出,這是瀏覽器剛連線上本伺服器首頁的狀態。因為此時只是剛連上網頁的首頁,所以三組的「LED? 目前狀態:」提示文字右邊都是顯示「熄滅」,而三個控制用的按鈕上的提示文字則是[點亮LED?],其中的’?’代表編號1~3。

圖六、38 手機連線後瀏覽器螢幕畫面


下面的【圖六、39】~【圖六、42】分別是LED1(紅色)、 LED2(綠色)、 LED3(藍色)及三顆LED同時點亮的畫面,其中圖的左邊是手機螢幕顯示的畫面,而右邊則是ESP-202模組板左上方那顆三色LED模組亮滅的情形。


圖六、39 LED1(紅色)點亮畫面


圖六、40 LED2(綠色)點亮畫面


圖六、41 LED3(藍色)點亮畫面


圖六、42 三顆LED同時點亮畫面


六、5-2.2 使用外掛函式庫控制3顆LED亮滅

Arduino 這個產品之所以會廣受全世界的使用者喜愛除了完全的開放環境之外最重要的就是有許多的高手創客無償無私地提供他們的研究心得在這個園地之中這些內容豐富又功能強大的所謂第三方函式庫可說是Arduino最重要的寶藏由於一些高手的努力ESP8266這個新興起的單晶片微電腦許多系列的模組板也成為Arduino IDE這個整合開發軟體的一員由於相容於Arduino IDE所以許多原來內建或是由第三方所提供的函式庫都可以無痛轉換到ESP8266系列模組上使用當然還有更多是專為ESP8266所開發的尤其是和無線WiFi有關的部分

在本節中就為各為介紹一個名為『ESPUI』的外掛函式庫,這個函式庫是由來自澳洲的Lukas Bachschwell年輕朋友所設計,如果使用了這個函式庫,那前面所有的範例都可以直接轉換採用,這樣一來不但畫面更好看,而且程式會更簡單設計!接下來就各位說明如何取得這個函式庫,和它提供那些功能可供我們使用。


『ESPUI.h』外掛程式庫安裝說明

要取得這個函式庫最好也是最簡單的方法就是使用Arduino IDE內建的程式庫管理員功能在啟動Arduino IDE後如【圖六、43】所示先用滑鼠左鍵點選主選單中標記1的[草稿碼]選項在系統帶出下拉選單後一樣用滑鼠左鍵點選標記2的匯入程式庫功能當出現新的選單視窗後再選取標記3的管理函式庫選項這時便可看到【圖六、44】的[程式庫管理員]彈出視窗


【圖六、43】 匯入程式庫操作畫面


在這個[程式庫管理員]彈出視窗中,我們將游標移動到標記2的搜尋文字輸入欄位中,輸入我們要找的『ESPUI』這個程式庫名稱後,便可在下方標記4的訊息視窗中看到相關的選項資料了!在本文撰寫時,這個程式庫已經更新到1.6.3版了只要點選標記3的選擇版本下拉按鈕就可以選擇所要的版本一般來說如果使用者是第一次安裝Arduino IDE系統會自動選擇最新的版本去安裝所以不用再去選擇版本。


【圖六、44】 程式庫管理員彈出視窗


從『ESPUI』這個程式庫名稱可以看出它主要是提供ESP8266這顆晶片的網頁人機介面(UI即User Interface)應用函式在本程式庫作者Lukas Bachschwell的Github網頁(網址為https://github.com/s00500/ESPUI)中對這個函式庫所提供的UI介面元件有詳細的說明在網頁中也提到這個程式庫並不是基本的程式庫還必須在Arduino IDE系統中再引入另外兩個程式庫

1ESPAsyncWebserver(網址https://github.com/me-no-dev/ESPAsyncWebServer)

2ArduinoJson (VERSIONS 5.x only currently)


由於Arduino IDE的[程式庫管理員]沒有支援第一個ESPAsyncWebserver程式庫所以必須到它的官方網站自行下載安裝此網頁位址及下載方的式如下面【圖六、45】所示

【圖六、45】


因為下載的程式庫檔案格式是”.ZIP”壓縮檔一般來說必須先解壓縮後才能掛入Arduino IDE的函式庫(library)資料夾中,不過也可以直接選取【圖六、43】中標記4的[加入.ZIP程式庫…]選項,然後找出該程式庫在電腦中下載存放的位置並選取它加入就可以了,後續的解壓縮與安裝都會由Arduino IDE自行處理

至於第二個需要的程式庫ArduinoJson 由於Arduino IDE內的[程式庫管理員]有支援所以直接使用[程式庫管理員]功能就可以按裝了其內容如下面的【圖六、46】所示不過原作者強調要使用5.X版的程式庫才不會有相容性的問題依筆者的實際測試結果要安裝【圖六、46】中標記2所示的5.13.1版才會完全相容其他的版本還是會有些問題


【圖六、46】 ArduinoJson程式庫管理員彈出視窗


『ESPUI.h』程式庫內建UI元件說明

在『ESPUI.h』的官方網頁中提到目前這個程式庫提供了下面八種可用於網頁中的使用者介面元件

  • Label (updateable)(文字標記)

  • Button(按鈕)

  • Switch (updateable)(開關)

  • Control pad(四向控制板)

  • Control pad with center button(含中央鍵之四向控制板)

  • Slider(滑桿)

  • Text Input (updateable)(文字輸入盒)

  • Numberinput (updateable)(數字輸入盒)

而這些網頁元件可使用的顏色共有下面八種

  • COLOR_TURQUOISE

  • COLOR_EMERALD

  • COLOR_PETERRIVER

  • COLOR_WETASPHALT

  • COLOR_SUNFLOWER

  • COLOR_CARROT

  • COLOR_ALIZARIN

  • COLOR_NONE

圖六、47 『ESPUI.h』程式庫可用之網頁介面元件與顏色


【圖六、47】是『ESPUI.h』程式庫中可用之網頁介面元件的外觀與顏色樣式其中標記2、3都是「Label」這種UI元件只是標題(Title)和內容文字不同而已其下方標註的”COLOR_XXXX”文字是該元件所使用的顏色名稱而標記4、5則是兩種不同顏色的”按鈕” 元件(「Button」),一樣只是標題(Title)和按鈕文字不同至於標記6、7則都是所謂的”開關”元件(「Switch」)而且使用相同的顏色接著的標記8、9一樣是兩個顏色相同的”控制滑桿”元件(「Slider」)最後的標記1011則分別是有中間按鈕的「Control Pad with Center Button」和無按鈕的”控制板” 元件(「Control  Pad」)

在圖最上方的標記1並不屬於任一種UI元件而是在執行初始化時由使用者自訂的文字訊息,或者可稱為整個UI介面的標題(Title)除了可作為這個網頁的標題之外還會自動顯示目前手機瀏覽器與ESP8266裝置的連線狀態

如果仔細去計算一下【圖六、47】中的UI元件種類的數目其實只有六種少了「Text Input」和「Number Input」這兩項在『ESPUI.h』程式庫的官方網頁中也沒看到作者的介紹不過在它們所提供的範例程式中倒是有出現由於在我們的範例程式中不會用到所以在此就略過不提有興趣的讀者可自行開啟該範例程式試試看效果如何。

接下來我們就使用上述的一些UI元件來取代之前使用標準的html語言程式去實現之前的一些範例動作


範例程式功能與動作說明

1、使用一個按鈕(Button)及兩個開關(Switch)元件控制ESP-202上並接在GPIO121315這三隻腳的三色LED模組(分別接在紅、藍、綠三種顏色)的亮滅

2、其中的按鈕按一次會使LED點亮再按一次則會讓LED熄滅,而開關元件則是依開(位置在右)或關(位置在左)的位置使LED亮滅這三顆LED亮滅的結果會回傳到連線裝置的瀏覽器螢幕上方的文字(Label)元件中讓使用者知道LED亮滅的狀態


在之前的範例,都是在開始設計程式之前,先規劃好使用者在手機瀏覽器上的操作介面,並設計一html網頁程式,將我們所希望得到的操作畫面在電腦的瀏覽器上呈現出來後,再轉移到ESP8266上去實現它。可是在本範例中,由於直接使用到內建在ESP8266上的UI元件,所以無法像一前一樣先在電腦的瀏覽器上執行並驗證;為了讓讀者們有一個清晰的概念,所以將手機實際連線的結果先顯示在下面的【圖六、48】中。


圖六、48 範例程式手機初始連線畫面


在【圖六、48】上方的標記1,是這個範例程式中ESP8266所建立的AP存取點之網路伺服器的IP位址,在此設定為固定的[192.168.0.100];而標記2是手機連線後網頁的標題文字,其內容為「ESP UI 按鍵與開關測試 :」,至於其右邊綠底的「Connected」文字是由『ESPUI.h』程式庫在初始化成功後依實際連線狀態自動產生的訊息,在此表示手機已經和ESP8266正常連線

接著由上而下依序是在第一個位置的「Label」UI介面元件、「Button」元件和兩個「Switch」元件,這四個元件都有自己獨立的標題文字。標記3所在的位置是「Label」這個元件真正顯示訊息的地方,而標記4、5則是兩個「Switch」元件開關撥動的位置在此都是位在代表”關閉”的左邊


下面是此範例程式的完整列表


 

#include <ESP8266WiFi.h>

#include <ESPUI.h>

 

IPAddress local_IP(192,168,0,100);  // 設定新的伺服器IP位址

IPAddress gateway(192,168,0,1);     // 設定新的伺服器閘道位址

IPAddress subnet(255,255,255,0);    // 設定新的伺服器網路遮罩位址

IPAddress apIP(192, 168, 1, 1);     // 設定新的伺服器IP位址

 

String softSsid = "ESP_softAP01";

const char* softPassword = "12345678";

 

long oldTime = 0;

bool state = false;

bool  padStatus[]={false,false,false,false,false};

byte  padPin[]={5,4,2,14,16};

byte  rgbPin[]={12,15,13};

 

// 初始化程式區 :

void setup(void) {

  Serial.begin(115200);

  WiFi.mode(WIFI_AP);             // 設定ESP8266為AP模式

  WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本地IP位址

  boolean result=WiFi.softAP(softSsid);       // 設定ESP8266為AP模式,不用密碼

  if(result==true)

  {  // 初始化設定AP存取點成功

    Serial.println("soft-AP ready!");

    Serial.print("softAP = ");    // 在Arduino IDE串列監控視窗中顯示目前

    Serial.println(softSsid);         // 顯示SSID名稱

    Serial.print("softIP = ");      // 在Arduino IDE串列監控視窗中顯示目前使用的

    Serial.println(WiFi.softAPIP());    // 本地IP位址,在此為[ 192.168.0.100 ]

 

    // 宣告一個label元件,元件ID為0,標題為"目前LED狀態",初始內容為 "三顆LED全滅"

    ESPUI.label("目前LED狀態", COLOR_SUNFLOWER, "三顆LED全滅");

    // 宣告一個Button元件,標題為"LED 紅"     

    ESPUI.button("LED 紅", &buttonCallback, COLOR_ALIZARIN);

    // 宣告一個Switch元件,標題為"LED 綠"

    ESPUI.switcher("LED 綠", false, &switchGreen, COLOR_TURQUOISE);

    // 宣告第二個Switch元件,標題為"LED 藍"

    ESPUI.switcher("LED 藍", false, &switchBlue, COLOR_PETERRIVER);

    // 初始化ESP UI介面,並設定網頁標題為"ESP UI 按鍵與開關測試 :"

    ESPUI.begin("ESP UI 按鍵與開關測試 :");    

    for(byte i=0;i<3;i++) {       // 設定GPIO12,13,15三隻腳為輸出

      pinMode(rgbPin[i],OUTPUT);

      digitalWrite(rgbPin[i],0);

    }

    state=false;

  }  

  else

    Serial.println("soft-AP failed");

    do {

      delay(1);

    } while(1);

}

 

  // 主迴圈程式區:

void loop(void) {

// 主程式內容式空的

}

 

    // 紅色按鈕button回叩服務副程式:

void buttonCallback(Control sender, int type) {

  switch (type) { // 測試按鈕觸發的來源為何

    case B_DOWN: // 按鈕被按下

      state=!state;   // 將按鍵狀態變數反相

      if(state) {     // 按鍵狀態變數為true則點亮LED

      Serial.println("Button DOWN, LED On!");

        digitalWrite(rgbPin[0],1); // 點亮LED

        ESPUI.print(0, "紅色 LED : 亮");

      }

      else  {     // 按鍵狀態變數為false則熄滅LED

      Serial.println("Button DOWN, LED Off!");

        digitalWrite(rgbPin[0],0); // 熄滅LED

        ESPUI.print(0, "紅色 LED : 滅");

      }

      break;

    case B_UP: // 按鈕被放開

//      Serial.println("Button UP");

      break;

  }

}

 

    // 綠色LED開關Switch回叩服務副程式:

void switchGreen(Control sender, int value) {

  Serial.println(sender.id);

  switch (value) {      // 測試開關狀態

    case S_ACTIVE:      // 若開關狀態為"ACTIVE"則點亮LED

      Serial.println("switch Green Active: On");

      digitalWrite(rgbPin[1],1); // 點亮LED

      ESPUI.print(0, "綠色 LED : 亮"); // 

      break;

    case S_INACTIVE:      // 開關狀態為"INACTIVE"則熄滅LED

      Serial.println("switch Green Inactive: Off");

      digitalWrite(rgbPin[1],0); // 熄滅LED

      ESPUI.print(0, "綠色 LED : 滅"); // 

      break;

  }

}

 

    // 藍色LED開關Switch回叩服務副程式:

void switchBlue(Control sender, int value) {

  Serial.println(sender.id);

  switch (value) {      // 測試開關狀態

    case S_ACTIVE:      // 若開關狀態為"ACTIVE"則點亮LED

      Serial.println("switch Blue Active: On");

      digitalWrite(rgbPin[2],1); // 點亮LED

      ESPUI.print(0, "藍色 LED : 亮");

      break;

    case S_INACTIVE:      // 開關狀態為"INACTIVE"則熄滅LED

      Serial.println("switch Blue Inactive: Off");

      digitalWrite(rgbPin[2],0); // 熄滅LED

      ESPUI.print(0, "藍色 LED : 滅");

      break;

  }

}



程式名稱softAP _GUI_1_BUT_SW.ino


程式說明

本範例程式由於使用了『ESPUI.h』這個程式庫(第2行)很明顯的整個程式比上一個softAP_6_5_3Led1.ino》少了快一半的程式碼,雖然說實際的大小並不是這樣,但以一個程式設計者來說,需要自己動手的部分就少很多了,而且網頁畫面的效果更好。

如果要使用『ESPUI.h』這個程式庫中所有的UI元件並不需要事先宣告特定的變數只要在初始化(setup())程式區中直接呼叫這UI元件就好了因此在始化程式區的32~41行便是在設定本次範例用到的一個「Label」UI介面元件、一個「Button」元件和兩個「Switch」元件的函式,以「Label」這個UI介面元件來說它的函式名稱與使用的引數格式如下:


ESPUI.label(“labelID”,COLOR,”DefaultContent”)


其中的”ESPUI.label”一看便知是它的函式名稱,而括弧中的第一個引數”labelID”是這個標記元件的標頭,但同時也是這個label的辨識ID第二個引數”COLOR”是這個元件的顏色,而第三個引數”DefaultContent”便是訊息框中預設的文字訊息,可以是空白內容。因此下面的程式便是在宣告一個標題為"目前LED狀態"的label元件,並設定文字框內的初始內容為"三顆LED全滅"。


33    ESPUI.label("目前LED狀態", COLOR_SUNFLOWER, "三顆LED全滅");


當要回傳訊息到這個標記時使用的指令如下


ESP.print(labelID, “Text”)


由於我們的”labelID”是中文在這個程式庫中是無法當成ID使用所以必須以它的設定順序當成ID在此為0


至於「Button」這個元件它的函式名稱與使用的引數格式如下:


ESPUI.button(“Title”,&buttonCallback,COLOR)


前面的”ESPUI.button”是它的函式名稱,而括弧中的第一個引數”Title”是這個按鈕元件的標頭,第二個引數則是這個按鈕元件被觸發時(觸發的事件包括按鈕被按下與放開)對應的處理副程式名稱,而第三個引數”COLOR”是這個元件的顏色。

下面的程式在宣告一個標題為"LED 紅"的「Button」元件,並設定處理按鍵被觸發的副程式為”buttonCallback”處理副程式名稱可依設計者的喜好自訂即使許多個按鈕共用一個副程式也無妨,因為我們可從觸發元件的ID來區分是誰觸發不過這種方式容易混淆因此不建議這樣使用;最後定義這個按鈕的顏色為「COLOR_ALIZARIN」。


35        ESPUI.button("LED 紅", &buttonCallback, COLOR_ALIZARIN);


而「Switch」這個元件它的函式名稱與使用的引數格式如下:


ESPUI.switcher(“Title”,state,&switchCallback,COLOR)


”ESPUI.switch”是它的函式名稱,而括弧中的第一個引數”Title”是這個開關元件的標頭,第二個引數是初始化時開關的預設狀態第三個引數則是這個開關元件被觸發時(觸發的事件包括開與關也就是右或左)對應的處理副程式名稱,最後第四個引數”COLOR”是這個元件的顏色。

下面的程式是在宣告一個標題為"LED 綠"的「Switch」元件,並設定初始化時開關的預設狀態是”關”(位置在左方),而處理這個開關被觸發的副程式名稱為”switchGreen”,這個開關的顏色為「COLOR_TURQUOISE」。


37      ESPUI.switcher("LED 綠", false, &switchGreen, COLOR_TURQUOISE);


至於另外一個控制藍色LED的開關元件其程式碼如下請自行參考


39     ESPUI.switcher("LED 藍", false, &switchBlue, COLOR_PETERRIVER);


當所有的UI介面元件都定義好之後便要執行初始化的動作這個動作的函式名稱與使用的引數格式如下:


ESPUI.begin("Title")


這個函式只有一個引數”Title”也就是整個網頁UI頁面的抬頭標題下面的程式會初始化ESP UI介面,並設定網頁標題為"ESP UI 按鍵與開關測試 :",除此之外還會自動偵測手機與ESP8266連線的狀態並顯示在標題的後面,如果訊息是Connected」代表連線正常反之則會出現「Error/No Connection」的訊息


41    ESPUI.begin("ESP UI 按鍵與開關測試 :");    


由於所有跟網頁有關的程式都由『ESPUI.h』這個程式庫所使用的UI介面元件包辦了因此主迴圈程式(loop())的內容在本範例中是空無一物我們只要處理這些UI元件被觸發時所對應的服務副程式就好了

接著的61~80行程式是紅色LED控制按鈕(button)回叩服務副程式(buttonCallback),這是一個不回傳值的副程式,使用到兩個引數,第一個引數是由ESPUI程式庫所自訂的型態為”Control”的”serder”代表呼叫這個副程式的按鈕UI元件ID,由於我們只有一個按鈕元件,所以可以不用去管它,假如每一個按鈕都有各自對應的副程式也一樣。如果有好幾個按鈕元件共用這個副程式,就可以由這個引數的值去判斷是那一個元件在呼叫。第二個引數”type”代表按鈕的觸發原因,是按鈕被按下(其值為”B_DOWN”)還是放開(值為”B_UP”)﹖為了讓按鈕動作反應比較快程式是在按鈕被按下時就開始動作但不管是按下或者是放開程式都會把相關的訊息傳送到Arduino IDE的序列監控視窗中以供開發時測試之用

在這個副程式中使用了”switch”這個流程判斷指令以對傳來的兩種觸發事件給予不同的反應動作不過真正有意義的是按鈕被按下(傳來的值為”B_DOWN”)的部分(63~75行)由於這個按鈕元件被按下時外觀並不會有什麼改變因此我們用一個布林變數”state”去代表按下的次數是偶數(狀態為“false”)還是奇數(狀態為“true”)當按鈕被按下時這個變數會被反相一次(第64行)然後再去測試結果為何如果是真(true)則65~69行程式會令接在第12腳的紅色LED點亮(在此輸出值為’1’)然後用下面這個指令把紅色 LED : 亮的訊息送到手機瀏覽器最上方的「Label」UI介面元件的訊息框中好讓使用者知道目前的動作結果


68         ESPUI.print(0, "紅色 LED : 亮");


假如結果是假(false)則70~74行程式會令接在第12腳的紅色LED熄滅(在此輸出值為’0’)同樣的用下面這個指令把紅色 LED : 滅的訊息送到瀏覽器最上方的「Label」元件的訊息框中以反映紅色LED目前的狀態


73         ESPUI.print(0, "紅色 LED : 滅");


當按鈕放開時會送出”B_UP”的觸發值這時程式(76~78行)只會單純的傳送"Button UP"這個訊息到Arduino IDE的序列監控視窗中不再進行任何動作。


從83行開始到程式結束分別是控制綠色(83~97行)與藍色(100~113行)兩顆LED開關(switch)元件的回叩服務副程式在此只說明控制綠色LED(接在第15腳)的”switchGreen”這個不回傳值的副程式。同樣的它也使用到兩個引數,第一個引數”serder”代表呼叫這個副程式的開關元件ID,第二個引數”value”表示目前開關的狀態,如果是被撥到左邊(一般代表關閉)這個值的內容為”S_INACTIVE”若是右邊則是” S_ACTIVE”但不管是開或是關程式都會把相關的訊息傳送到Arduino IDE的序列監控視窗中以供開發時測試之用

第85行程式同樣使用了”switch”這個指令去測試第二個引數”value”的內容如果是” S_ACTIVE”則會點亮綠色LED(88行)並使用下列程式把綠色 LED : 亮這個訊息傳送到使用者手機的”label”元件上


89      ESPUI.print(0, "綠色 LED : 亮");


反之當引數”value”的內容為”S_INACTIVE”時則令綠色LED熄滅(93行)並回傳綠色 LED : 滅」的訊息到手機瀏覽器上的”label”元件以提醒使用者


94      ESPUI.print(0, "綠色 LED : 滅");


◎ 執行結果:

在前面的【圖六、48】便是手機連線成功後,瀏覽器螢幕初始的畫面,由最上面的標記1網址輸入欄位列的內容是[ 192.168.0.100 ]可看出,這是瀏覽器剛連線上本伺服器首頁的狀態。標記2的「ESP UI 按鍵與開關測試 :」是這個範例程式的標題,而其右邊綠底的「Connected」文字是由『ESPUI.h』程式庫在初始化成功後,依實際連線狀態自動產生的訊息,在此代表手機已經和ESP8266正常連線。

而標記3這個做為ESP8266與使用者訊息介面的”label”元件上的提示文字內容為三顆LED全滅。由於按鈕這個元件不管是否曾經被按下外觀都不會改變因此是看不出目前狀態的至於標記4、5是兩個開關元件的開關初始狀態開始都是撥在左邊,也就是關閉(”S_INACTIVE”)。

下面的圖六、49是標記1這個LED 紅按鈕被按下一次的畫面這時接在ESP8266/ESP-202第12腳的紅色LED會點亮而且上面標記2”label”元件中的訊息文字框內會顯示《紅色LED:亮》的提示訊息如果再按一次這個按鈕則會使ESP-202上的紅色LED熄滅並使標記2”label”元件中的訊息文字框內容改成《紅色LED:滅》。

開關UI元件的使用方式是點選標記1之處開關的位置當點選或是碰觸到左邊時畫面中的方塊圖形會移到左邊反之則會移向右邊!【圖六、50】是使用“LED 綠”這個開關UI元件去點亮綠色LED的畫面從標記1之處可以看到這時開關的位置是被撥到了右邊(代表ON)而標記2”label”元件中的訊息文字框則是顯示《綠色LED:亮》的提示訊息

圖六、49 “LED 紅”按鈕按下畫面

圖六、50 “LED 綠”開關ON畫面


下面的【圖六、51】是使用“LED 藍”這個開關UI元件去點亮藍色LED的畫面,在標記1之處的開關位置撥到了右邊(代表ON),所以標記2”label”元件中的訊息文字框是顯示《藍色LED:亮》的提示訊息。如果開關撥到左邊的話,提示訊就會改成《藍色LED:滅》,當然接在ESP-202第13腳的藍色LED也會隨之熄滅。

圖六、51 “LED 藍”開關ON畫面


六、5-2.3使用外掛函式庫控制3顆LED漸層次亮滅

ESPUI這個程式庫所提供的UI元件簡單易用外觀也很好看不過唯一的缺點就是這些元件都沒辦法調整大小所以在單一個螢幕上就沒辦法放太多的元件如果只是要控制多個ESP8266輸出接腳可以使用其中的控制板元件(即「PAD」)假如啟用中央的控制按鈕一個「PAD」元件就可以控制到5個輸出這在需多的應用上應該使很足夠了。

在接下來的範例中會示範使用一個「PAD」UI元件去控制ESP-202實驗版上的5顆LED的亮滅此外再加上三個滑桿(Slider)元件去控制之前使用的RGB三色LED模組的亮度以做為像直流DC馬達PWN速度控制的參考


範例程式功能與動作說明

1、使用一個有中間按鈕的控制板元件(「Control Pad with Center Button」),控制ESP-202中間除了GPIO00之外,其他IO接腳所並接的5顆藍色LED的亮滅,控制板的上、下、左、右及中間按鍵,分別對應到ESP8266的GPIO 5、4、2、14、16這5隻接腳,這5顆LED的亮滅狀態會回傳到連線裝置的瀏覽器螢幕上方的文字(Label)元件中,以提醒使用者。

2、使用三個控制滑桿(Slider)元件分別控制ESP-202上並接在GPIO12、13、15這三隻腳的三色LED模組(分別接在紅、藍、綠三種顏色)的明亮度;這三顆LED的明亮度同樣會回傳到連線裝置的瀏覽器螢幕上方的文字(Label)元件中,讓使用者知道LED點亮的程度。


這個範例同樣沒有辦法先設計一html網頁程式,將我們所希望得到的操作畫面在電腦的瀏覽器上呈現出來驗證後,再轉移到ESP8266上去實現它,所以我們將手機實際連線的結果先顯示在下面的【圖六、52】中。在圖中由上到下所使用的ESPUI元件依序是

1、ESPUI初始化標題

2、文字標記框Label

3、5鍵控制板 Control Pad with Center Button

4、紅色LED控制滑桿Slider

5、綠色LED控制滑桿Slider

6、藍色LED控制滑桿Slider


圖六、52 範例程式手機初始連線畫面


由於這個範例總共控制了8個GPIO輸出如果每一個輸出都使用一個回應的訊息元件「Label」的話整個介面將過於龐大以使用者的觀點來說不是很方便必須經常上下滑動螢幕畫面因此在這個範例中只使用了一個「Label」元件去顯示目前操作的結果。即使就算是這樣精簡了還是會有許多手機的螢幕無法顯示完整的UI操作介面

下面就是完整的範例程式內容

 

#include <ESP8266WiFi.h>

#include <ESPUI.h>

 

IPAddress local_IP(192,168,0,100);  // 設定新的伺服器IP位址

IPAddress gateway(192,168,0,1);     // 設定新的伺服器閘道位址

IPAddress subnet(255,255,255,0);    // 設定新的伺服器網路遮罩位址

IPAddress apIP(192, 168, 1, 1);     // 設定新的伺服器IP位址

 

String softSsid = "ESP_softAP01"; // 軟體AP點的名稱

const char* softPassword = "12345678"; // 軟體AP點的連線密碼,在本範例程式中並未使用

long oldTime = 0;

bool state = false;

bool  padStatus[]={false,false,false,false,false};  // 含中央鍵之PAD元件按鍵對應狀態陣列

byte  padPin[]={5,4,2,14,16}; // 含中央鍵之PAD元件對應之GPIO腳位

byte  rgbPin[]={12,15,13};    // RGB三色LED模組對應之GPIO腳位

 

// 初始化程式區 :

void setup(void) {

  Serial.begin(115200);

  WiFi.mode(WIFI_AP);             // 設定ESP8266為AP模式

  WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本地IP位址

 

  WiFi.softAP(softSsid); // 設定ESP8266為AP模式,不用密碼

  Serial.println("soft-AP ready!");

  Serial.print("softAP = ");    // 在Arduino IDE串列監控視窗中顯示目前

  Serial.println(softSsid);         // 顯示SSID名稱

  Serial.print("IP address: ");

  Serial.println(WiFi.softAPIP());

 

    // 宣告一個label元件,標題為"目前LED狀態",並設定初始內容為 "LED全部熄滅"

  ESPUI.label("目前按鍵狀態", COLOR_WETASPHALT, "LED全部熄滅");

    // 宣告一個Pad元件,標題為"含中央鍵之四向控制板"     

  ESPUI.pad("含中央鍵之四向控制板", true, &padExample, COLOR_SUNFLOWER);

    // 宣告一個Slider元件,標題為"紅色LED控制滑桿"     

  ESPUI.slider("紅色LED控制滑桿", &slider, COLOR_ALIZARIN, "0");

    // 宣告一個Slider元件,標題為"綠色LED控制滑桿"     

  ESPUI.slider("綠色LED控制滑桿", &slider, COLOR_EMERALD, "0");

    // 宣告一個Slider元件,標題為"藍色LED控制滑桿"     

  ESPUI.slider("藍色LED控制滑桿", &slider, COLOR_PETERRIVER, "0");

 

  //  初始化ESPUI元件

  ESPUI.begin("ESP PAD及Silder介面RGB測試 :");

  

  for(byte i=0;i<5;i++) {     // 設定PAD 5個按鍵對應的5隻腳為輸出

    pinMode(padPin[i],OUTPUT);

    digitalWrite(padPin[i],1);

  }

}

 

  // 主迴圈程式區:

void loop(void) {

 // 主程式區空白

}

 

//  滑桿處理副程式 :

void slider(Control sender, int type) { 

    Serial.print(sender.id); // 顯示觸發的滑桿ID號碼

    Serial.print(" value= ");

    Serial.println(sender.value); // 顯示滑桿傳來的控制值

    analogWrite(rgbPin[sender.id-2],10.23*(sender.value.toInt())); // 依傳來的控制值產生對應的PWM輸出到對應的LED接腳

    String  colorSlider;

    if(sender.id==2) // 依照觸發ID的編號回應LED的顏色種類

      colorSlider="紅色: "+String(sender.value);

    else if(sender.id==3)

      colorSlider="綠色: "+String(sender.value);

    else

      colorSlider="藍色: "+String(sender.value);

    ESPUI.print(0, colorSlider); // 將輸出結果回傳到使用者端的文字標記框中

    

}

 

//  5鍵控制板Pad處理副程式 :

void padExample(Control sender, int value) {

  String state;

  switch (value) { 引數”value”的內容代表按鍵的種類

    case P_LEFT_DOWN: // 測試是否為左鍵被按下

      Serial.print("left down");

      padStatus[2]=!padStatus[2];

      if(padStatus[2]) {

        ESPUI.print(0,"左:開");

        digitalWrite(padPin[2],0);

      }

      else {

        ESPUI.print(0,"左:關");

        digitalWrite(padPin[2],1);

      }

      break;

    case P_RIGHT_DOWN: // 測試是否為右鍵被按下

      Serial.print("right down");

      padStatus[3]=!padStatus[3];

      if(padStatus[3]) {

        state="右:開";

        ESPUI.print(0,"右:開");

        digitalWrite(padPin[3],0);

      }

      else  {

        state="右:關";

        ESPUI.print(0,"右:關");

        digitalWrite(padPin[3],1);

      }

      break;

    case P_FOR_DOWN: // 測試是否為前進或上方鍵被按下

      Serial.print("for down");

      padStatus[0]=!padStatus[0];

      if(padStatus[0])  {

        ESPUI.print(0,"前:開");

        state="前:開";

        digitalWrite(padPin[0],0);

      }

      else  {

        state="前:關";

        ESPUI.print(0,"前:關");

        digitalWrite(padPin[0],1);

      }

      break;

    case P_BACK_DOWN: // 測試是否為後退或下方鍵被按下

      Serial.print("back down");

      padStatus[1]=!padStatus[1];

      if(padStatus[1])  {

        state="下:開";

        ESPUI.print(0,"下:開");

        digitalWrite(padPin[1],0);

      }

      else  {

        state="下:關";

        ESPUI.print(0,"下:關");

        digitalWrite(padPin[1],1);

      }

      break;

    case P_CENTER_DOWN: // 測試是否中央鍵被按下

      Serial.print("center down");

      padStatus[4]=!padStatus[4];

      if(padStatus[4])  {

        ESPUI.print(0,"中:開");

        digitalWrite(padPin[4],0);

      }

      else  {

        ESPUI.print(0,"中:關");

        digitalWrite(padPin[4],1);

      }

      break;

  }

  Serial.print(" ");

  Serial.println(sender.id);

}



程式名稱softAP _GUI_2_PAD_Slider2.ino


程式說明

程式的1~15行是相關的引入檔及變數定義區和之前的範例主要不同的是下面兩個陣列變數由於一個有中央按鍵的PAD元件其實就等於5個按鈕集中在一起在本範例中我們的按鍵一樣也會在被按下時觸發動作所以在程式的第13行定義一個對應到這5鍵控制板的布林陣列變數


13   bool  padStatus[]={false,false,false,false,false};  // 5鍵PAD元件按鍵狀態陣列


以作為按鍵被按下的次數是偶(值為”false”)或奇數(“true”)的紀錄這5個按鍵狀態變數依序對應到上、下、左、右、中這5個按鍵。

至於這5個按鍵對應到的ESP8266的GPIO接腳由程式的第14行所定義


14   byte  padPin[]={5,4,2,14,16}; // 含中央鍵之PAD元件對應之GPIO腳位


第15行則是定義RGB三色LED所對應的輸出腳


15    byte  rgbPin[]={12,15,13};    // RGB三色LED模組對應之GPIO腳位


始化程式區(“setup()”,18~48行)中的30~39行在設定本次範例用到的四個UI元件第一個是顯示回應訊息用的「label」UI介面元件


31 ESPUI.label("目前按鍵狀態", COLOR_WETASPHALT, "LED全部熄滅");  


接著是具中央按鍵的控制板「pad」


33   ESPUI.pad("含中央鍵之四向控制板", true, &padExample, COLOR_SUNFLOWER);


而「pad」這個元件它的函式名稱與使用的引數格式如下:


ESPUI.pad(“Title”,center_pad,&padCallback,COLOR)


”ESPUI.pad”是它的函式名稱,而括弧中的第一個引數”Title”是這個開關元件的標頭,第二個引數”center_pad”是中央按鍵的啟用選擇值為”true”代表啟用反之為”false”則是不啟用第三個引數” &padCallback”則是這個「PAD」元件被觸發時(觸發的事件是五個按鈕中任一個被按下或者是放開)對應的處理副程式名稱,在此使用的名稱為” &padExample”最後第四個引數”COLOR”是這個元件的外觀顏色。

接著是宣告三個控制RGB三色LED模組亮度的Slider元件


34    // 宣告一個Slider元件,標題為"紅色LED控制滑桿"     

35 ESPUI.slider("紅色LED控制滑桿", &slider, COLOR_ALIZARIN, "0");

36    // 宣告一個Slider元件,標題為"綠色LED控制滑桿"     

37   ESPUI.slider("綠色LED控制滑桿", &slider, COLOR_EMERALD, "0");

38   // 宣告一個Slider元件,標題為"藍色LED控制滑桿"     

39  ESPUI.slider("藍色LED控制滑桿", &slider, COLOR_PETERRIVER, "0");


Slider這個元件它的函式名稱與使用的引數格式如下:


ESPUI.slier(“Title”, &sliderCallback,COLOR,Initial_val)


ESPUI.slider是這個控制滑桿函式的名稱,而括弧中的第一個引數”Title”是這個開關元件的標頭,第二個引數” &sliderCallback”是這個「Slider」元件被觸發時(觸發的事件是元件中的滑桿被牽引移動或被碰觸到)對應的處理副程式名稱,在此使用的三個元件共用一個名稱為” &slider”的副程式第三個引數”COLOR”是這個元件的外觀顏色最後第四個引數” Initial_val”是這個「Slider」元件中滑桿的初始值在此設定為”0”。由於這三個控制滑桿元件依宣告的次序是345(前面兩個是「label」和「pad」)所以它們被分配到的UI元件id號碼會是234

在宣告完使用的UI元件跟它們對應的服務函式之後當然就是要初始化這些元件了


42  ESPUI.begin("ESP PAD及Silder介面RGB測試 :");


在此設定這個ESPUI介面程式的螢幕標題是ESP PAD及Silder介面RGB測試 :

初始化程式區中最後的部分(44~47行)在設定PAD控制板的5個按鍵所對應的5隻腳為輸出模式。在本範例中主迴圈程式(51~53行)由於沒有需要執行任何動作,所以一樣是空的。

接著的56~70行程式是控制R、G、B三個LED亮度共同使用的滑桿(silder)回應服務副程式「silder」,這是一個不回傳值的副程式,使用到兩個引數,第一個引數是由ESPUI程式庫所自訂的型態為”Control”的”serder”,代表呼叫這個副程式的控制滑桿UI元件ID,我們可以從這個引數的值去判斷是那一個元件在呼叫。第二個引數”type”代表觸發原因,在這裡並未被使用到。


56    void slider(Control sender, int type)  


副程式開始的57~59行程式會把觸發呼叫的控制滑桿id號碼及滑動的位移值顯示在Arduino IDE的序列監控視窗中,然後使用下列指令把設定的PWM值送到對應的LED輸出接腳


60    analogWrite(rgbPin[sender.id-2],10.23*(sender.value.toInt()));


在這行程式中的analogWrite是Arduino中用來控制PWM輸出的內建指令同樣也可以適用在ESP8266上指令中使用到兩個引數第一個是輸出PWM信號的IO腳位(即”rgbPin[sender.id-2]”)其中的”sender.id-2”這個變數是觸發動作的滑桿UI元件的id號碼第二個是引數則是輸出PWM的脈波寬度由於ESPUI程式庫中滑桿(silder)這個元件的控制範圍只有1~100可是ESP8266的PWM輸出範圍則是從0~1023所以必須經過轉換之後(也就是將控制值”sender.value.toInt()”乘以10.23)才能使用

剩下的63~69行程式會依觸發動作的滑桿UI元件id號碼去整合回應用的訊息文字訊息中包括了對應的LED顏色和亮度值(即”sender.value“)最後再以下面的指令將結果回傳到使用者端的文字標記框(label)中


69      ESPUI.print(0, colorSlider); 


剩下的73~134行程式是5鍵控制板(pad)的回應服務副程式「padExample」


73    void padExample(Control sender, int value) 


這個副程式使用了兩個引數,第一個引數一樣是由ESPUI程式庫所自訂的型態為”Control”的”serder”,代表呼叫這個副程式的控制滑桿UI元件id,由於範例中只有一個pad所以這個引數不會用到!第二個引數”value”代表被按下的控制板5個按鍵的名稱及動作內容,按鍵的名稱共有5種分別是,英文字母都是大寫:

    1. P_LEFT:左向鍵

    2. P_RIGHT:右向鍵

    3. P_FOR:前向鍵

    4. P_BACK:後向鍵

    5. P_CENTER:中央鍵

至於動作內容則只有兩個分別是

  1. _DOWN按下

  2. _UP放開


經由按鍵名稱及動作內容的組合便可得知這個5鍵控制板(pad)的所有觸發狀態

在這個副程式中使一樣使用”switch”這個流程判斷指令以測試觸發事件的來源與內容,由於5個案件處理的過程大同小異,在此僅舉左鍵被按下(即“value”的內容為「P_LEFT_DOWN」)的程式(76~87行)來說明


76    case P_LEFT_DOWN: // 測試是否為左鍵被按下

77      Serial.print("left down");

78      padStatus[2]=!padStatus[2];

79      if(padStatus[2]) {

80        ESPUI.print(0,"左:開");

81        digitalWrite(padPin[2],0);

82      }

83      else {

84        ESPUI.print(0,"左:關");

85        digitalWrite(padPin[2],1);

86      }

87      break;


由於這幾個按鈕元鍵被按下時外觀並不會有什麼改變,因此我們用前面定義過的控制板用布林變數陣列”padStatus[2]”去記錄按鍵按下的次數是偶數(狀態為“false”)還是奇數(狀態為“true”),當按鈕被按下時這個變數會被反相一次(第78行),然後再去測試結果為何﹖如果是真(true),則8081行程式會令接在padPin[2](在此為GPIO2)腳的LED點亮(輸出值為’0’),並把「左 : 開」的訊息送到手機瀏覽器最上方的「Label」UI介面元件的訊息框中,讓使用者知道目前的動作結果。

假如結果是假(false)則8485行程式會令接在第2腳的LED熄滅(在此輸出值為’1’)同樣的用下面這個指令把左:關的訊息送到瀏覽器最上方的「Label」元件的訊息框中以反映紅色LED目前的狀態

5鍵控制板中其他的按鍵都是測試按鍵是否被按下觸發條件由於處理的程式雷同就請自行參考前述的程式列表內容。


◎ 執行結果:

前面的【圖六、52】是手機瀏覽器連線後螢幕的畫面,便是手機連線成功後,瀏覽器螢幕初始的畫面,由最上面的網址輸入欄位列的內容是[ 192.168.0.100 ]可看出,這是瀏覽器剛連線上本伺服器首頁的狀態。標記1的「ESP  PAD及Slider界面RGB測試 :」是這個範例程式的標題,而其右邊綠底的「Connected」文字是由『ESPUI.h』程式庫在初始化成功後,依實際連線狀態自動產生的訊息,在此代表手機已經和ESP8266正常連線。而標記2這個做為ESP8266與使用者訊息介面的”label”元件上的提示文字內容為LED全部熄滅

下面的【圖六、53】是標記1這個四向控制板中央按鍵被按下一次點亮LED畫面,這時接在ESP8266/ESP-202上標記3的GPIO16腳藍色LED會點亮,而左邊手機端螢幕上面標記2”label”元件中的訊息文字框內會顯示《中:開》的提示訊息。右方照片中標記4的LED及標註「GPIO00」由於尚未移開燒錄用的短接頭所以會呈現點亮的狀態。


圖六、53 四向控制板中央按鍵點亮LED畫面


圖六、54 四向控制板點亮全部5顆LED畫面


至於【圖六、54】則是使用5鍵的四向控制板點亮全部5顆LED畫面這時如果再按下任一鍵就會使對應的LED熄滅

圖六、55 紅色LED控制滑桿動作畫面


圖六、56 綠色LED控制滑桿動作畫面


【圖六、55】、【圖六、56】分別是使用紅色及綠色LED亮度控制滑桿操作的畫面,如果跟前面【圖六、49】、【圖六、50】使用開關直接控制LED的ON、OFF的結果來比較,可以看出兩者之間的亮度有明顯的不同。雖然說ESP8266在做PWM控制輸出時範圍可以由0到1023之間變化可是受限於ESPUI程式庫中「slide」元件的可用範圍只有1~100所以無法提供比較高的解析度這可說是「slide」這個元件美中不足之處希望很快能看到原創者的修正與升級。


沒有留言:

張貼留言