Wednesday, January 7, 2015

Raspberry Pi + Arduino i2c communication, Wire.write() multi-byte from Arduino requestEvent

Last exercise show Raspberry Pi master + Arduino slave i2c communication, write block of data from Pi to Arduino Uno, and read a single byte from Arduino Uno. In this post show how to echo multi-byte from Arduino in requestEvent, by calling Wire.write().


In Raspberry Pi, i2c master, it send block of data to Arduino Uno, i2c slave, by calling bus.write_i2c_block_data(), to trigger receiveEvent in Arduino.
then call number of bus.read_byte() to trigger requestEvent in Arduino. The first byte echo from Arduino is the number of byte to sent, then echo the data in reversed sequency.

i2c_uno.py run on Raspberry Pi
#have to run 'sudo apt-get install python-smbus'
#in Terminal to install smbus
import smbus
import time
import os

# display system info
print os.uname()

bus = smbus.SMBus(1)

# I2C address of Arduino Slave
i2c_address = 0x07
i2c_cmd_write = 0x01
i2c_cmd_read = 0x02

def ConvertStringToBytes(src):
    converted = []
    for b in src:
        converted.append(ord(b))
    return converted

# send welcome message at start-up
bytesToSend = ConvertStringToBytes("Hello Uno")
bus.write_i2c_block_data(i2c_address, i2c_cmd_write, bytesToSend)

# loop to send message
exit = False
while not exit:
    r = raw_input('Enter something, "q" to quit"')
    print(r)
    
    bytesToSend = ConvertStringToBytes(r)
    bus.write_i2c_block_data(i2c_address, i2c_cmd_write, bytesToSend)
    
    # delay 0.1 second
    # with delay will cause error of:
    # IOError: [Error 5] Input/output error
    time.sleep(0.1)
    
    data = ""
    numOfByte = bus.read_byte(i2c_address)
    print numOfByte
    
    for i in range(0, numOfByte):
        data += chr(bus.read_byte(i2c_address));
    print data
    
    if r=='q':
        exit=True


i2c_slave_12x6LCD.ino, run on Arduino Uno
/*
 LCD part reference to:
 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 */

#include <LiquidCrystal.h>
#include <Wire.h>

#define LED_PIN 13
boolean ledon = HIGH;
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

byte slave_address = 7;
int echonum = 0;

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print startup message to the LCD.
  lcd.print("Arduino Uno");
  
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  
  Wire.begin(slave_address);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);

}

void loop() {

}

char echo[32];
int index = 0;

void requestEvent(){
  toggleLED();
  if(index==0){
    Wire.write(echonum);
  }else{
    Wire.write(echo[echonum-1-(index-1)]);
  }
  index++;
}

void receiveEvent(int howMany) {
  
  lcd.clear();
  
  int numOfBytes = Wire.available();
  //display number of bytes and cmd received, as bytes
  lcd.setCursor(0, 0);
  lcd.print("len:");
  lcd.print(numOfBytes);
  lcd.print(" ");
  
  byte b = Wire.read();  //cmd
  lcd.print("cmd:");
  lcd.print(b);
  lcd.print(" ");
  
  index = 0;

  //display message received, as char
  lcd.setCursor(0, 1);
  for(int i=0; i<numOfBytes-1; i++){
    char data = Wire.read();
    lcd.print(data);
    
    echo[i] = data;
  }
  
  echonum = numOfBytes-1;
}

void toggleLED(){
  ledon = !ledon;
  if(ledon){
    digitalWrite(LED_PIN, HIGH);
  }else{
    digitalWrite(LED_PIN, LOW);
  }
}

No comments: