建立NXT與Arduino之間的I2C通訊,主要重點在於瞭解:
NXT Master端程式如何傳送
以及 Arduino Slave端如何接收與回應。
I2C Address
NXT Master端程式如何傳送
以及 Arduino Slave端如何接收與回應。
I2C Address
對於7-bits定址當以一個byte(8-bits)來傳送時,需要將位址放在較高的7個bits(bit 1-bit 7),bit 0(LSB)是用來通知Slave目前Master是要傳送(0)或讀取(1),舉例:
若Slave Arduino的I2C 位址為0x31(Wire.begin(0x31))時,則NXT端Slave的 8-bits I2C位址就須設成0x62(0x31 << 1)。
若Slave Arduino的I2C 位址為0x31(Wire.begin(0x31))時,則NXT端Slave的 8-bits I2C位址就須設成0x62(0x31 << 1)。
NXC I2C Buffer
NXC以LowspeedWrite(port,retrunLength, I2C_input_buffer )來啟始並傳送資料至Slave,傳送的資料存放在I2C_input_buffer的陣列中,第一個元素所存的就是Slave的8-bits address,第二個元素及以後的資料就是要傳送至Slave的資料,而Slave端Arduino會觸發Wire.onReceive (handler)所註冊的handler接收來自NXT所傳送的資料。
而當NXC以LowspeedRead(port, bufferLength,I2C_output_buffer)要求Slave Arduino回傳資料時,會觸發Wire.onRequest (handler)所註冊的handler,所以要回傳給NXT的資料需要在onRequest
handler使用Wire. send()傳送。
handler使用Wire. send()傳送。
測試案例
將Arduino模擬成NXT的I2C裝置,除了可以回傳裝置資訊外,另外若寫入0x42再加上LED的控制指令,可以開關Arduino上紅色與綠色的LED。
就如同前面所提,由onReceive handler接收來自NXC input buffer的資料,若判斷接收到的第一個byte是0x42則表示後續還須接收一個byte的LED控制指令,而若為要求回應裝置資訊的指令(0x00, 0x08, 0x10)時,則在NXT傳送 LowspeedRead()時於onRequest()handler中回傳資料。
在進行這個測試時,原來使用的接線方式與”兩部Arduino之間的I2C通訊”相同,但就是一直連不上,後來才發現問題出在Pull-up,拿掉後就一切OK了
Arduino Slave
#include <Wire.h>
#define I2C_SLAVE_ADDRESS 0x31
#define LED_RED 13
#define LED_GREEN 12
#define RED_ON 0x52
#define GREEN_ON 0x47
#define RED_GREEN_ON 0x59
#define RED_GREEN_OFF 0x4E
uint8_t softwareVersion[9] = "V1.00 ";
uint8_t vendorID[9] = "Arduino ";
uint8_t deviceID[9] = "UNO ";
byte requestRegister, requestCommand;
void executeCommand(byte execCmd)
{
if (requestRegister== 0x42)
{
if (execCmd ==RED_ON)
{
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_GREEN, LOW);
}
else if (execCmd == GREEN_ON)
{
digitalWrite(LED_RED, LOW);
digitalWrite(LED_GREEN, HIGH);
}
else if(execCmd == RED_GREEN_ON)
{
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_GREEN, HIGH);
}
else if(execCmd == RED_GREEN_OFF)
{
digitalWrite(LED_RED, LOW);
digitalWrite(LED_GREEN, LOW);
}
}
}
void setup()
{
pinMode(LED_RED,OUTPUT);
pinMode(LED_GREEN,OUTPUT);
digitalWrite(LED_RED,LOW);
digitalWrite(LED_GREEN, LOW);
Serial.begin(9600);
Wire.begin(I2C_SLAVE_ADDRESS);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
}
void loop() { }
void receiveEvent(int howMany)
{
requestRegister =Wire.receive();
if (Wire.available()> 0)
{
requestCommand = Wire.receive();
executeCommand(requestCommand);
}
}
void requestEvent()
{
if (requestRegister ==0x00)
{
Wire.send(softwareVersion, 8);
}
else if (requestRegister== 0x08)
{
Wire.send(vendorID, 8);
}
else if(requestRegister == 0x10)
{
Wire.send(deviceID, 8);
}
}
NXT Master
#define ARDUINO_ADDRESS 0x31
#define ARDUINO_SEND_ADDRESS 0x62
#define ARDUINO_SW_VERSION 0x00
#define ARDUINO_VENDOR_ID 0x08
#define ARDUINO_DEVICE_ID 0x10
#define ARDUINO_COMMAND_REG 0x42
#define RED_ON_GREEN_OFF 'R'
#define RED_OFF_GREEN_ON 'G'
#define RED_ON_GREEN_ON 'Y'
#define RED_OFF_GREEN_OFF 'N'
#define I2C_PORT S1
void sendDeviceCommand(const byte deviceAddress,
const byte deviceRegister,
const byte deviceCommand)
{
byte I2C_req_buf[];
ArrayBuild(I2C_req_buf, deviceAddress, deviceRegister, deviceCommand);
while(I2CCheckStatus(I2C_PORT) == STAT_COMM_PENDING);
LowspeedWrite(I2C_PORT, 0, I2C_req_buf);
}
string getDeviceInfo(const byte deviceAddress,
const byte deviceRegister,
byte num_of_bytes)
{
byte I2C_req_buf[], I2C_get_buf[];
short status_code;
ArrayBuild(I2C_req_buf, deviceAddress, deviceRegister);
ArrayInit(I2C_get_buf, " " , 9);
while(I2CCheckStatus(I2C_PORT) == STAT_COMM_PENDING);
status_code =I2CBytes(I2C_PORT, I2C_req_buf, num_of_bytes, I2C_get_buf);
if (status_code <0) return "Failed !";
else return (ByteArrayToStr(I2C_get_buf));
}
task main()
{
SetSensorLowspeed(I2C_PORT);
while (TRUE)
{
ClearScreen();
TextOut(0,LCD_LINE1, "NXT-I2C-Arduino " );
TextOut(0,LCD_LINE2, "Show Device Info" )
TextOut(0, LCD_LINE4, "SW Ver: " );
TextOut(0,LCD_LINE5, "Vendor: ");
TextOut(0,LCD_LINE6, "Device: ");
TextOut(0,LCD_LINE7, " ");
TextOut(0,LCD_LINE8, " Run");
until(ButtonPressed(BTNRIGHT, TRUE));
Wait(50);
TextOut(0,LCD_LINE8, " Processing ... " ); //Request Arduino for returning device info.
TextOut(48,LCD_LINE4,
getDeviceInfo(ARDUINO_SEND_ADDRESS, ARDUINO_SW_VERSION, 8));
TextOut(48,LCD_LINE5,
getDeviceInfo(ARDUINO_SEND_ADDRESS, ARDUINO_VENDOR_ID, 8));
TextOut(48,LCD_LINE6,
getDeviceInfo(ARDUINO_SEND_ADDRESS,ARDUINO_DEVICE_ID, 8));
//Send command to Arduino turning ON/OFF Red/Green LED
TextOut(0,LCD_LINE7, "Red ON , GR OFF");
sendDeviceCommand(ARDUINO_SEND_ADDRESS,
ARDUINO_COMMAND_REG, RED_ON_GREEN_OFF);
Wait(3000);
TextOut(0,LCD_LINE7, "Red OFF, GR ON ");
sendDeviceCommand(ARDUINO_SEND_ADDRESS,
ARDUINO_COMMAND_REG, RED_OFF_GREEN_ON);
Wait(3000);
TextOut(0,LCD_LINE7, "Red ON , GR ON ");
sendDeviceCommand(ARDUINO_SEND_ADDRESS,
ARDUINO_COMMAND_REG, RED_ON_GREEN_ON);
Wait(3000);
TextOut(0, LCD_LINE7, "RedOFF, GR OFF" );
sendDeviceCommand(ARDUINO_SEND_ADDRESS,
ARDUINO_COMMAND_REG, RED_OFF_GREEN_OFF);
TextOut(0,LCD_LINE8, "Continue ");
until (ButtonPressed(BTNLEFT,TRUE));
}
}
沒有留言:
張貼留言