2011-08-21

Mindstorms NXT與Arduino之間的I2C通訊





建立NXTArduino之間的I2C通訊,主要重點在於瞭解:

NXT Master
端程式如何傳送
以及 Arduino Slave端如何接收與回應


I2C Address
對於7-bits定址當以一個byte(8-bits)來傳送時,需要將位址放在較高的7bits(bit 1-bit 7)bit 0(LSB)是用來通知Slave目前Master是要傳送(0)或讀取(1),舉例:
Slave ArduinoI2C 位址為0x31(Wire.begin(0x31))時,NXTSlave 8-bits I2C位址就須設成0x62(0x31 << 1)

NXC I2C Buffer
NXCLowspeedWrite(port,retrunLength, I2C_input_buffer )來啟始並傳送資料至Slave,傳送的資料存放在I2C_input_buffer的陣列中,第一個元素所存的就是Slave8-bits address,第二個元素及以後的資料就是要傳送至Slave的資料,SlaveArduino會觸發Wire.onReceive (handler)所註冊的handler接收來自NXT所傳送的資料
而當NXCLowspeedRead(port, bufferLength,I2C_output_buffer)要求Slave Arduino回傳資料時,會觸發Wire.onRequest (handler)所註冊的handler所以要回傳給NXT的資料需要在onRequest
 handler
使用Wire. send()傳送

測試案例
Arduino模擬成NXTI2C裝置,除了可以回傳裝置資訊外,另外若寫入0x42再加上LED的控制指令,可以開關Arduino上紅色與綠色的LED

就如同前面所提,由onReceive handler接收來自NXC input buffer的資料,若判斷接收到的第一個byte0x42則表示後續還須接收一個byteLED控制指令,而若為要求回應裝置資訊的指令(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));
      }
}


沒有留言:

張貼留言