藍牙模組補充說明(四):無線連結兩個Arduino控制板

本文將示範讓兩個Arduino控制板透過藍牙連線傳遞訊息。

Arduino藍牙無線通信實驗

本單元的實驗材料:

  • 兩個Arduino控制板
  • 兩個藍牙模組:其中一個必須是HC-05,另一個可以是HC-05或HC-06。
  • (選擇性的)兩個1KΩ(棕黑紅)~4.7KΩ(黃紫紅)電阻
  • Android或iPhone手機一支

讓HC-05與另一個藍牙模組在通電時自動配對

藍牙模組有「主控端」和「從端」兩種模式,在配對時,一定是由「主控端」主導,探索其他「從端」並與之配對連線;從端無法彼此互連。

HC-05模組可以透過AT命令,設定成「主控端(Master)」或「從端(Slave)」;HC-06模組只能當「從端」。因此在配對連線實驗中,至少要有一個HC-05模組。

每個藍牙模組都有一個唯一的位址,主控端模組可透過AT+BIND命令(註:“bind”代表「繫結」)紀錄要配對的從端位址,設定好之後,它就能在通電(開機)時,自動探索並和指定位址的從端相連,這中間的過程,不需要Arduino介入,也就是不必寫任何程式碼。

藍牙模組能在開機時自動配對連結

一旦藍牙自動連線完成,Arduino控制板就能透過藍牙傳輸訊息。

使用手機的「藍牙掃描器」App取得藍牙裝置的位址

進行配對之前,我們得先知道從端的位址。取得位址的方法有兩種:

  • 使用手機App掃描
  • 透過AT命令讀取(僅適用於HC-05模組,參閱下一節說明)

在一般情況下,開啟手機藍牙時,手機應該會找到並顯示探索到的設備位址,接著顯示它的名稱。為了方便檢視探索到的藍牙裝置位址,請先在手機上安裝藍牙掃描器軟體,請到Google商店或者Apple的App Store搜尋“Bluetooth Scanner”,便能找到相關App(筆者安裝的是這個Bluetooth Scanner)。

接著,請參考底下的接線,利用Arduino控制板的5V電源供電給藍牙模組:

藍牙模組的電源接線

線路接好之後,插上Arduino的USB線讓模組通電,接著開啟手機的藍牙,透過手機探索藍牙設備。

底下是在Android手機上,透過Bluetooth Scanner軟體搜尋到的HC-06模組畫面,從中可看到此模組的名稱、位址和無線信號強度:

Bluetooth Scanner APP操作畫面

請先把這個位址抄寫下來。

透過AT命令取得從端位址

如果「從端」也是HC-05模組,除可透過手機App取得它的位址之外,還能透過“AT+ADDR?”命令顯示位址(註:HC-06不具備這個指令;HC-06模組的AT命令,請參閱「HC-05與HC-06藍牙模組補充說明(三):使用Arduino設定AT命令」)。

請參考底下的接線,HC-05模組的Key腳位在開機時,必須處於「高」電位,模組才能進入AT命令狀態。

HC-05設置AT命令的接線

我們將透過Arduino的序列埠監控視窗設定藍牙模組的AT命令,請先將底下的程式上傳到Arduino。此程式碼的相關說明,請參閱這一篇文章

#include <SoftwareSerial.h>   // 引用程式庫

// 定義連接藍牙模組的序列埠
SoftwareSerial BT(8, 9); // 接收腳, 傳送腳
char val;  // 儲存接收資料的變數

void setup() {
  Serial.begin(9600);   // 與電腦序列埠連線
  Serial.println("BT is ready!");

  // 設定HC-05藍牙模組,AT命令模式的連線速率。
  BT.begin(38400);
}

void loop() {
  // 若收到「序列埠監控視窗」的資料,則送到藍牙模組
  if (Serial.available()) {
    val = Serial.read();
    BT.print(val);
  }

  // 若收到藍牙模組的資料,則送到「序列埠監控視窗」
  if (BT.available()) {
    val = BT.read();
    Serial.print(val);
  }
}

程式上傳完畢後,打開「序列埠監控視窗」,輸入AT命令看看,藍牙模組將回應OK

AT命令測試

如果沒有回應OK,代表此模組沒有進入AT命令模式,請確認模組的Key腳位有接高電位。

輸入AT+ADDR?命令,它將傳回模組的位址:

AT+ADDR?命令

藍牙裝置位址

透過手機App和AT指令查詢到的位址格式不同,兩種寫法都行,但採用AT命令設定位址時,必須使用下圖右邊的格式

補充說明:藍牙裝置位址(Bluetooth Device Address,簡稱BD_ADDR)由一連串16進位數字組成,總長48位元。裝置位址相當於藍牙裝置的序號,每個裝置都不同,它可細分成三個部份:

  • NAP:未定義位址部分(Non-significant Address Part),由IEEE分配給製造商的編碼。
  • UAP:較高位址部分(Upper Address Part),用於產生錯誤偵測碼以及藍牙裝置的跳頻順序。
  • LAP:較低位址部分(Lower Address Part),製造商設定的編碼。

藍牙裝置位址的格式

將藍牙模組設定成Master(主控端)並紀錄Slave(從端)的位址

請將要當作主控端的HC-05模組按照上一節的電路接好,Arduino控制板同樣執行上一節的程式。

HC-05模組在出貨時,通常都是「從端」模式。必須先用AT指令改成「主控端」,請開啟「序列埠監控視窗」,輸入AT+ROLE=1,藍牙將傳回OK,代表已經設定成主控端;日後若要改成「從端」,請輸入AT+ROLE=0。

AT+ROLE=1命令

接著輸入AT+BIND=命令,後面跟著要配對的從端設備位址,只要位址格式無誤,HC-05將回應OK,代表位址紀錄完成。

AT+BIND命令

以上設定都會永久保存在藍牙晶片,直到你重新設定。

一對一藍牙無線通訊實驗

本單元將實驗透過藍牙連結兩個Arduino控制板,其中一個板子充當「命令發送者」,發出‘1’或‘0’訊息,藉以控制另一個板子上的LED開關。

請將兩個Arduino都依照底下的接線組裝好:

藍牙序列埠模組與Arduiono的接線

在準備充當「命令發送者」的Arduino上傳底下的程式碼,不一定要是連接HC-05模組的那個Arduino,因為藍牙模組之間的配對連線,跟Arduino沒有關係。對Arduino來說,這兩個相連的藍牙模組,就相當於在Arduino之間用導線連接一樣。

#include <SoftwareSerial.h>   // 引用程式庫

// 定義連接藍牙模組的序列埠
SoftwareSerial BT(8, 9); // 接收腳, 傳送腳
char val;  // 儲存接收資料的變數

void setup() {
  Serial.begin(9600);   // 與電腦序列埠連線
  Serial.println("BT is ready!");

  // 藍牙透傳模式的預設連線速率。
  BT.begin(9600);
}

void loop() {
  // 若收到「序列埠監控視窗」的資料,則送到藍牙模組
  if (Serial.available()) {
    val = Serial.read();
    BT.print(val);
  }

  // 若收到藍牙模組的資料,則送到「序列埠監控視窗」
  if (BT.available()) {
    val = BT.read();
    Serial.print(val);
  }
}

接著在另一個,充當「接收命令者」的Arduino板上傳底下的程式碼:

#include <SoftwareSerial.h>   // 引用程式庫

// 定義連接藍牙模組的序列埠
SoftwareSerial BT(8, 9); // 接收腳, 傳送腳
char val;  // 儲存接收資料的變數
const byte LED_PIN = 13;  // 定義LED腳位

void setup() {
  // 設定HC-05藍牙模組,AT命令模式的連線速率。
  BT.begin(38400);
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  // 若收到藍牙模組的資料,則送到「序列埠監控視窗」
  if (BT.available()) {
    val = BT.read();
    if (val == '1') {
      digitalWrite(LED_PIN, HIGH);
      // 回應命令發送端,告知「已開燈」
      BT.println("LED ON");
    } else if (val == '0') {
      digitalWrite(LED_PIN, LOW);
      // 回應命令發送端,告知「已關燈」
      BT.println("LED OFF");
    }
  }
}

開啟兩個Arduino板的電源(先後順序不重要),觀察主控端藍牙的LED狀態燈,將先快速閃爍,與從端建立連線後,閃爍速度會變慢。

請先確認Arduino編輯器的序列埠連線是在「命令發送者」的板子:

選擇「命令發送者」的序列埠

接著開啟「序列監控視窗」,輸入‘1’和‘0’試試看:

控制LED

延伸閱讀

Posts created 468

267 thoughts on “藍牙模組補充說明(四):無線連結兩個Arduino控制板

  1. 老師您好:
    最近小的在做一個專案,想透過lcd讓使用者自己選擇要連的藍牙,能請問老師給小的一些建議嗎?謝謝

  2. 你好 我參考這邊文章,再編譯 接收命令者 程式碼時 出現錯誤,請問我是不是有什麼地方有錯誤
    Arduino:1.6.3 (Windows 8.1), 板子:”Arduino Uno”

    HC_RX.ino:17:1: error: stray ‘\’ in program

    HC_RX.ino:17:1: error: stray ‘\’ in program

    HC_RX.ino:17:1: error: stray ‘\’ in program

    HC_RX.ino:18:1: error: stray ‘\’ in program

    HC_RX.ino:18:1: error: stray ‘\’ in program

    HC_RX.ino:18:1: error: stray ‘\’ in program

    HC_RX.ino:19:1: error: stray ‘\’ in program

    HC_RX.ino:19:1: error: stray ‘\’ in program

    HC_RX.ino:19:1: error: stray ‘\’ in program

    HC_RX.ino:20:1: error: stray ‘\’ in program

    HC_RX.ino:20:1: error: stray ‘\’ in program

    HC_RX.ino:20:1: error: stray ‘\’ in program

    HC_RX.ino:21:1: error: stray ‘\’ in program

    HC_RX.ino:21:1: error: stray ‘\’ in program

    HC_RX.ino:21:1: error: stray ‘\’ in program

    HC_RX.ino:23:1: error: stray ‘\’ in program

    HC_RX.ino:23:1: error: stray ‘\’ in program

    HC_RX.ino:23:1: error: stray ‘\’ in program

    HC_RX.ino:24:1: error: stray ‘\’ in program

    HC_RX.ino:24:1: error: stray ‘\’ in program

    HC_RX.ino:24:1: error: stray ‘\’ in program

    HC_RX.ino:25:1: error: stray ‘\’ in program

    HC_RX.ino:25:1: error: stray ‘\’ in program

    HC_RX.ino:25:1: error: stray ‘\’ in program

    HC_RX.ino:26:1: error: stray ‘\’ in program

    HC_RX.ino:26:1: error: stray ‘\’ in program

    HC_RX.ino:26:1: error: stray ‘\’ in program

    HC_RX.ino:27:1: error: stray ‘\’ in program

    HC_RX.ino:27:1: error: stray ‘\’ in program

    HC_RX.ino:27:1: error: stray ‘\’ in program

    HC_RX.ino: In function ‘void loop()’:

    HC_RX.ino:17:2: error: ‘u3000’ was not declared in this scope

    HC_RX.ino:17:8: error: expected ‘;’ before ‘u3000’

    HC_RX.ino:18:8: error: expected ‘;’ before ‘u3000’

    HC_RX.ino:23:21: error: expected ‘}’ before ‘else’

    HC_RX.ino:24:2: error: ‘u3000’ was not declared in this scope

    HC_RX.ino:24:8: error: expected ‘;’ before ‘u3000’

    HC_RX.ino:25:8: error: expected ‘;’ before ‘u3000’

    HC_RX.ino:27:8: error: expected ‘;’ before ‘u3000’

    HC_RX.ino: At global scope:

    HC_RX.ino:29:1: error: expected declaration before ‘}’ token

    編譯時發生錯誤

    這份報告的詳情將會在
    “編譯時顯示詳細輸出資訊”
    在檔案 > 偏好設定裡啟用。

    1. hi loeb:

      想必是我在編寫文章時,不小心在程式碼中插入了「全形」空格。內文的程式碼已經更新,請重新貼入Arduino測試。

      thanks,
      jeffrey

  3. 謝謝你 編譯沒問題了,
    可否在請教一下 開啟終端機後 輸入 0 或 1都無反應,只有顯示 BT is ready!
    有發現程式碼中命令傳送者的BT.begin(9600); 而 命令接收者的BT.begin(38400);
    兩著不一樣 會有影響嗎?
    在請教一個小問題
    藍芽模組裡的at+uart?顯示出來的速率 要跟程式碼的BT.begin(38400); 設定一樣嗎?
    謝謝你的指導.

    1. 你好 我把命令接收者的BT.begin(38400); 改成BT.begin(9600);
      以及兩片HC-05也改成9600 並重新啟動,貌似就可以了,謝謝指導.

    2. 半年前做過類似作品(1個HC-05加上1個HC-06),當時也遇到同樣問題,自己也摸索了好久,最後才搞好,當時不以為意,沒想到半年後的今天,重作一次又花了好多時間,因此PO文說一說心得,加深自己的印象,免得下次又要搞半天:首先HC-05和HC-06的鮑率要設為一致(我用9600),發送端的HC-05AT命令是要用BT.begin(38400)沒錯,但在執行老師的程式時,必須將發送端的38400改為9600,這樣做就可以從接收端(也就是HC-06那一端)的序列埠監控視窗看到對應的LED ON,LED OFF了。但是改成9600後,就沒辦法下達AT指令了,如果想再下AT指令,必須將發送端的程式再改回BT.begin(38400),以上拙見。

  4. 老師你好:
    我們想用兩個(Arduino+NRF24L01)
    一個當接收一個當發送
    請問該怎麼讀取他們之間的訊號強度
    我們的程式碼是參考上面的網站

    1. 根據NFR24系列晶片的原廠技術文件第25頁的”6.4
      Received Power Detector measurements”單元,”nRF24L01+”這個型號具備一個Received Power Detector(接收功率偵測器,簡稱RPD)暫存器,但是它只佔一個位元,只能判斷接收功率是否大於或小於-64 dBm。

      因此nRF24L01通訊模組可能不適合用於妳的專題。

      thanks,
      jeffrey

  5. 老師你好 我現在再做arduino紅外線的專題
    我想要把arduino感測到的序列阜值經過藍芽傳到手機上顯示
    請問我該怎麼做

    1. 專題製作就是讓你把過去所學的,透過一個作品展現出來。以Android程式為例,假設你學的是Java語言,你可以找到Android的Java藍牙相關程式庫;Arduino控制板的程式範例也很多,建議你先從讀取感測器資料,並透過序列埠傳送下手,相關的細節可以和你的專題指導老師討論。

      good luck!
      jeffrey

  6. 老師您好
    我想問一下,我的藍芽(HC-05)跟arduino 都沒有問題
    然後再跟手機跟藍芽連結的時候,可以配對,但是無法連結 ,請問該如何解決

  7. Hi, cubie
    Your code “AT+ROLL=1 ” is wrong.
    It should be “AT+ROLE=1”. BTW, thanks for the introduction to BT connection with 2 Arduino, your article saves me a lots of time for this.

    Best,
    AK

  8. 老師您好! 我使用HC-05藍芽模組, 用手機app發送 “a”字元到arduino的藍芽接收, 但是序列監控讀出來都是”120″和”248” 兩個數值(有故意不轉成char來檢查 不然會是亂碼) ,其他的英文字母或數字也都相同,讀到的都是多個數字組, 請問一下是哪裡出錯了呢? 謝謝!!!

    1. hi yonoodle:

      藍牙序列通訊板只是負責轉發微控制器和其他裝置(如:手機)的訊號,如果Arduino收到非預期的字元,問題應該是出在App上,請確認你的App程式傳出ASCII字元。

      thanks,
      jeffrey

  9. 老師您好,若想購買《超圖解》中的HC-05晶片,請問該如何選擇?
    網路上發現若是”主從一體”的價格,比單純”主端”或”從端”的價格低上許多,不知性質差在何處? 謝謝。

    1. hi dun:

      HC-05模組的基本差異是在出貨時,事先幫你設定好從端或主控端,硬體和韌體都是一樣的…建議直接購買「主從一體」型即可。

      thanks,
      jeffrey

  10. 老師您好

    照著”使用手機的「藍牙掃描器」App取得藍牙裝置的位址”的接法後,發現手機掃不到此HC-05的資訊耶,請問我是哪裡出錯了呢? 謝謝老師

    1. hi dun:

      請問你有事先在Android系統的「設定」裡的「藍牙」中,將手機與HC-05配對嗎?因為該程式讀取的是手機的已配對藍牙裝置資料。

      thanks,
      jeffrey

  11. 老師您好
    我想請問如果我用HC05 跟BTbee HC06的
    這2個是否能建立無線連接

  12. 老師您好!
    如果我有多個感測器(4個左右) ,那我可以用兩個藍芽+兩個arduino把感測器分成2個2個,並把抓到的數值顯示在同一台手機的app上嗎?

    因為如果一個藍芽模組配多個感測器,掉資料的機率很大,導致我可能抓不到正確的數值,最近正在想辦法解決這問題。

    請問老師有什麼好的建議嗎?

  13. 謝謝老師!
    再問一個問題
    照著以上步驟
    到序列監控視窗,輸入‘1’和‘0’時
    一直沒有出現LED ON或OFF
    是可能哪個步驟有出錯嗎?
    謝謝!

  14. 老師您好,

    前半段照著老師的步驟都沒問題,
    但到了最後的序列監控視窗,
    輸入‘1’和‘0’時,
    一直沒有出現LED ON或OFF,
    我也重複認過配對的位址沒有錯誤,
    想請問是不是還有可能是哪個步驟出了問題?

    謝謝!

    1. hi michael:

      請分開測試兩組程式,例如,接收端部份,請改用有線序列連接,也就是移除藍牙模組,直接把Arduino和電腦相連,透過序列埠監控視窗測試,看看是哪個部份有問題。

      thanks,
      jeffrey

  15. 老師你好!
    最近手邊有4顆hc-05藍芽 所以我配成了兩組自動配對的藍芽
    上面的測試都沒有問題
    但我發現配成主端的hc-05不管是哪一個都會在通電時會自己找另外兩個從端自己配對,和我預期的不太一樣,預期上我以為它們只會配對我設定的從端位址,兩個主端我分別都用(AT+BIND=從端位址)設定了一組從端資料進去,它也有回應OK
    但結果和我想得不太一樣,是文章中哪個部份我理解錯誤了嗎?還是”AT+BIND=”設定的東西和我想的不一樣?
    煩請老師替我解答

    1. hi coobe:

      有個叫做”CMODE”的AT指令,能夠設定是否連接任何藍牙從端,或者只連接到已配對的從端:

      【已修正錯誤】
      AT+CMODE=0 #代表只與已配對的從端相連
      AT+CMODE=1 #代表能與任何從端相連

      thanks,
      jeffrey

  16. 老師你好!
    經過測試沒有問題了 不過和老師解答的內容剛好反過來了這裡可能要和你說一下,查了一下網路上的AT指令集,AT+CMODE=0是和綁定的從端連接,AT+CMODE=1是和隨意從端連接
    另外我想請問HC-05使用”AT+BIND=”只能綁定一組藍芽麼? 我試過複數藍芽位址但用”AT+BIND?”查詢時始終只會顯示一組藍芽位址
    謝謝!

    1. 欸~仔細看了AT指令說明書第9頁,我上個留言確實寫反了,感謝糾正!

      AT+BIND只能綁定一組藍牙位址(請參閱說明書第10頁)。

      thanks,
      jeffrey

  17. 老師您好,

    前半段照著老師的步驟都沒問題,
    但到了最後的序列監控視窗,
    輸入‘1’和‘0’時,
    一直沒有出現LED ON或OFF,後用兩台電腦將ho5 fo6都改為38400
    分別接 uno 和 nano上,兩台都灌入您的控端程式,分別從兩台電腦上序列埠監控及輸入資料,結果發現不論從哪邊輸入,另一邊都出現亂碼,(分別都有進入AT 模式 指令都 OK),
    想請問是不是還有可能是哪個步驟出了問題?

    1. HC-06的預設連線速率是9600bps,你有試過直接用有線方式測試嗎?

      thanks,
      jeffrey

  18. 老師您好,
    如果我想在arduino裹知道藍牙模組有沒有裝置連接
    在code中應該如何寫??
    何否用以下模式寫??
    if (deviceconnected ==1){ digitalWrite(ledpin,HIGH);}
    else {…….}
    謝謝老師

  19. 老師您好,我依照上面AT設定好at+bind和at+role,
    但兩塊HC-05一直無法連線(快速閃燈)
    請問是甚麼原因?

    謝謝

    1. hi alvin:

      請確認藍牙的Key腳沒有接高電位、從端的位址輸入正確,嘗試在主控端輸入底下的AT命令,再測試看看:

      AT+CMODE=0 #代表只與已配對的從端相連

      thanks,
      jeffrey

  20. 老師您好,
    上述的程式本人已經成功,
    接下來我想利用單顆按鈕來控制LED的亮滅,
    想利用傳值的方式,
    卻一直無法成功
    老師可給個建議?
    我主端程式後半部是
    void loop() {
    buttonstate=digitalRead(buttonpin);
    // 若收到「序列埠監控視窗」的資料,則送到藍牙模組
    if (buttonstate == HIGH) {
    val = 1;
    BT.print(val);
    }
    else{
    val = 0;
    BT.print(val);
    }

    // 若收到藍牙模組的資料,則送到「序列埠監控視窗」
    if (BT.available()) {
    val = BT.read();
    }
    }

    1. hi rasico:

      在接收端加入digitalWrite()敘述即可,例如:

      if (BT.available()) {
      val = BT.read();
      if (val == ‘1’) {
      digitalWrite(LED_PIN, HIGH);
      }
      }

      thanks,
      jeffrey

  21. 老師您好,
    可請問一下-48的用意為何?
    還有digitalWrite(val)後是不是要加個high?

    1. -48是為了把字元轉成數字(相關說明請參閱10-10頁「透過序列埠調整燈光亮度」單元),請忽略之前的寫法,上個留言的程式敘述已更新,LED_PIN常數代表預設的LED連接腳位。

      thanks,
      jeffrey

  22. 老師您好,
    關於您的主控端程式
    void loop() {
    // 若收到「序列埠監控視窗」的資料,則送到藍牙模組
    if (Serial.available()) {
    val = Serial.read();
    BT.print(val);
    }

    // 若收到藍牙模組的資料,則送到「序列埠監控視窗」
    if (BT.available()) {
    val = BT.read();
    Serial.print(val);
    }
    }
    我發現是兩邊資料互相接送
    那我上兩個留言的主控端程式
    是否不能這樣打呢
    目前情況是led亮的有點詭異
    不符合情況

    1. 如果你只需要由一方控制另一方,那麼序列接收程式就不必送回訊息,例如:

      if (BT.available()) {
        val = BT.read();
        if (val == '1') {
          digitalWrite(LED_PIN, HIGH);
        } else {
          digitalWrite(LED_PIN, LOW);
        }
      }
      

      我不了解「led亮的有點詭異」的意思。

      thanks,
      jeffrey

    2. 謝謝老師,
      我成功執行利用利用按鈕控制LED的亮滅了,
      最後是在主控端的程式,
      加上上拉電阻digitalWrite(2, HIGH);
      可以讓LED穩定工作了

    3. 感謝告知!所以原先的問題是出在開關?因為直接把開關串接在Arduino,然後接地,而非透過外接的上拉電阻…

      thanks,
      jeffrey

  23. 您好,請問有什麼方法可以讓藍芽模組傳輸兩組數值

    並且接收端也接收兩組數值呢?

    因為有兩個變數要傳輸。

    1. 你可以自訂傳送的訊息格式。

      假設我要透過序列埠傳送兩個馬達控制訊號,左馬達我叫它”L”,右馬達用”R”代表。這個序列資料:

      “L50\nR128\n”

      代表左馬達輸出50、右馬達輸出128。

      接收端程式用String物件解析比較方便,請參閱書本17-22頁的調光器範例(程式說明在17-24頁)。

      thanks,
      jeffrey

  24. 您好,老师。 我想请问下, 我有1个代码是用arduino mega上面的1个电位器通过串口通信来控制舵机控制板上的1个舵机。 我有两个HC-05 的蓝牙模块, 分别用AT指令设置成了主端和从端了,并且都成功配对连接上了,每个蓝牙都分别连接在一个arduino mega上 我想问下如何把以下的代码分别写到两个arduino mega 里,让两个arduino能够成功的连接在一起。

    #include //包含舵机库
    int pos = 0; // 设定舵机的转动位置为变量

    void setup()
    {
    Serial.begin(115200); //舵机控制板的速率
    }
    void loop()
    {
    int value = analogRead(A0); //读取A0口输入的模拟值
    pos = map(value,0,1023,0,180); //将读到的模拟值0~1023映射为0°~180°

    Serial.println(String(“#10P”) + (pos) + 0);
    delay(100); //延时一段时间让舵机转动到对应位置
    }

    1. hi,

      Arduino Mega 2560控制板包含额外的Serial对象:

      • Serial1:19 (RX) 和 18 (TX)
      • Serial2:17 (RX) 和 16 (TX)
      • Serial3:15 (RX) 和 14 (TX)

      假设你的蓝牙模块接在Serial1,修改上文的代码,便可从Serial1收发蓝牙资料:

      char val;  // 存储接收资料的变量
       
      void setup() {
        Serial.begin(9600);   // 与电脑序列埠连线
        Serial.println("BT is ready!");
       
        // 蓝牙透传模式的预设连线速率。
        Serial1.begin(9600);
      }
       
      void loop() {
        // 若收到「序列埠监控窗口」的资料,则送到蓝牙模块
        if (Serial.available()) {
          val = Serial.read();
          Serial1.print(val);
        }
       
        // 若收到蓝牙模块的资料,则送到「序列埠监控窗口」
        if (Serial1.available()) {
          val = Serial1.read();
          Serial.print(val);
        }
      }
      

      thanks,
      jeffrey

  25. 非常感谢您的回复, 只是我还是不太清楚 如何把我的代码分别截成相应的两断然后放到两个arduino mega里面。 具体说的话就是 int value = analogRead(A0); 这句是作为主端arduino mega 上的电位器的输入值。 pos = map(value,0,1023,0,180); 这句是相互对应输入和输出的值, 最后这句Serial.println(String(“#10P”) + (pos) + 0); 则是做为另一个从端的arduino mega 上的舵机输出值。 能分别帮我改成一个主端命令, 和一个从端接受蓝牙的代码吗。 非常感谢。

    1. OK, 這個程序需要執行下列幾個事項:

      傳送端:通過Serial1.print()送出旋轉角度值。

      接收端:
      1. 通過Serial.availible()檢查序列埠是否有數據
      2. 通過Serial1.read()讀取轉動值
      2. 把轉動值(字符串)轉換成數字
      3. 調用Servo對象的write()方法轉動角度。

      代碼請自己完成。

      thanks,
      jeffrey

  26. 老師,您好:

    拜讀您的大作,受益良多。
    透過您這篇文章,成功連結兩個arduino 的藍芽模組;
    連結android手機及arduino 的藍芽模組也沒有問題。
    可是當兩個arduino 的藍芽模組連結後,
    卻無法使用android手機去讀取主端或從端的arduino 的藍芽模組。

    請問老師是否有解決方案?

    謝謝!

    1. hi 阿漂:

      設定成主控端的藍牙板可能連不上Android手機,但從端應該沒問題,請開啟「設定→藍牙」,重新搜尋、配對看看。

      thanks,
      jeffrey

    1. hi 小郭:

      你可以嘗試在App Inventor的編輯畫面拖放多個Bluetooth Server元件,分別設置連線程式看看,我沒有實際試過。

      thanks,
      jeffrey

  27. 老師,您好:

    從端是已可以配對,此時由從端將主機接收的資料傳送出去,讓手機也可以收到主機端傳來的資料,
    我將從端資料透過同一COM 同時傳送給主機端跟手機,
    但是只要主機端傳送資料給從端時,
    從端傳送的資料會被主機端鎖定,無法同時傳送資料給手機端;
    若手機端讀取從端傳送資料時,主機端無法同時傳送資料給從端。

    請問資料傳送的方向 可以是 主機->從端->手機 ?
    我試過很多次始終沒有辨法達成?

    不吝賜教! 謝謝!

    SoftwareSerial BT(10, 11); // 接收腳, 傳送腳
    char val; // 儲存接收資料的變數

    void setup() {
    pinMode(RelayPin, OUTPUT); //繼電器設定
    digitalWrite(RelayPin, HIGH);
    Serial.begin(9600);
    BT.begin(38400);
    }

    void loop()
    {

    if (BT.available()) {
    val=BT.read();
    if (val==’d’) {
    digitalWrite(RelayPin, LOW);
    return;
    }
    BT.write(val); //讓手機可以收到
    }
    }

    1. 藍牙從端一次只能與一個主控端相連,就像藍牙滑鼠不能同時連接兩台PC。

      所以你只能朝這些方向進行:
      1. 把Android當成從端,連接到HC-05主控端,但是,我不確定HC-05的韌體是否有支援連接多個從端的功能。
      2. 把Android當成主控端,連接其他HC-05藍牙裝置,但是這會變成以Android主導,若Android中斷連線,其他藍牙也就失去連線。
      3. 理論上,兩個藍牙主控端可相互連線,但是必須韌體支援”scatternet”通訊協定,所以這個方法不可行。

      thanks,
      jeffrey

  28. 老師你好:
    手機app 連結HC-05 之前使用皆正常但卻突然為何出現ERROR 516 Unable to write Broken pipe 是何原因 謝謝
    哪種藍芽最穩定

    1. hi 小郭:

      Android系統的”Unable to write Broken pipe”錯誤訊息,代表連結目標的藍牙裝置突然中斷連線,程式無法順利送達訊息,通常是因為藍牙模組隔太久時間沒有和App聯繫導致。

      請試著在App Inventor中加入底下的錯誤捕捉程式區塊,它應該能在發生516編號錯誤時,中斷藍牙連線。這是中文版畫面:

      處理藍牙連線中斷的程式區塊

      這是英文版:

      bluetooth write broken pipe handle code

      thanks,
      jeffrey

  29. 老師你好:

    可否請老師介紹何種適合arduino控制12v/24v 輸出電流為3a之馬達正逆轉 ic 具 pwm功能 謝謝

  30. 老師你好: 不好意思再次打擾, 問題是app 已連結藍芽 但卻忘了登出待下次使用app時卻無法連線因 藍芽已處於連線狀態 所以想請教老師 app invertor 2是否有解決之法 謝謝

    1. 你可以在關閉App時,透過Disconnect指令中斷藍牙連線。這篇文章有一個按下Back鍵,詢問用戶是否關閉App的範例。你可以在其中的”AfterChoosing”區塊,執行藍牙的Disconnect。

      thanks,
      jeffrey

  31. 老師你好:
    我用藍芽HC-05模組接86-duino educake
    想看看能否自傳自收寫了下面的程式
    void setup() {
    // put your setup code here, to run once:
    Serial.begin(9600);
    Serial.println(“READY”);
    Serial1.begin(9600);
    }

    void loop() {
    // put your main code here, to run repeatedly:

    Serial.write(2);
    Serial1.write(3);

    Serial.println(Serial1.read());
    Serial.println(Serial.read());
    delay(100);
    }

    結果打開序列監控視窗顯示的是:
    -1
    -1
    -1
    -1
    為什麼會是-1以及有個-1前面會多個空格呢?

    1. Serial.write() 送出的是ASCII值,所以序列埠監控視窗接收到的是控制字元,-1代表序列埠緩衝記憶體裡面是空的,尚未收到資料。

      thanks,
      jeffrey

  32. 老師你好:
    我想請問一下如果要在兩個模組間傳送一組sensor感應到的數據
    程式碼要怎麼改
    才能傳送指定的數據

    1. 藍牙傳送序列訊號,跟使用USB序列埠傳送訊號的程式是一樣的,你可以直接用10-10頁「透過序列埠調整燈光亮度」的例子來修改,只是把「燈光亮度」訊息改成「感測訊號值」。

      thanks,
      jeffrey

  33. 老師你好:
    不好意思想請問 app 三段指令意思
    (1) if callbluetoothclient1.BytesAvailableToRecevive>0 是何意
    (2) then Setglobaltext to callbluetoothclient1.ReceviveText NumberOfBytes 1 其中數字1 是何意
    (3) if getglobaltext <0 是何意
    謝謝

    1. 如果把程式設計比喻成拼圖遊戲的話,你這個問題就好像從一大盒拼圖裡面取出幾片丟給我,要我猜猜這是什麼主題的拼圖一樣…

      幸好,程式語言的指令,以及程式設計師在寫程式的時候都會遵循一定的命名規則,而且它們都是有意義的英文單字組成。就像callbluetoothclient1,就是call bluetooth client 1,其後的指令也就是bytes available to receive,你查一下英文字典就能得知這些單字的意思了。

      have fun!
      jeffrey

  34. 請問老師,如果要讓手機app傳送資料>>主機>>從端
    要用app inventer的Bluetooth sever還是Bluetooth client
    我想做一個手機連接一個HC-05主機端,傳送資料分別控制2個從端

  35. 老師您好,我的專案有分為”傳送端”,”控制端”分別使用兩台86duino和兩片HC-05的藍芽模組,使用可變電阻的感測器
    我問題是:我成功了很多次,但是等下一次再進行測試的時候,就會跟上一次的結果不一樣,不是亂抖動,就是會很久才有反應.
    或是一開始很正常,測試5分鐘後就不太正常了變的反應很慢或亂抖動,測試正常的時候偶爾也是會抖一下.
    我不知道是不是我一直讓它一直傳送數值而讓藍芽塞車?我希望可以讓我的機械手穩定一點,不知道是我的寫法不好還是哪裡出錯了?
    我試過改變了很多組的delay參數組合,每次的結果也都很不同,有時候這組超正常以為成功,再隔一天測試又不行了.希望可以有人指導我.
    以下是我最基礎的程式碼
    傳送端:

    //可變電阻腳位的命名指定
    int r1=A0;
    int r2=A1;
    int r3=A2;
    int r4=A3;
    int r5=A4;
    //宣告儲存類比數值
    int val,val2,val3,val4,val5;
    //宣告儲存數值的陣列
    long Data[10]={};
    void setup() {
    //與電腦序列埠連線的連線速率
    Serial.begin(9600);
    // 藍牙透傳模式的預設連線速率。
    Serial1.begin(38400);
    }
    void loop() {
    //指定類比數值儲存空間
    val=analogRead(r1);
    val2=analogRead(r2);
    val3=analogRead(r3);
    val4=analogRead(r4);
    val5=analogRead(r5);
    //設定範圍
    val=map(val,0,1023,20,150);
    val2=map(val2,0,1023,20,150);
    val3=map(val3,0,1023,20,150);
    val4=map(val4,0,1023,20,150);
    val5=map(val5,0,1023,20,150);
    //將數值給定陣列
    Data[1]='a';
    Data[2]=val;
    Data[3]=val2;
    Data[4]=val3;
    Data[5]=val4;
    Data[6]=val5;
    //藍芽傳送陣列數值
    if(val<145 || val2<145 || val3<145 || val4<145 || val5<145)
    {
    for(int i=0;i<7;i++)
    {
    delay(1);
    Serial1.write(Data[i]);
    }
    }
    //監控視窗顯現數值
    for( int x = 1; x<7; x++)
    {
    Serial.println(Data[x]);
    }
    delay(10);
    }// end of loop
    

    接收端:

    //標頭檔
    #include 
    //建立 Servo物件,控制伺服馬達
    Servo myservo;
    Servo myservo2;
    Servo myservo3;
    Servo myservo4;
    Servo myservo5;
    //儲存數值陣列
    long Data[10]={};
    void setup() {
    // put your setup code here, to run once:
    //伺服馬達腳位設定
    myservo.attach(3);
    myservo2.attach(5);
    myservo3.attach(6);
    myservo4.attach(9);
    myservo5.attach(10);
    //與電腦序列埠連線的連線速率
    Serial.begin(9600);
    // 藍牙透傳模式的預設連線速率。
    Serial1.begin(38400);
    }
    void loop() {
    // put your main code here, to run repeatedly:
    //藍芽接收數值
    if(Serial1.available())
    {
    byte x=Serial1.read();
    if(x=='a')
    {
    for(int i=2;i<7;i++)
    {
    delay(1);
    Data[i]=Serial1.read();
    }
    //馬達轉動數值
    myservo.write(Data[2]);
    myservo2.write(Data[3]);
    myservo3.write(Data[4]);
    myservo4.write(Data[5]);
    myservo5.write(Data[6]);
    }
    }
    //監控視窗顯示數值
    for(int i=1 ;i<7 ; i++)
    {
    Serial.println(Data[i]);
    }
    delay(10);
    }//end of loop
    
    1. hi 小郭:

      你可以先著手修改兩個部份:
      1. 傳送多筆資料值,請將所有資料都組成一個字串,同時傳送。例如,原本的程式逐一傳送Data[0], Data[1], Data[2],…

      請把這些資料組成如下的字串,每筆資料中間用逗號或其它字元分隔,最後可加上’\n’結尾:

      11,22,33,…\n

      接收端程式再透過String物件,即可分割、取出個別的資料,相關範例可參閱17-21頁的「動手做17-3」。

      2. 伺服馬達的轉動延遲時間,應該要依照你採用的規格來調整,例如,普通的9g微型伺服馬達旋轉60度約需時0.12秒,轉動180度就需要0.36秒。你的延遲時間不應該小於這個數值,否則馬達可能無法轉到定位。

      have fun!
      jeffrey

  36. 請問hc-06的藍芽模組可以接到linkit one嗎?
    那它要怎麼和連接hc-05模組的arduino互通?

    1. hi joanne:

      凡是具有RxD和TxD序列傳輸介面的微電腦板,都能連接藍牙序列模組,包括linkit one在內。
      至於和其他控制板互通,那是程式的問題,Arduino板就用Arduino的C程式來寫,至於linkit one,應該是透過Node.js,抱歉我沒用過linkit one。

      thanks,
      jeffrey

  37. 我們找到了下面的程式,並且燒製linkit one的hc-06,但它一直無法與arduino的hc-05相連?

    char val; // 儲存接收資料的變數

    void setup() {
    Serial.begin(9600); // 與電腦序列埠連線
    Serial.println(“BT is ready!”);

    // 設定藍牙模組的連線速率
    // 如果是HC-05,請改成38400
    Serial1.begin(9600); // 與電腦序列埠連線
    }

    void loop() {
    // 若收到「序列埠監控視窗」的資料,則送到藍牙模組
    if (Serial.available()) {
    val = Serial.read();
    Serial1.print(val);
    }

    // 若收到藍牙模組的資料,則送到「序列埠監控視窗」
    if (Serial1.available()) {
    val = Serial1.read();
    Serial.print(val);
    }
    }

    1. 從你上個留言看來,我覺得你的實驗順序搞錯了。你應該先了解並搞定控制板的序列通訊程式,並透過電腦或手機的藍牙連線測試,兩個控制板的序列連線分別測試成功之後,再嘗試用藍牙連接兩個控制板。

      兩個藍牙序列通訊板之間的配對連線,透過AT命令操作,跟控制板上的程式沒有關聯。

      have fun!
      jeffrey

  38. 老師您好,若想要使用多台Arduino + HC-05,
    在主從模式變換中,互相偵測對方的RSSI值,
    並以無線方式,將收到的資料傳給筆電,
    在筆電中,使用類似Putty等軟體,掃描com port,
    但問題是螢幕顯示出相同的RSSI值,並不斷重複
    表示sensor只偵測一次RSSI,請問是哪裡出錯了呢?
    還是需要一台sensor先以有線方式連接筆電,其他sensor再將資料轉傳呢?

    SoftwareSerial BTserial(10, 11);

    void loop()
    {
    當BTserial.available()時 //讀取BT module中的資料
    char c = BTserial.read();
    String += c; //將讀到的資料寫進String中

    BTserial.print(“AT+ROLE=1\r\n”);
    BTserial.print(“AT+INQ\r\n”);
    BTserial.print(String); //印出從BT module來的資料
    BTserial.print(“AT+ROLE=0\r\n”);
    }

  39. 之前用兩個arduino板子已成功將兩個藍芽模組配對成功,到linkit one上還要再配對一次?

    1. 如同我上一則回應,「兩個藍牙序列通訊板之間的配對連線,透過AT命令操作,跟控制板上的程式沒有關聯。」

      既然你已經在Arduino上連線測試成功,那就代表藍牙也已配對連接成功,不需要重新配對,跟微電腦控制板沒有關係。所以問題出在你的linkit one程式…你有事先單獨測試linkit one的序列通訊程式是否如預期般運作嗎?

      have fun!
      jeffrey

  40. 主端傳送資料時,在serial monitor上顯示正常,但在從端的serial monitor上卻是顯示亂碼,請問這樣實際上接收到的值會是正確的嗎?要怎樣才能讓從端的serial monitor顯示正常的值?

    1. 接收端的「亂碼」應該是字元的ASCII編碼,假設接收字元的變數是val,執行char(val),將能把資料轉換成字元。

      thanks,
      jeffrey

  41. 老師您好,我最近遇到兩個HC-05配對通信的問題。兩個HC-05一主一從,波率同都是9600,配對成功,但主控端發送的數據,從控端一直接收不到。請問老師,這可能是什麽原因?

  42. 您好
    想請問我想用 iphone 4S 藍牙4.0 連接ARDUINO UNO 作一些簡單的遙控開開關關的動作
    應該要選擇甚麼樣的藍牙模組(BLE or HC-05)來實驗?
    您書上用的是HC-05,用在安卓手機上自然是沒問題
    但爬過GOOGLE後
    http://thinkingiot.blogspot.tw/2015/11/bluetooth-mfi.html
    似乎 IOS 封鎖了藍牙上的SPP,若真如上面連接所言
    照您書上的藍牙範例要iphone以SPP方式透過HC-05豈不是無法連上arduino ??
    或是我有哪些地方誤解?

    苦惱中

    1. hi rainey:

      我在 Cordova (PhoneGap) 上採用的藍牙外掛是Bluetooth Serial Plugin for PhoneGap,在該專案網頁有提到Android和Windows手機採用的是普通的藍牙模組(也就是HC-05或HC-06等藍牙序列模組),iOS則需要使用藍牙低功耗(Bluetooth Low Energy, BLE),也就是藍牙4.0模組,提供你參考。

      thanks,
      jeffrey

  43. 老師您好:
    我現在有兩個HC-05,已經設定好主從端了
    也綁定好位址了
    因為我想利用感測器透過ARDUINO傳送資料(無線)到電腦
    所以我想問如果主端的HC-05有辦法透過行動電源供電,然後連接我的ARDUINO跟感測器
    將資料傳到從端的HC-05
    然後透過ACCESSPORT把資料讀出
    想問一下藍芽模組有辦法這樣嗎?

    1. hi lee:

      可以,藍牙模組透過SoftwareSerial連結Arduino板,AccessPort透過Arduino預設的序列埠相連即可,程式範例如同《超圖解Arduino互動設計入門》14-10頁所示。

      thanks,
      jeffrey

  44. 請問如果我的arduino板子要擴接藍芽模組跟RFID模組….,多模組的話可以這樣做?

    1. hi condy:

      可以,因為你提到的模組都是用序列方式連接,只要用SoftwareSerial個別定義接腳即可。

      thanks,
      jeffrey

  45. 請問 我設計好 app invertor 2 的APP, 可以和 3個 HC-05 都配對成功,個別連線控制也可以,現在的問題是要 同時控制3個的話,也就是群控,可以做的到嗎? APP要怎麼選拼塊來改? 謝謝!

    1. hi cliff:

      如果每次切換不同的藍牙模組都要先切斷前一個模組的連線,那恐怕就不行了,否則,你可以嘗試用迴圈處理。

      thanks,
      jeffrey

  46. 老師您好,我們在做專題時遇到了問題,要使用2個HC06或HC05分別傳送不同訊息到android手機端,目前寫的是一對一程式是可以通訊的,但2個HC06或HC05可以利用上面的方式傳輸嗎,還有能分別出我哪一端傳送甚麼資料到android端嗎?

    1. hi shawn:

      你可以在Android上透過藍牙裝置的名稱和UUID識別碼來分辨不同的藍牙周邊。

      thanks,
      jeffrey

  47. 老師您好,我是SHAWN,這樣還需要用到HC06連接HC05這個嗎,還是我可以分別HC06接手機跟HC05接手機。

    我android已經有寫UUID:00001101-0000-1000-8000-00805F9B34FB,HC06跟HC05應該都是這個UUID,這樣還能夠分辨不同的嗎,還是一個是用UUID一個是用藍芽裝置名稱這樣子的寫法

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top