ArduinoはBluetooth通信できませんので、
HC-05というBluetoothモジュールを使用します。
1年半ほど前の前回記事ではwindowsとArduinoを
Bleutooth通信するバージョンを投稿しましたが、
それのちょっとした応用という形になります。
今回行うことは以下になります。
M5Stack(Gray)が周期的にデータを送信し、
そのデータをHC-05経由でArduinoが受信します。
そしてPCに直接つながったArduinoが
UART-USB経由でPCへ送信し、
そのデータをシリアルモニタで確認する、
というシナリオです。
前回記事で用いたArduinoコードをほぼ、
流用できますがM5Stack側は新しく作成します。
その際、HC-05に格納されている情報を
取得する必要がありますので、
その方法も併せて載せます。
それではまずはHC-05の説明から見ていきましょう!
HC-05のATコマンドとBD ADDRについて
コード作成にするにあたり、
必要な準備がありますので、
それに関するお話を順を追ってします。
HC-05はBluetooth Classic ver2.0に該当します。
なのでペアリングはLegacy Paringで、
ver2.1から実装されたSSPには対応していません。
(SSPは、Secure Simple Paringの略)
M5StackがHC-05に対してペアリングを行うには、
HC-05を一意に特定する識別子が必要です。
その識別子をBD ADDRと言います。
BD ADDR: Bluetooth Device ADDRess
ちなみにその構成は以下になっています。

参考元:https://macaddresschanger.com/what-is-bluetooth-address-BD_ADDR
NAP, UAP, LAPの3要素で成り立っています。
それぞれ順に2バイト、1バイト、3バイト
となっていて前半3バイトはOUIになります。
OUIはEthernetのMACアドレスでも出てきましたね。
BD ADDRを調べるにはATコマンドを使って、
デバイスにリクエストを投げます。
ここで少し話しが変わりますが、
データを送受信するとき以外に、
HC-05には2つのモードがあります。
ペアリングモード、ATコマンドモードです。
HC-05のLEDの点滅速度によってモードが分かります。
速い → ペアリングモード
遅い → ATコマンドモード
ペアリングモードは1秒間に
何回もLEDのON/OFFが切り替わります。
ATコマンドは2秒毎にON/OFFが替わります。
ペアリングが完了すると高速点滅は終わます。
データが送受信される毎に点滅します。
今回鍵となるのが、ATコマンドモードです。
HC-05がこのモードの時にシリアル(UART)経由で
特定のコマンドを送信することで、
それに対するリスポンスが返ってきます。
ちなみにATコマンドモードは、
モジュールがペアリングモードの時に、
EN (Key)ピンをHighにすることで
ATコマンドモードへと遷移します。
つまりArduinoの3.3Vピンを
ENピンと接続すれば良いだけです。
配線は以下になります。
HC-05 | Arduino |
---|---|
STATE | not connected |
RX | PIN_11 |
TX | PIN_10 |
GND | GND |
VCC | 5V |
EN | 3.3V |
そしてコードは以下になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <SoftwareSerial.h> SoftwareSerial SerialBT(10, 11); //Rx, Tx void setup() { Serial.begin(9600); Serial.println("Ready"); SerialBT.begin(38400); //must be 38400 ? } void loop() { if(SerialBT.available()){ int c = SerialBT.read(); Serial.print(char(c)); } if(Serial.available()){ int c = Serial.read(); SerialBT.print(char(c)); } } |
シリアルモニタからコマンドを送りますが、
改行も一緒に送信する必要があります。
改行はBoth NL & CR で設定しておきましょう。
続いてPCとArduino間のボーレートですが、
最初115200に設定していたのですが、
ERROR(0)しか返ってきませんでした。
9600に落としたら上手く行きました。

設定も正しいのにERRORが返って来る場合は、
HC-05モジュール上のRESETボタンを押しながら、
電源を入れたりしてみてください。
今回、最低限欲しい情報はAddrですが、
参考として主なATコマンドとそれに対する
私の場合のリプライを記載しておきます。
AT commands | Replay |
---|---|
AT | OK |
AT+RESET | OK |
AT+VERSION? | +VERSION:2.0-20100601 OK |
AT+NAME? | +NAME:DSD TECH HC-05 OK |
AT+ADDR? | +ADDR:14:3:5f3e4 OK |
AT+ROLE? | +ROLE:0 OK |
AT+PSWD? | +PSWD:1234 OK |
Role:0 がslave(peripheral)で、1がMaster(central)です。
PSWDはペアリングの際に入力するコードです。
もし何か値を変更したい場合は、
"?" を "= new value"にすれば出来ます。
例えば、AT+PSWD=777 で変更可能です。
以下のリンク先にATコマンドの詳しい情報があります。
https://s3-sa-east-1.amazonaws.com/robocore-lojavirtual/709/HC-05_ATCommandSet.pdf
ここでBD ADDRの話しになりますが、
AT+ADDR?とコマンドを送信することで、
自分のBD ADDRが取得出来ます。
コロンでNAP, UAP, LAPにそれぞれ区切られます。
ですので私のアドレスで言うところの
NAPは14で、UAPが0で、LAPが5f3e4です。
この値を後述のコードで使用します。
以上が、HC-05とATコマンドになります。
続いてArduinoのコード作成です。
ArduinoとHC-05
受信データはUART(SoftwareSerial)から流れてくるので、
受信したらそれをそのままPCへ流す、というだけです。
コードは以下になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <SoftwareSerial.h> SoftwareSerial SerialBT(10, 11); //Rx, Tx void setup() { Serial.begin(9600); Serial.println("Ready"); SerialBT.begin(9600); } void loop() { if(SerialBT.available()){ Serial.write(SerialBT.read()); } } |
HC-05と接続するためのUARTを
SoftwareSerial SerialBTで定義し、
10ピンと11ピンをアサインしています。
ここで1つ注意(私だけ?)なのですが、
ボーレートの値についてです。
115200と38400で試したのですが、
M5StackからBluetooth経由で送られてきたデータは、
文字化けしてシリアルモニタ上で
正確なデータが確認出来ませんでした。
結局ボーレートはどちらも9600にしたら
シリアルモニタに上手く表示されました。
また、このときのArduinoとHC-05に配線ですが、
今回はペアリングモードから入るので、
ENピンはLow(何も接続しない)状態にしておきます。
最後にM5Stack側のコードです。
M5Stack GrayとHC-05
M5Stack Grayを使用しており、
今回は何か接続する必要はありません。
コードの概要ですが、
setup()でコネクションの確立、
そしてloop()で周期的にデータの送信を
するコードになっています。
コネクションの確立には、
ATコマンドで取得したHC-05の識別子
BD ADDRが必要になります。
それをuint8_tの配列にセットしてあげます。
コードは以下になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include <M5Stack.h> #include "BluetoothSerial.h" BluetoothSerial SerialBT; unsigned long previousMS = 0; const long interval = 1000; //msec uint8_t address[6] = {0x00, 0x14, 0x3, 0x5, 0xf3, 0xe4}; bool connected; void setup() { M5.begin(); M5.Power.begin(); M5.Lcd.clear(WHITE); M5.Lcd.setCursor(0, 5); M5.Lcd.setTextColor(RED); M5.Lcd.setTextSize(2); SerialBT.begin("ESP32test", true); //By default it’s called ESP32test connected = SerialBT.connect(address); if(connected) { M5.Lcd.printf("Connected Succesfully!\n"); } else { while(!SerialBT.connected(10000)) { M5.Lcd.printf("Failed to connect. Make sure remote device is available and in range, then restart app.\n"); } } } void loop() { //millis():プログラムの実行を開始した時から現在までの時間をミリ秒単位で返します。約50日間でオーバーフローし、ゼロに戻る unsigned long currentMS = millis(); if(currentMS - previousMS >= interval){ previousMS = currentMS; SerialBT.write(77); //Ascii "M" M5.Lcd.printf("BT sends data!\n"); delay(interval-20); } } |
SerialBT.connect(address)で、
指定したアドレスを持つBluetoothデバイスと
コネクションの確立を試みます。
戻り値はboolであり、もしそれがtrueなら
loop文に進み、データを送信し続けます。
falseならFailed to connect を表示し続けます。
loopの最初に1秒たったか判定します。
1秒経過しているならデータを送信します。
t秒経過の判定にはmillis関数を使用します。
プログラムが走り始めてからの実行時間が返るので、
前回のデータ送信時からの差分を計算してあげます。
もしデータを送信したら、
delayで約1秒ほど待ちます。
1秒をそのままdelayさせてしまうと、
送信や分岐命令で使用したクロックサイクルが
その時間に含まれていないことになるので、
適当にインターバル時間から20ms引いています。
この数値は感覚的なものであり、
特に正確ではないのでご注意ください。
実行結果は以下になりました。

期待通りに出力されました!
最後まで読んでいただきありがとうございます。
補足:
HC-05 / HC-06ともに技適が取れていないので、
電波暗室等などで実験を行う必要があります。
私は研究室の電波暗室で行いました。