Arduino有許多的I2C週邊或擴充板,如何來讓NXT也能使用這些週邊? 若是能夠藉由Arduino主板來存取,那就大大的提昇了這些週邊的使用範圍與彈性。
對於這樣的應用,首先要確認的是:Wire.h library能否支援多個Master的運作,
更明確的說法是:Arduino主板是否可以同時身兼Master與Salve。
當它與NXT進行通訊時須擔任Salve,但當要存取I2C週邊時又得作為Master。
幾週前由Digital Cave這個網站,查到了以下對於Multi Master的說明資料:
The I2C protocol
is a multi-master protocol; however, the Wire library in the Arduino
distribution does not make it clear on how to implement this functionality.
…
the documentation on the Arduino webpage
is slightly misleading in how
you would go about doing it. The documentation as currently written states that
for Wire.begin(address), the address is optional and 'if not specified, join
the bus as a master'. However, what is not stated is that if you transmit something from a device which has already
joined as a slave, it will assume the role of Master when it sends the data to another slave.
以上算是 Wire.h library的Missing Manual。
為了驗證以上的說法,延續之前NXT與Arduino之間的I2C通訊測試,實作了以下的測試Case:
(1) 使用兩部UNO,都模擬成I2C Slave裝置,其Address分別是0x31與0x33,而upload的sketch功能皆相同:
當它們接收到0x42+0x01/0x02的控制指令資料時,就會去開/關接在D13的LED(0x31為紅色,0x33為綠色),此外,又多增加了一個0x43的控制指令,附加的指令資料包含:另一部Slave的位址、要傳送的控制指令值以及LED的開關指令值。
(2) 將以上兩部UNO與NXT串接成I2C通訊架構。
首先由NXT以Lowspeedwrite()傳送[0x62, 0x43, 0x33, 0x42,
0x01]的資料,
這時候0x31 Slave會接收到[0x43, 0x33, 0x42,
0x01]的控制指令,
當它處理完onReceive() Handler之後,
接著它就會扮演起Master角色,send()出[0x33, 0x42, 0x01]的資料,
這時候0x33 Slave就會接收到[0x42, 0x01]的資料而去執行開啟LED(綠色)的指令。
所以依據以上的測式情境,0x31 Slave就是身兼Slave與Master的雙重角色。
NXT 新增的Function與呼叫程式碼:
void sendTransferCommand(const byte
deviceAddress,
const byte
deviceRegister,const byte anotherDevice,
const byte
anotherRegister, const byte anotherCommand)
{
byte I2C_req_buf[];
ArrayBuild(I2C_req_buf,
deviceAddress, deviceRegister,
anotherDevice,
anotherRegister, anotherCommand);
while(I2CCheckStatus(I2C_PORT)
== STAT_COMM_PENDING);
LowspeedWrite(I2C_PORT,
0, I2C_req_buf);
}
…
sendTransferCommand(ARDUINO_RED_SEND_ADDRESS,
ARDUINO_TRANSFER_CMD,
ARDUINO_GREEN_ADDRESS,
ARDUINO_COMMAND_REG,
LED_ON);
Arduino新增的Function與呼叫程式碼:
void loop()
{
if
(isTransfer) {
Wire.beginTransmission(anotherAddress);
Wire.send(anotherRegister);
Wire.send(anotherCommand);
Wire.endTransmission();
isTransfer = false;
}
}
void receiveEvent(int howMany)
{
requestRegister = Wire.receive();
if
(requestRegister == 0x42) {
requestCommand = Wire.receive();
if
(requestCommand == LED_ON) {
digitalWrite(LED_PIN, HIGH);
}
else
if (requestCommand == LED_OFF) {
digitalWrite(LED_PIN, LOW);
}
}
else if
(requestRegister == 0x43) {
anotherAddress= Wire.receive();
anotherRegister = Wire.receive();
anotherCommand= Wire.receive();
isTransfer = true;
}
}