EV3軟體中的Messaging Block是唯一使用藍芽通訊的程式區塊,它的功能是在EV3之間傳送與接收郵件訊息(Message),所以只要能夠解析EV3的通訊格式,就同樣可以用來與Arduino進行無線的藍芽通訊。
配對與建立連結
經由EV3進行配對之後,在EV3 UI的藍芽Favorites清單中所顯示的裝置名稱為:Bluebooth_Bee_V2。
接下來就可以在EV3程式中使用Bluetooth Connection Block,並選擇Initiate Mode與輸入Bluebooth_Bee_V2裝置名稱,建立與Arduino藍芽模組之間的連結。
EV3通訊格式解析
唯一能夠參考的就是流傳於網路中的EV3 Source
code,其中c_com.h有關於EV3 System Command與Direct Command封包格式的相關註解。
由此推測與歸結出當使用EV3 Messaging Block的Send Mode時,就是使用WRITEMAILBOX 的 System command。
至於封包的格式為:
由此推測與歸結出當使用EV3 Messaging Block的Send Mode時,就是使用WRITEMAILBOX 的 System command。
至於封包的格式為:
bbbb mmmm tt ss ll aaa LLLL ppp
而封包的資料內容如下表:
Byte
0~1
|
bbbb
= 整體訊息長度(bytes), Word型態, little endian
|
Byte
2~3
|
mmmm
= message counter, 用途不明, Word型態, little endian
|
Byte
4
|
tt
= command類型,
值為0×81: System command, reply not required
|
Byte
5
|
ss
= System command
值為0x9E: WRITEMAILBOX, write to mailbox
|
Byte
6
|
ll
= 包含null結尾字元的Message Title字串長度
|
Byte
7~(6+ll)
|
aaa…
= 包含null結尾字元的Message Title字串
|
Byte
(7+ll)~(8+ll)
|
LLLL
=包含null結尾字元的Message Content字串長度,
Word型態, little endian
|
Byte
(9+ll)~(8+ll+LL)
|
ppp…
=包含null結尾字元的Message Content字串
|
在上表中封包內容裏的 Message Title與Message Content兩個值,在 EV3 Messaging Block對應的input值如下圖:
Arduino原始碼
#define SYSTEM_COMMAND_REPLY 0x01#define SYSTEM_COMMAND_NO_REPLY 0x81
#define SYSTEM_REPLY 0x03
#define SYSTEM_REPLY_ERROR 0x05
#define DIRECT_COMMAND_REPLY 0x00
#define DIRECT_COMMAND_NO_REPLY 0x80
#define DIRECT_REPLY 0x02
#define DIRECT_REPLY_ERROR 0x04
// EV3 System command
#define WRITEMAILBOX 0x9E
#define MIN_PACKET_SIZE 11
#define MAX_PACKET_SIZE 64
#define RCV_MSG_TIMEOUT 5000
byte rcvMessage [MAX_PACKET_SIZE];
byte rcvByte;
int bytesRead=0, packetLength=0;
char strMsg [256];
/* Listen to incoming messages */
void receiveMessage()
{
bytesRead = 0;
for(short xii=0; xii<MAX_PACKET_SIZE; xii++) rcvMessage[xii]=0x00;
Serial.println("\n\r");
Serial.println("Listening ..");
while(true)
{
if(Serial.available() > 0)
{
rcvMessage[bytesRead] = Serial.read();
bytesRead++;
}
if(((bytesRead >= MIN_PACKET_SIZE) &&
(bytesRead == (word(rcvMessage[1], rcvMessage[0])+2))) || (bytesRead > MAX_PACKET_SIZE))
break;
}
}
/* Prints received message sent from EV3 */
boolean printMessage()
{
//String strCmdType;
short packetLength = word(rcvMessage[1], rcvMessage[0]);
if(packetLength == (bytesRead-2))
{
sprintf(strMsg, "There are total %d bytes has been read.", bytesRead);
Serial.println(strMsg);
Serial.println("The message payload receviced from EV3: ");
sprintf(strMsg, "(Byte 0-1) Packet size: %d bytes", packetLength);
Serial.println(strMsg);
sprintf(strMsg, "(Byte 2-3) Message counter: %d", word(rcvMessage[3], rcvMessage[2]));
Serial.println(strMsg);
sprintf(strMsg, "(Byte 4) Command type: %X", rcvMessage[4]);
Serial.println(strMsg);
sprintf(strMsg, "(Byte 5) Command: %X", rcvMessage[5]);
Serial.println(strMsg);
short titleLength = short(rcvMessage[6]);
sprintf(strMsg, "(Byte 6) Message title length: %d", titleLength);
Serial.println(strMsg);
sprintf(strMsg,"(Byte 7-%d) Message title: ", titleLength+6);
Serial.print(strMsg);
for(int xii=0; xii<titleLength-1; xii++) Serial.print((char)rcvMessage[xii+7]);
sprintf(strMsg,"\\%X", rcvMessage[titleLength+6]);
Serial.println(strMsg);
short msgLength = word(rcvMessage[titleLength+8], rcvMessage[titleLength+7]);
sprintf(strMsg,"(Byte %d-%d) Message length: %d", titleLength+7, titleLength+8, msgLength);
Serial.println(strMsg);
sprintf(strMsg,"(Byte %d-%d) Message content: ", titleLength+9, titleLength+msgLength+8);
Serial.println(strMsg);
for(int xii=0; xii<msgLength-1; xii++) Serial.print((char)rcvMessage[xii+titleLength+9]);
sprintf(strMsg,"\\%X", rcvMessage[titleLength+msgLength+8]);
Serial.println(strMsg);
Serial.println("\n\r");
return true;
}
else return false;
}
/* Send a non-empty message to EV3 */
void sendMessage()
{
char replyMessage[] = {0x1A, 0x00,
0x01, 0x00,
SYSTEM_COMMAND_NO_REPLY, WRITEMAILBOX,
0x09, 'C','H','_','E','V','3','_','A','\0',
0x0A, 0x00, 'H','e','l','l','o',' ','E','V','3','\0'};
for(int xii=0; xii<(word(replyMessage[1], replyMessage[0])+2); xii++)
{
Serial.write(replyMessage[xii]);
delay(1);
}
Serial.flush(); // Waits for the transmission of outgoing serial data to complete
}
/* Send a empty message to EV3 */
void sendEmptyMessage()
{
char emptyMessage[] = {0x19, 0x00,
0x01, 0x00,
SYSTEM_COMMAND_NO_REPLY, WRITEMAILBOX,
0x09, 'I','g','n','o','r','e','M','e','\0',
0x09, 0x00, 'I','g','n','o','r','e','M','e','\0'};
for(int xii=0; xii<(word(emptyMessage[1], emptyMessage[0])+2); xii++)
{
Serial.write(emptyMessage[xii]);
delay(1);
}
Serial.flush();
}
void setup()
{
Serial.begin(9600);
for(int xii=5; xii>0; xii--)
{
sprintf(strMsg, "Start to listen after %d seconds ..", xii);
Serial.println(strMsg);
delay(950);
}
}
void loop()
{
receiveMessage();
if(printMessage())
delay(1000);
{
sendMessage();
delay(1000);
sendEmptyMessage();
delay(1000);
}
}
沒有留言:
張貼留言