我的ESP32實做書籍:我出書了 ESP32 物聯網專題
博客來網址:https://www.books.com.tw/products/0010901195
實作說明
本章將介紹ESP32的藍芽通訊,藍芽與WiFi都是用來通訊,藍芽通常用於近端點對點通訊,WiFi則常用來連入網際網路,所謂的點對點就像是藍芽無線耳機與手機連接,用來播放音樂,或者藍芽滑鼠鍵盤功能是輸入文字,只是一種序列通訊,功能較為簡單,因此不需要像WiFi這樣太複雜的設定,不過藍芽雖然簡單,但是使用上方便,只要配對就可以取用服務,所以也非常流行。
與藍芽同位階的應該算是紅外線,不過紅外線有方向性,是要對準裝置才能傳輸,速度慢不說,距離大概不能超過10公尺,而藍芽則無方向性,因此不用對準,而且傳輸距離遠、速度也比紅外線快很多。
本書將會介紹如何使用ESP32藍芽與手機連線通訊,並透過手機的語音辨識遙控電風扇及檯燈,此外也會介紹最新的ibeacon室內定位裝置原理及實做。本章先簡介ESP32的藍牙通訊設定與使用,由於是藍芽內建的,所以不用接線或設定AT COMMAND,也不用宣告TXRX相關的通訊協定,而且ESP32內建的藍芽是採用低功率藍芽(BLE:Bluetooth Low Energy)耗電量較少,傳輸距離理論可達300公尺遠,實際測試30公尺沒問題,而常見搭配UNO使用的HC-05屬於藍芽2.1,理論傳輸距離只有10公尺,本章將介紹如何的啟動ESP32藍芽裝置,並搭配Android手機進行通訊。
一、藍芽單向傳輸
本節說明使用ESP32藍芽將資訊傳遞給藍芽裝置(手機)進行接收,由於bluetooth函式庫iOS手機不相容的原因,後續章節都將使用Android裝置進行解說。
ESP32藍芽的開啟僅需幾個步驟:
- 使用藍芽函式庫:#include
- 宣告藍芽序列通訊物件:BluetoothSerial BT;//BT為藍芽通訊物件
- 在Setup中開啟藍芽:BT.begin(“BTName”);// BTName為藍芽廣播名稱
- 當要傳輸資訊時:BT.print(“要傳輸的文字”);//println則是換行
我們先來一個簡單的測試,就是每秒傳輸一次”Hello World!”到手機中,程式如下
#include <BluetoothSerial.h>
BluetoothSerial BT;//宣告藍芽物件,名稱為BT
void setup() {
Serial.begin(115200);
BT.begin("Eric1030");//請改名例如英文+生日,以免與其他同學名稱重複
}
void loop() {
BT.println("Hello World!");
delay(1000);
}
完成程式上傳後,我們來處理手機的部份,請將Android手機開啟App store,並搜尋Arduino Bluetooth Control,其圖示如下,APP Store有很多類似的APP其實功能都差不多,但是我們選定的這個APP有提供語音辨識的功能,後續練習將會用到。
讀者若無法找到該APP,可能是版本不相容,但可從筆者雲端空間中下載備份APK檔案:https://t.ly/YRWpD
手機安裝好APP後,啟動藍芽連線設定如圖2,如果未在可用裝置中出現請點選不常用類型裝置,您所設定的ESP32藍芽名稱就會出現在這裡(如圖3),點選您的ESP裝置就會出現配對訊息(如圖4),點選下方的配對即可完成配對(如圖5)。
完成配對後,開啟剛剛安裝的Arduino Bluetooth Control APP,若沒有自動連線,則點選上方的箭頭圖示選擇要本次要連線的ESP32裝置(如圖6)。
連線成功時,下方會出現「Connected to 裝置名稱」的訊息(如圖7),此時再點選序列通訊的功能,即可看到每秒一次的「Hello World!」訊息(如圖8)。
接下來我們使用DHT11溫濕度計為範例,將溫濕度的值傳入手機中,關於DHT11溫濕度計的使用方式請參考前面章節的內容,另外每次ESP32更新程式時重新啟動時,APP都必須按一下連線的圖示 ,重新與裝置建立連線,才能讀取資訊。
#include <SimpleDHT.h>
#include <BluetoothSerial.h>
BluetoothSerial BT;
int pinDHT11 = 25; //本例請將溫度計S腳接在左11 (GPIO25)
SimpleDHT11 dht11(pinDHT11);
void setup() {
Serial.begin(115200);
BT.begin("Eric1030");//請改名
}
void loop() {
// start working...
Serial.println("=================================");
Serial.println("Sample DHT11...");
// read without samples.
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("Read DHT11 failed, err="); Serial.println(err); delay(1000);
return;
}
//將溫濕度傳輸到藍芽裝置
BT.print((int)temperature);
BT.print(" *C,");
BT.print((int)humidity);
BT.println(" H");
delay(1000); //休息1秒
}
二、藍芽雙向傳輸
只有ESP32傳送資料到手機
可以反過來讓手機傳資料到ESP32嗎?
當然可以,而且更好玩。這部份ESP32的流程是這樣的
- 檢測藍芽是否有資料:BT.available()
- 如果有資料,我們就把資料讀出:BT.readString()
- 將資料從電腦的序列視窗(Serial)中印出來。
這部份的程式如下
#include <BluetoothSerial.h>
BluetoothSerial BT;
void setup() {
Serial.begin(115200);
BT.begin("Eric1030");//請改名
}
void loop() {
//檢查藍芽內是否有資料
while (BT.available()) {
//讀取藍芽資料
String BTdata=BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
}
delay(1);
}
連線成功後,一樣點選右上序列通訊功能後,此次在下方的空白處,輸入文字並按鍵盤的Done或Enter送出後,我們即可在電腦的序列通訊視窗中收到手機傳來的訊息。
不過這樣單方面只能手機講話有點孤單
我們要如何讓ESP32也能打字回覆?
其實語法很類似,只是與藍芽的方向相反,就是檢查序列是否有資料輸入Serial.available(),當Serial.available()時用Serial.readString()將資料讀入後,再用BT.println()將資料送到手機。不過ESP32要在哪裡打字呢?是透過序列通訊視窗上面的空白處(如圖13),本部份程式如下
#include <BluetoothSerial.h>
BluetoothSerial BT;
void setup() {
Serial.begin(115200);
BT.begin("Eric1030");//請改名
}
void loop() {
//檢查序列內是否有資料
while (Serial.available()) {
//讀取序列資料
String Sdata = Serial.readString();
//傳輸給藍芽
BT.println(Sdata);
}
//檢查藍芽內是否有資料
while (BT.available()) {
//讀取藍芽資料
String BTdata = BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
}
delay(1);
}
三、藍芽指令與語音辨識
這樣的程式只能拿來藍芽聊天嗎?
其實這可以用來遙控一些東西,例如我們用簡單的LED燈來測試,將LED依照前面的內容依序將綠黃紅放置在GPIO4,16,17(麵包板右7,8,9)位置,接下來我們假設ESP32從藍芽接到傳來’1’時,就開啟綠LED,而’2’代表關閉綠LED,其餘雷同,’3”4’代表開啟及關閉黃LED,’5”6’代表開啟及關閉紅LED,這樣我們就可以用手機來遙控三個燈號。完整程式如下
#include <BluetoothSerial.h>
BluetoothSerial BT;
void setup() {
Serial.begin(115200);
BT.begin("Eric1030");//請改名
pinMode(15, OUTPUT); //綠色LED
pinMode(2, OUTPUT); //黃色LED
pinMode(4, OUTPUT); //紅色LED
}
void loop() {
//檢查序列內是否有資料
while (Serial.available()) {
//讀取序列資料
String Sdata = Serial.readString();
//傳輸給藍芽
BT.print(Sdata);
}
//檢查藍芽內是否有資料
while (BT.available()) {
//讀取藍芽資料
String BTdata = BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
//檢查藍芽資料及相對的指令
if (BTdata == "1") {
//1:開綠燈
digitalWrite(15, HIGH);
}
if (BTdata == "2") {
//2:關綠燈
digitalWrite(15, LOW);
}
if (BTdata == "3") {
//3:開黃燈
digitalWrite(2, HIGH);
}
if (BTdata == "4") {
//4:關綠燈
digitalWrite(2, LOW);
}
if (BTdata == "5") {
//5:開紅燈
digitalWrite(4, HIGH);
}
if (BTdata == "6") {
//6:關紅燈
digitalWrite(4, LOW);
}
}
delay(1);
}
我們將數字1~6按過一次,就會發現燈號依序亮起熄滅,代表藍芽傳輸正常。
除了使用序列通訊用自己打字的方式之外,也可以使用APP上其他的功能,我們先來看看左側上方的方向鍵,我們點選不同方向時,觀察獲得的資訊,會發現其實每個方向對應的是一個數字(如圖17)
因此按下不同方向,剛好可以控制燈號,例如「^」對應數字「1」,所以按「^」就會開啟綠燈,在按鈕時要請讀者慢慢按,不要太急,否則他會將很多數字合成一個字串才送出,例如一直按往上「^」會送出「11111」,而這樣的方式我們的程式是無法判讀的,因為我們是用字串比對,而非字元比對。
而在加速器上,則對應的方向與上面的方向鍵是相同的,不過他的控制是用手機的傾斜方向來控制送出的訊號,例如你將手機向前傾斜一秒鐘後復原水平狀態,手機會對ESP32送出一連串的「11111111」,向後則會送出「2222222…..」等,有些手機硬體沒有支援加速器,就不會送出任何資料,與上面相同的,我們程式以字串比對,所以這個功能無法控制燈號。
按鈕控制功能
按鈕的功能如圖示,不過這裡APP有一個小bug,就是5、6是標錯的,預設標成4、4(如圖20),我們要進入設定進行修改。
點選右上機器人圖示按鈕進入設定功能,尋找「Command button configuration」(如圖21),點選Button E,然後修改對應的值從4改為5,相同的步驟,請設定Button F對應的值為6。完成修改設定之後,一樣依序點選按鈕,也可以觀察到燈號的變化
語音指令功能
最後我們來看右下角的功能語音指令(Voice Control),也就是透過語音辨識來控制傳輸的,不過我們一樣必須先設定語音及所對應的文字,例如,當我們說「開綠燈」,手機就送出「1」到ESP32,而根據判斷ESP32獲得1就會開啟綠色LED。
我們先點選右上角的機器人圖示來設定語音指令,進入設定後往下拉到底,可以找到「Vocal Command Configuration」的功能(如圖24),進入設定畫面後,該APP一共提供10個語音指令(如圖25),我們先設定一個作為示範。
設定方式如下,我們點選第一個語音指令「Vocal Command no1」後,一共有兩個值要設定,第一個Vocal command代表要講的話,第二個Data to send則是要在藍芽發送的文字,舉例來說,要講的話就是「開綠燈」(如圖26),而要在藍芽發送的文字則是「1」(如圖27)。
這樣當手機聽到我們講「開綠燈」時,就會發送1到ESP32,而依據程式的判斷,收到1就會開啟綠燈。而其餘的語音指令則可以依照相同的方式設定,例如「Vocal Command no2」的Vocal command設定為「關綠燈」、Data to send設定為「2」,而「Vocal Command no3」的Vocal command設定為「開黃燈」、Data to send設定為「3」等等。
接下來我們就可以利用手機語音辨識的功能,來控制燈號開關,回到APP首頁畫面後(如圖28),點選右下角的「Voice Control」語音按鈕就會跳出麥克風圖示(如圖29),點選麥克風後,請讀者說出設定好的語音指令,例如「開綠燈」,此時手機辨識「開綠燈」成功後(如圖30),就會在藍芽送出「1」給ESP32,ESP32就可以開啟綠燈。
本練習只用來開啟或關閉LED,當然有點大材小用,但是讀者可以自行開發新的功能,例如透過繼電器relay來開啟或關閉電風扇、檯燈、甚至冷氣等等的家電,而達到簡易的智慧家電的功能。
參考本人之前的作品如下
PS.本練習其實只有用到ESP32 藍芽2.0 Serial Port Profile(SSP)通訊。