0

I am working on a project which involved i2c communication between an Arduino Uno and a Raspberry Pi. I'm trying to send data to the Arduino from the Pi and back.

Here is my code for the Arduino:

#include <Wire.h>
#include <Arduino.h>
#define SLAVE_ADDRESS 0x12

int flag_int_to_send_to_PI = 0;
int flag_int_received_from_PI = 0;
char data_to_send_PI[] = "hello PI";
String data_recieved_from_pi = "";

void setup() {
     Wire.begin(SLAVE_ADDRESS);
     Wire.onReceive(receiveData);
     Wire.onRequest(sendData);

     Serial.begin(9600);
     flag_int_to_send_to_PI = 1;
}

void loop() {}

void receiveData(int byteCount) {

    while(Wire.available()) {
        flag_int_received_from_PI = Wire.read();

        if(flag_int_received_from_PI == 1) {
            Serial.println("PI Wants data[].");
            flag_int_to_send_to_PI = 3;
        }

        if(flag_int_received_from_PI == 3) {
            Serial.println("PI Wants To say its ok.");

            //reading a string from pi: Here (How ?)
            while( Wire.available()) {
                data_recieved_from_pi += (char)Wire.read();
            }

            Serial.print("Data Received From PI:");
            Serial.println(data_recieved_from_pi);

            data_recieved_from_pi = "";
        }
    }
}

void sendData() {

    if(flag_int_to_send_to_PI == 1) {
        Serial.println("Conversation begin : sending 1 to PI");

        Wire.write(flag_int_to_send_to_PI);
    }

    if(flag_int_to_send_to_PI == 3) {
        Wire.write(data_to_send_PI);
    }

    flag_int_to_send_to_PI = 0;
}

and here is the Raspberry Pi Code:

#!/usr/bin/python

from smbus import SMBus
import time
bus = SMBus(1)
slaveAddress = 0x12
data_received_from_Arduino = ""
data_to_send_to_Arduino = "Hello Uno"

def StringToBytes(val):
    retVal = []
    for c in val:
            retVal.append(ord(c))
    return retVal


while(1):
    try:
        x = bus.read_byte(slaveAddress)

        if (x == 1):
            print(x)
            bus.write_byte(slaveAddress,1)
            time.sleep(0.2)
            data_received_from_Arduino = bus.read_i2c_block_data(slaveAddress, 0,12)
            print(data_received_from_Arduino)
            bus.write_byte(slaveAddress,3)
            print(StringToBytes(data_to_send_to_Arduino))
            bus.write_i2c_block_data(slaveAddress, 0x00,StringToBytes(data_to_send_to_Arduino))

Here is the serial and console output:

Arduino serial output:
    Conversation begin : sending 1 to PI
    PI Wants data[].
    PI Wants To say its ok.
    Data Received From PI:


Raspberry Pi console:
    1
    [0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
    [72, 101, 108, 108, 111, 32, 85, 110, 111]

How does it work?

  1. The Arduino sends a 1 to the Pi to initiate a two communication.
  2. The Pi sends back 1 to acknowledge.
  3. The Arduino then sends the data string to the Pi.
  4. The Pi receives the data and sends back 3 to the Arduino to say it went OK. (but it does not go ok).

The Pi then sends the data string to the Arduino, which I'm unable to read on the Arduino side, even though I tried.

My Questions

  • Why is the Raspberry Pi receiving 255 every where in the buffer?
  • How can the Arduino get the byte array sent from the Pi?
  • May I suggest you break this task down. Can you send any data successfully from the Pi to the Arduino? – joan Feb 20 '17 at 9:26
  • yes the arduino successfully sends initially the integer 1 and PI receives it. also the PI sends back the integer 1 which is received by arduino. but the string is not sent correctly. – dfeast Feb 20 '17 at 10:59
  • i am trying to achieve kind of interrupt based communication by sending and receiving certain integers through the i2c . e.g if arduino wants to send some string to PI. it initiate the process by sending 1 through the I2c bus. upon receiving 1 the PI sends an acknowledgment by sending 1 back to arduino and start reading the i2c bus for a block. after receiving 1 from PI arduino write the block of data to the wire. the PI sends 3 to arduino as a successful read. here PI reads the data bytes but they are all null. – dfeast Feb 20 '17 at 11:11
  • Remember that the Pi normally acts as the I2C bus master so all transfers must be initiated by the Pi. – joan Feb 20 '17 at 11:20
  • i have a gsm module installed on arduino and i want to save the incoming number and message by sending it to pi through i2c. how can i achieve this synchronization between arduino and PI? how can i tell the pi from arduino to read two blocks from i2c one containing number and one containing message. – dfeast Feb 20 '17 at 11:31
1

I discovered something like real interrupts triggered by the GPIO pins.

Here is how I solved it.

Pi.py

#!/usr/bin/python

import RPi.GPIO as GPIO
import smbus

slaveAddress = 0x12    
numberInterruptPIN = 19
messageInterruptPIN = 12

def readMessageFromArduino():
    global smsMessage
    data_received_from_Arduino = i2c.read_i2c_block_data(slaveAddress, 0,15)
    for i in range(len(data_received_from_Arduino)):
        smsMessage += chr(data_received_from_Arduino[i])

    print(smsMessage.encode('utf-8'))
    data_received_from_Arduino =""
    smsMessage = ""

def readNumberFromArduino():
    global smsNumber
    data_received_from_Arduino = i2c.read_i2c_block_data(slaveAddress, 0,15)
    for i in range(len(data_received_from_Arduino)):
        smsNumber += chr(data_received_from_Arduino[i])

    print(smsNumber.encode('utf-8'))
    data_received_from_Arduino = ""
    smsNumber = ""

smsMessage = ""
smsNumber = ""

if __name__ == '__main__':
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(numberInterruptPIN, GPIO.IN)
    GPIO.setup(messageInterruptPIN, GPIO.IN)

    i2c = smbus.SMBus(1)

    GPIO.add_event_detect(numberInterruptPIN, GPIO.RISING)
    GPIO.add_event_detect(messageInterruptPIN, GPIO.RISING)

    while 1:
        try:
            if GPIO.event_detected(numberInterruptPIN): 
                try:
                    readMessageFromArduino() 
                except IOError:
                    pass
            if GPIO.event_detected(messageInterruptPIN):
                try:
                    readNumberFromArduino()
                except IOError:
                    pass

        except KeyboardInterrupt:
               GPIO.cleanup()

Arduino.ino

#include <Wire.h>

static const char messageInterrupt = A1;
static const char numberInterrupt = 5;

int flag = 0;

void setup() {
    pinMode(numberInterrupt, OUTPUT);
    pinMode(messageInterrupt, OUTPUT);

    Serial.begin(9600);

    Wire.begin(0x12);
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);
    digitalWrite(numberInterrupt, LOW);
    digitalWrite(messageInterrupt, LOW);

    trigger_numberInterrupt();
    delay(100);
    trigger_messageInterrupt();
}

void loop() {}

void trigger_numberInterrupt() {
    digitalWrite(numberInterrupt, HIGH);
    flag = 2;
    delay(10);
    digitalWrite(numberInterrupt, LOW);
}

void trigger_messageInterrupt() {
    digitalWrite(messageInterrupt, HIGH);
    flag = 1;
    delay(10);
    digitalWrite(messageInterrupt, LOW);
}

void receiveData(int bytes) {}

void sendData() {
    if(flag == 2) {
      Wire.write("Hello foo");
      delay(1000);
    }

    if(flag == 1) {
        Wire.write("Hello bar");
        delay(1000);  //if no sync : add more delay.
    }

    flag = 0;
}

I have connected the GPIO pin 19 and 12 to the Arduino Pin 15 and 5. This works fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.