Ref : http://gsyan888.blogspot.tw/2014/03/arduino-hc-05.html
Ref : http://gsyan888.blogspot.tw/2015/03/arduino-hc-05-master-and-slave.html
Ref :
這篇文章示範如何使用Python透過Bluetooth跟Arduino連結.並使用Python建立出來的圖形介面來控制Arduino上LED 的ON/OFF.
底下實驗概念接線圖
Python 因為是跨平台的程式語言所以也執行在windows或是Linux,底下範例是直接使用一般電腦及windows 10去做示範.Python原始程式碼只要稍微修改一下也可以改成使用在安裝Linux的系統上,如樹梅派.
底下是之前USB2Serial範例的介紹連結:
http://arbu00.blogspot.tw/2016/07/pythonarduinoled.html
底下所建立出來的圖形介面如下圖所示,
當按下按鈕<check>去跟Arduino確認是否已經連線成功.
按下按鈕<ButtonA>則會傳送字元'a' 到arduino當指令去啟動LED跑馬燈1
按下按鈕<ButtonB>則會傳送字元'b' 到arduino當指令去啟動LED跑馬燈2
按下按鈕<ButtonC>則會傳送字元'c' 到arduino當指令去啟動LED閃燈的動作.
按下按鈕<Exit>則會傳送'ESC' 鍵字元到arduino當指令去結束視窗跟所有動作.
當成是執行時必須先按下<Check>Button 再reset Arduino才能順執行以確保連線成功.
video 連結
https://www.youtube.com/watch?v=M8hEMtvtui8
# -*- coding:utf-8 -*-
from
time
import
sleep
import
serial
import
tkinter
Ready_flag
=
0
##==============================================================================
ser
=
serial.Serial(
"COM9"
,
9600
, timeout
=
2
)
# Establish the connection on a specific port
##==============================================================================
##===============For Linux=========================================================
#ser =serial.Serial("/dev/ttyACM0", baudrate=9600, timeout=2) # Establish the connection on a specific port
##==============================================================================
def
SerialWrite(command):
ser.write(command)
rv
=
ser.readline()
#print (rv) # Read the newest output from the Arduino
print
(rv.decode(
"utf-8"
))
sleep(
1
)
# Delay for one tenth of a second
ser.flushInput()
##===When button A be pressed then Send 'a' to arduino============
def
SendCmdA():
global
Ready_flag
if
Ready_flag
=
=
1
:
Arduino_cmd
=
'a'
cmd
=
Arduino_cmd.encode(
"utf-8"
)
SerialWrite(cmd)
#Show to LabelA----------------
LabelA.config(text
=
"Send the command 'a' to Arduino"
)
LabelA.update_idletasks()
Tkwindow.update()
else
:
LabelA.config(fg
=
'red'
,)
LabelA.config(text
=
"Arduino not ready!Please check it again"
)
LabelA.update_idletasks()
Tkwindow.update()
##===When button A be pressed then Send 'a' to arduino============
def
SendCmdB():
global
Ready_flag
if
Ready_flag
=
=
1
:
Arduino_cmd
=
'b'
cmd
=
Arduino_cmd.encode(
"utf-8"
)
SerialWrite(cmd)
#Show to LabelA----------------
LabelA.config(text
=
"Send the command 'b' to Arduino"
)
LabelA.update_idletasks()
Tkwindow.update()
else
:
LabelA.config(fg
=
'red'
,)
LabelA.config(text
=
"Arduino not ready!Please check it again"
)
LabelA.update_idletasks()
Tkwindow.update()
##===When button A be pressed then Send 'a' to arduino============
def
SendCmdC():
global
Ready_flag
if
Ready_flag
=
=
1
:
Arduino_cmd
=
'c'
cmd
=
Arduino_cmd.encode(
"utf-8"
)
SerialWrite(cmd)
#Show to LabelA----------------
LabelA.config(text
=
"Send the command 'c' to Arduino"
)
LabelA.update_idletasks()
Tkwindow.update()
else
:
LabelA.config(fg
=
'red'
,)
LabelA.config(text
=
"Arduino not ready!Please check it again"
)
LabelA.update_idletasks()
Tkwindow.update()
##==Serial connect and Get arduino Ready================
def
Serial_Connect():
global
Ready_flag
for
i
in
range
(
1
,
10
):
print
(
"Checking..."
)
#Show to LabelA----------------
Str_index
=
""
str_check
=
"th Checking...\n"
Str_index
=
str
(i)
Label_msg
=
"The "
+
Str_index
+
str_check
LabelA.config(fg
=
'green'
,)
LabelA.config(text
=
Label_msg)
LabelA.update_idletasks()
buttonStart.config(state
=
"disabled"
)
Tkwindow.update()
rv
=
ser.readline()
#Debug print (rv) # Read the newest output from the Arduino
print
(rv.decode(
"utf-8"
))
ser.flushInput()
sleep(
0.5
)
# Delay
Str_Message
=
rv.decode(
"utf-8"
)
#Debug print(Str[0:5])
if
Str_Message[
0
:
5
]
=
=
"Ready"
:
Ready_flag
=
1
print
(
"Get Arduino Ready !"
)
#Show to LabelA----------------
LabelA.config(text
=
"Get Arduino connecting Ready !"
)
LabelA.update_idletasks()
Tkwindow.update()
break
elif
i
=
=
9
:
Ready_flag
=
0
LabelA.config(fg
=
'red'
,)
LabelA.config(text
=
"Can't connnect to Arduino successfully!\
\nPlease press
'check'
button then reset Arduino to
try
again!")
buttonStart.config(state
=
"active"
)
LabelA.update_idletasks()
Tkwindow.update()
sleep(
1
)
# Delay
##------------------------------------------------------
##==Serial connect Exit================
def
All_Exit():
print
(
"Exit....."
)
#Show to LabelA----------------
LabelA.config(text
=
"Exit....."
)
LabelA.update_idletasks()
Tkwindow.update()
sleep(
1
)
chr_num
=
27
##ESC
cmd
=
(
chr
(chr_num).encode(
'utf-8'
))
SerialWrite(cmd)
ser.close()
Tkwindow.destroy()
# Kill the root window!
##------------------------------------------------------
Tkwindow
=
tkinter.Tk()
Tkwindow.title(
"Using Python to Control Arduino LED ON/OFF"
)
Tkwindow.minsize(
600
,
400
)
LabelA
=
tkinter.Label(Tkwindow,
bg
=
'white'
,
fg
=
'blue'
,
text
=
"Press 'Check' Button then reset Arduino to connect!"
,
width
=
80
,
height
=
10
,
justify
=
tkinter.LEFT
)
LabelA.pack(side
=
tkinter.TOP)
buttonA
=
tkinter.Button(Tkwindow,
anchor
=
tkinter.S,
text
=
"Button A"
,
width
=
10
,
height
=
1
,
command
=
SendCmdA)
buttonA.pack(side
=
tkinter.LEFT)
buttonB
=
tkinter.Button(Tkwindow,
anchor
=
tkinter.S,
text
=
"Button B"
,
width
=
10
,
height
=
1
,
command
=
SendCmdB)
buttonB.pack(side
=
tkinter.LEFT)
buttonC
=
tkinter.Button(Tkwindow,
anchor
=
tkinter.S,
text
=
"Button C"
,
width
=
10
,
height
=
1
,
command
=
SendCmdC)
buttonC.pack(side
=
tkinter.LEFT)
buttonStart
=
tkinter.Button(Tkwindow,
anchor
=
tkinter.S,
text
=
"Check"
,
width
=
10
,
height
=
1
,
command
=
Serial_Connect)
buttonStart.pack(side
=
tkinter.RIGHT)
buttonEnd
=
tkinter.Button(Tkwindow,
anchor
=
tkinter.S,
text
=
"Exit"
,
width
=
10
,
height
=
1
,
command
=
All_Exit)
buttonEnd.pack(side
=
tkinter.RIGHT)
Tkwindow.mainloop()
<Arduino source code>
//*****************************************************************************
//*****************************************************************************
//ArbuluckyChat V1.0
//阿布拉機的3D列印與機器人
//
//2016/07/ˇ0 Writen By Ashing Tsai
//
//******************************************************************************
#include <softwareserial>
const
int
LedPin12=12;
const
int
LedPin11=11;
const
int
LedPin10=10;
//USB-Serial String Str01="";
SoftwareSerial BT(2,3);
//RX,TX
String ReadBTString=
""
;
void
setup() {
BT.begin(9600);
BT.println(
"Ready"
);
// print "Ready" once
//USB-Serial Serial.begin(115200); // set the baud rate
//USB-Serial Serial.println("Ready"); // print "Ready" once
pinMode(LedPin12,OUTPUT);
pinMode(LedPin11,OUTPUT);
pinMode(LedPin10,OUTPUT);
digitalWrite(LedPin12,LOW);
digitalWrite(LedPin11,LOW);
digitalWrite(LedPin10,LOW);
}
void
loop() {
/*USB-Serial+
if
(Serial.available())
{
Str01=
""
;
delay(1);
while
(Serial.available())
{
Str01+=(
char
)Serial.read();
}
Serial.println(Str01);
// send the data back in a new line so that it is not all one long line
}
USB-Serial-*/
//BT+========================
if
(BT.available()) {
ReadBTString=
""
;
while
(BT.available()) {
ReadBTString+=(
char
)BT.read();
delay(1);
}
BT.println(ReadBTString);
}
//BT-========================
if
(ReadBTString[0]==
'a'
)
{
digitalWrite(LedPin12,HIGH);
digitalWrite(LedPin11,LOW);
digitalWrite(LedPin10,LOW);
delay(500);
digitalWrite(LedPin12,LOW);
digitalWrite(LedPin11,HIGH);
digitalWrite(LedPin10,LOW);
delay(500);
digitalWrite(LedPin12,LOW);
digitalWrite(LedPin11,LOW);
digitalWrite(LedPin10,HIGH);
delay(500);
}
if
(ReadBTString[0]==
'b'
)
{
digitalWrite(LedPin12,HIGH);
digitalWrite(LedPin11,LOW);
digitalWrite(LedPin10,LOW);
delay(100);
digitalWrite(LedPin12,LOW);
digitalWrite(LedPin11,HIGH);
digitalWrite(LedPin10,LOW);
delay(100);
digitalWrite(LedPin12,LOW);
digitalWrite(LedPin11,LOW);
digitalWrite(LedPin10,HIGH);
delay(100);
}
if
(ReadBTString[0]==
'c'
)
{
digitalWrite(LedPin12,HIGH);
digitalWrite(LedPin11,HIGH);
digitalWrite(LedPin10,HIGH);
delay(300);
digitalWrite(LedPin12,LOW);
digitalWrite(LedPin11,LOW);
digitalWrite(LedPin10,LOW);
delay(300);
}
}
</softwareserial>
======================================================================
它和電腦或是 Android 的藍芽配對連線以後,電腦或是裝置上就會多一個 serial port 可以通訊,Scratch 或是 Android Apps 就可以透過這個無線的通道和 Arduino 傳送資料。
不過,要開始玩 S4A 之前,因為這個改過的 Scratch 內定是用 38400 的 baud rate 來和 serial port 連線,而 HC-05 預設的 baud rate 卻是 9600,因此,新買的 HC-05 藍芽模組,第一關是要能進入 AT command mode 去修改它的設定值。
如果有 USB to TTL ,可以利用它直接和 HC-05 連接,除了 Vcc , GND, Key(接5V), 兩個裝置的 RXD → TXD, TXD→RXD。
下面介紹第二種方法,以 Arduino 的第 9, 10, 11 pins 和 5V, GND 五個腳位來達到相同的目的。
硬體的部份
=====================================================================
HC-05 和 Arduino 接線的腳位對應如下:
HC-05 VCC → Arduino 5V
HC-05 GND → Arduino GND
HC-05 TXD → Arduino pin 10
HC-05 RXD → Arduino pin 11
HC-05 KEY → Arduino pin 9
/*
AUTHOR: Hazim Bitar (techbitar)
DATE: Aug 29, 2013
LICENSE: Public domain (use at your own risk)
CONTACT: techbitar at gmail dot com (techbitar.com)
*/
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // RX | TX
void setup()
{
pinMode(9, OUTPUT); // this pin will pull the HC-05 pin 34 (key pin) HIGH to switch module to AT mode
digitalWrite(9, HIGH);
Serial.begin(9600);
Serial.println("Enter AT commands:");
BTSerial.begin(38400); // HC-05 default speed in AT command more
}
void loop()
{
// Keep reading from HC-05 and send to Arduino Serial Monitor
if (BTSerial.available())
Serial.write(BTSerial.read());
// Keep reading from Arduino Serial Monitor and send to HC-05
if (Serial.available())
BTSerial.write(Serial.read());
}
================================================================= 我們先將 Arduino 以 USB 接上電腦,打開靭體程式編寫工具,將上面的程式碼貼上、儲存後,上載到 Arduino 中。
讓 HC-05 進入 AT command mode
如果 HC-05 和 Arduino 已按照前述的腳位接好線,並且將前述的靭體上載到 Arduino 中了。就可以依照下面的程序連線並讓 HC-05 進入 AT command mode:
- 先拔掉 Arduino 的 USB 線,也拔掉 HC-05 VCC 和 Arduino 5V 相連的這條線。
- 將 Arduino 的 USB 線插入電腦。
- 開啟終端機軟體(例如 Windows 的超級終端機或是 Putty ......),以
每秒傳輸位元: 9600
資料位元:8
同位檢查:無
停止位元:1
的設定來和 Arduino 的 serial port 連線,成功的話,應該可以在終端機軟體的畫面中看到「Enter AT commands:」的訊息。 - 將 HC-05 VCC 和 Arduino 5V 的線重新接上。
- 供電後的 HC-05 應該是以慢速(約兩秒一次)閃爍 LED,這表示它已進入 AT command mode,等候我們輸入 AT 指令。
啟動「超級終端機」新增連線 |
選取 Arduino 的 serial port |
傳輸速率設為 9600 |
成功和 Arduino 連線 |
HC-05 進入 AT command mode 以後,我們可以先輸入「AT」,按完 Enter 鍵後,應該可以看到畫面回應了「OK」,如果沒訊息,先檢查一下硬體的部份是否有按腳位接對了,再依前述的程序重新來一次。
如果畫面上的「OK」一直重覆的出現,停不下來(我被它給嚇壞了,以為買到了有問題的東西),只要每次按 Enter 鍵時快速的多按一下(也就是連按兩次 Enter 鍵),或是用鍵盤按「Ctrl C」,它就不會瘋狂的回應你了。這個問題應該是 HC-05 的 AT 指令最後要送出「\r\n」,而我們按下 Enter 鍵時,終端機的預設值並沒有送出「換行」字元所致。以 Windows 的「超級終端機」來說,我們可以多設定以下的內容來避免前述的情形:
如果用的是 Arduino 內建的終端機,就在下方多選個「Both NL & CR」,讓在在每道指令後頭都自動加上「\r\n」。
HC-05 的 AT 指令
除了「AT」這個指令外,接下來,我們先查詢一下 HC-05 目前的連線速率,在終端機中輸入底下的指令並按 Enter 鍵:
AT+UART?
如果都沒更改過,預設值的回應可能是:
+UART:9600,0,0
我們想將速率換成 S4A 的 36800 ,輸入以下的指令,並按 Enter 鍵:
AT+UART:38400,0,0
成功的話,HC-05 應該會回應「OK」。
除此之外,可能還有其它 AT command 可以執行的,基本的格式是:
- 查詢:以問號 (?) 結尾。
- 設定:將前述的問號換成冒號 (:) ,其後再接要設定的新內容。
例如:
- AT+VERSION?
- AT+NAME?
- AT+ADDR?
- AT+PSWD?
上面分別是查詢版本(VERSION)、藍芽裝置名稱(NAME)、藍芽裝置位址(ADDR)、配對時的密碼(PSWD)。
相對應的設定指令變成:
- AT+NAME:xxxxx
- AT+PSWD:xxxxx
xxxxx 為想自訂的內容。
還有其它的 AT 指令,有興趣可以找 HC-05 的手冊來研究吧!
設定 HC-05
首先,當然是要以 AT command mode ,先設定一下兩片 HC-05,主要是讓它們扮演不同的角色:slave 和 master (出廠時,預設是 slave);除此之外, 通訊時,UART 的 baud rate 也要設為一樣......。
假設兩片 HC-05 要以 115200 的 baud rate 通訊,並且只鎖定對方連線,可能要進行以下的設定:
在當 slave 的 HC-05 必須執行的 AT command :
- AT+UART=115200,0,0
- AT+CMODE=0
- AT+ROLE=0
- AT+ADDR?
如果「AT+ADDR?」回應的內容是:
+ADDR:14:1:61757
要記下 +ADDR: 後面的那串數字「14:1:61757」(slave 的 address),設定 master 時會用到。
- AT+UART=115200,0,0
- AT+CMODE=0
- AT+ROLE=1
- AT+BIND=14,1,61757
(注意:14,1,61757 請自行置換成您查到的 slave address)
照上面的 AT commands 來看,slave 和 master 不同的地方在後兩道指令:
- 「AT+ROLE=」用來設定模組的角色是 slave ( 0 ) ,還是 master ( 1 )。
- 「AT+ADDR?」用來查詢 client 的 address。
- 「AT+BIND=」用來指定要主動連哪一個 address 的 slave。
特別注意:「AT+ADDR?」查到的 address 中是用冒號「:」當分隔符號,而在 BIND 指令中用的卻是用逗號「,」當分隔符號哦!
經過前述的設定後,照說,當 master 找到 slave 時,就會自動連線了。接著就可以利用兩片 HC-05 上的 TXD 和 RXD 來傳送及接收資料。
Arduino 接線
HC-05 要怎麼和 Arduino 連接呢?其實兩片 HC-05 交換資料和一片 HC-05 與其它藍牙裝置交換資料,接線的方法並沒有什麼不同,最重要的是前一步驟,利用 AT command 要將「UART」、「ROLE」及 master 的「BIND」設對啦!
我們可以選擇用 Arduino 的 D0、D1 來連接 HC-05,或是利用 Arduino 的 D10、D11,以 SoftwareSerial 的方式來連接 HC-05,腳位對應如下:
方法一 (HC-05 TXD、RXD接在D10、D11):
- HC-05 TXD ----- Arduino D0
- HC-05 RXD ----- Arduino D1
方法二 (用 SoftwareSerial,HC-05 TXD、RXD接在D10、D11):
- HC-05 TXD ----- Arduino D10
- HC-05 RXD ----- Arduino D11
如果使用方法二,記得要導入 SoftwareSerial 的函數庫,在程式的最前面加入:
#include <SoftwareSerial.h>
並建立一個「SoftwareSerial」的物件才能使用,而方法一只要直接用「Serial」即可。
Arduino 程式
我寫了個測試的程式,在插 slave HC-05 的 Arduino 加一片 LCD(1602A),當 master 那塊 Arduino 傳來字串,slave 接收到後,將字串顯示在 LCD 上
slave 端程式碼(HC-05 TXD、RXD接在D10、D11)
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // HC-05的TXD,RXD腳位
LiquidCrystal_I2C lcd(0x27,16,2); // 設定 LCD
void setup()
{
lcd.init(); // initialize the lcd
lcd.backlight();
BTSerial.begin(115200);
}
void loop()
{
// 檢查是否有資料傳來
if (BTSerial.available()) {
delay(100); //稍候一下,讓資料都到
lcd.clear(); //清除 LCD 畫面
// 讀取所有資料,並顯示在 LCD
while (BTSerial.available() > 0) {
lcd.write( BTSerial.read() );
}
}
}
上面程式中,關於 HC-05 的指令如下:
- 建立SoftwareSerial : SoftwareSerial BTSerial(10, 11)
- 設定鮑率:BTSerial.begin(115200);
- 檢查是否有資料傳來:BTSerial.available()
- 讀取傳來的資料:BTSerial.read()
有「read」,當然就可以使用「write」來將資料傳送給 master 端。
master 端程式碼(HC-05 TXD、RXD接在D10、D11)
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // HC-05的TXD,RXD腳位
void setup() {
BTSerial.begin(115200);
//稍等一秒後再送資料給遠方
delay(1000);
BTSerial.write("^^ I Love You ^^");
}
void loop()
{
//
}
哈~將 LCD 裝在之前 3D printer 做的履帶車上,用手機遙控,開到老婆面前後,再打出字幕,不賴吧!討了老婆歡心之後,應該可以提高對我老是花很多時間在研究如何「玩耍」的耐受度吧?!
========================================================================
把人家文章的圖文直接複製貼上,是不是有一點過份了呢?
回覆刪除沒連接成功執行到198行i==9 做下面的事,可能我藍芽有問題怎麼連,都跑到這行,COM4,HC-06,不應該用9600而是38400
回覆刪除