透過預先規劃好的「I2C虛擬暫存器位址映對表(Register layout)」,提供作為回應Master(EV3)的多種功能需求,包含:
暫存器位址
|
執行功能
|
0x00
|
回傳版本資訊 "V1.00 " 共8個bytes
|
0x08
|
回傳廠商名稱 "Arduino " 共8個bytes
|
0x10
|
回傳裝置代號 "UNO " 共8個bytes
|
0x18
|
接收來自Master傳送的7個bytes資料並顯示在Serial Console
|
0x19
|
執行開啟 Arduino板的L LED
|
0x1A
|
執行熄滅 Arduino板的L LED
|
測試案例
一、由EV3控制開啟Arduino板上的L-LED:
作法即使用EV3_I2C Block的「Write 1 byte」模式寫入 25(0x19)到 Arduino,
Arduino 將會觸發receiveEvent()程序,再以Wire.read()讀取25這個值並透過負責執行指令的executeCommand()函式,
開啟L-LED
void receiveEvent(int howMany)
{
requestRegister = Wire.read();
while(Wire.available() > 0 && bytesRead < MAX_DATA_BUF_SIZE) {
rcvData[bytesRead]=Wire.read();
bytesRead++;
}
executeCommand(requestRegister);
}
...
{
if(execCmd == COMMAND_LLED_ON) {
Serial.println("Turn ON LED");
digitalWrite(LLED, HIGH);
}
else if(execCmd == COMMAND_LLED_OFF) {
Serial.println("Turn OFF LED");
digitalWrite(LLED, LOW);
}
else if(execCmd == COMMANDD_SEND_7_BYTES) {
sprintf(strMsg, "%d bytes of data has been read.", bytesRead);
Serial.println(strMsg);
if(bytesRead>0) {
for(int i=0; i<bytesRead; i++) {
Serial.println((char)rcvData[i]);
}
bytesRead=0;
}
}
}
二、EV3傳送7個bytes資料給Arduino顯示於Serial Console:
作法即使用EV3_I2C Block的「Write 8 byte」模式,在Byte 1寫入 24(0x18),以通知Arduino還要繼續接收7個bytes的資料,而Byte 2~Byte8則分別寫入所要顯示7個字元的Ascii值,如以下所示:
Arduino同樣經由receiveEvent()接收資料後,再交由executeCommand()顯示於Serial Console:
else if(execCmd == COMMANDD_SEND_7_BYTES) {
sprintf(strMsg, "%d bytes of data has been read.", bytesRead);
Serial.println(strMsg);
if(bytesRead>0) {
for(int i=0; i<bytesRead; i++) {
Serial.println((char)rcvData[i]);
}
bytesRead=0;
}
}
三、由EV3向Arduino請求傳送8個bytes的資料(例如廠商名稱)
作法會分成兩個步驟:
●首先使用EV3_I2C Block的「Write 1 byte」模式,
寫入 8(0x08)到 Arduino,●首先使用EV3_I2C Block的「Write 1 byte」模式,
Arduino同樣經由receiveEvent()接收到資料,
以Wire.read()將0x08這個值存起來,
並知道接下來會有廠商名稱("Arduino ")的請求資料需求。
以Wire.read()將0x08這個值存起來,
並知道接下來會有廠商名稱("Arduino ")的請求資料需求。
● 接著,再使用「Read 8 byte」模式向Arduino請求傳送8個bytes的資料,
Arduino會觸發onRequest() handler,依據先前EV3所要求的資料項目0x08(vendorID),以Wire.write()回傳資料給EV3。
void requestEvent()
{
if(requestRegister == COMMAND_GET_VERSION) {
Wire.write(softwareVersion, 8);
}
else if(requestRegister == COMMAND_GET_VENDOR) {
Wire.write(vendorID, 8);
}
else if(requestRegister == COMMAND_GET_DEVICE_ID) {
Wire.write(deviceID, 8);
}
}
● 接下來就可以由EV3_I2C block的8個Output plug讀取Arduino回傳的資料,不過有三點需要注意的地方:
※ 首先讀到是Ascii值而非字元(character),正常應該是要使用
「Read 8 bytes ASCII」模式才能夠讀到,
不過目前這個模式的功能異常,無法使用。
「Read 8 bytes ASCII」模式才能夠讀到,
不過目前這個模式的功能異常,無法使用。
※ 接下來,比較不解的是,
回傳回來的資料在EV3_I2C block Output Plug 存放的順序
居然是由 Byte 8開始,所以,以上圖為例,
Byte 1~Byte 8依序所讀到的資料為:
32, 111, 110, 105, 117, 100, 114
回傳回來的資料在EV3_I2C block Output Plug 存放的順序
居然是由 Byte 8開始,所以,以上圖為例,
Byte 1~Byte 8依序所讀到的資料為:
32, 111, 110, 105, 117, 100, 114
※ 最後,如果回傳的資料數目少於請求的資料數,
則在Output Plug會讀到 -1 的值, 以下圖為例,Arduino只回傳了4個bytes,注意,資料還是由Byte 8開始存放 ???????
Arduino Sketch
/* ********************************************************
* Program ID: Arduino_RequestFm_EV3
* Created by: CH, Chen (Taiwan)
* Date: 2014.6.10
* ******************************************************** */
#include <Wire.h>
#define I2C_SLAVE_ADDRESS 0x04
#define COMMAND_GET_VERSION 0x00
#define COMMAND_GET_VENDOR 0x08
#define COMMAND_GET_DEVICE_ID 0x10
#define COMMANDD_SEND_7_BYTES 0x18
#define COMMAND_LLED_ON 0x19
#define COMMAND_LLED_OFF 0x1A
#define LLED 13
#define MAX_DATA_BUF_SIZE 32
uint8_t softwareVersion[9] = "V1.00 ";
uint8_t vendorID[9] = "Arduino ";
uint8_t deviceID[9] = "UNO ";
byte requestRegister, rcvData[32];
char strMsg[256];
int bytesRead=0;
void setup()
{
pinMode(LLED, OUTPUT);
digitalWrite(LLED, LOW);
Serial.begin(9600);
Wire.begin(I2C_SLAVE_ADDRESS);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
Serial.println("Ready ..");
}
void loop() { }
void executeCommand(byte execCmd)
{
if(execCmd == COMMAND_LLED_ON) {
Serial.println("Turn ON LED");
digitalWrite(LLED, HIGH);
}
else if(execCmd == COMMAND_LLED_OFF) {
Serial.println("Turn OFF LED");
digitalWrite(LLED, LOW);
}
else if(execCmd == COMMANDD_SEND_7_BYTES) {
sprintf(strMsg, "%d bytes of data has been read.", bytesRead);
Serial.println(strMsg);
if(bytesRead>0) {
for(int i=0; i<bytesRead; i++) {
Serial.println((char)rcvData[i]);
}
bytesRead=0;
}
}
}
void receiveEvent(int howMany)
{
requestRegister = Wire.read();
while(Wire.available() > 0 && bytesRead < MAX_DATA_BUF_SIZE) {
rcvData[bytesRead]=Wire.read();
bytesRead++;
}
executeCommand(requestRegister);
}
void requestEvent()
{
if(requestRegister == COMMAND_GET_VERSION) {
Wire.write(softwareVersion, 8);
}
else if(requestRegister == COMMAND_GET_VENDOR) {
Wire.write(vendorID, 8);
}
else if(requestRegister == COMMAND_GET_DEVICE_ID) {
Wire.write(deviceID, 8);
}
}
作者已經移除這則留言。
回覆刪除