Thursday, December 25, 2014

Raspberry Pi + Arduino i2c communication, write block and read byte

This example extends work on last example "Raspberry Pi send block of data to Arduino using I2C"; the Raspberry Pi read byte from Arduino Uno after block sent, and the Arduino always send back length of data received.


i2c_slave_12x6LCD.ino sketch 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() {

}

void requestEvent(){
  Wire.write(echonum);
  toggleLED();
}


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(" ");

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

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

i2c_uno.py, python program 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 = 0x01

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, 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, bytesToSend)
    
    # delay 0.1 second
    # with delay will cause error of:
    # IOError: [Error 5] Input/output error
    time.sleep(0.1)
    number = bus.read_byte(i2c_address)
    print('echo: ' + str(number))
    
    if r=='q':
        exit=True


Next:
Wire.write() multi-byte from Arduino requestEvent


WARNING:
Somebody advise to use I2C Logic Level Converter between Raspberry Pi and Arduino, otherwise the RPi's ports will be burnt! So, please think about it and take your own risk.

No comments: