NicolasColsoul
NicolasColsoul

Reputation: 31

Arduino as I2C slave talk to RPi

I use an Arduino as I2C slave to treat some Ultrasonic sensors and send revelant data to a Raspberry. The code running on Arduino :

void setup() {
  // initialize i2c as slave
  Serial.begin(9600);
  Wire.begin(SLAVE_ADDRESS);
  // define callbacks for i2c communication
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);

  // useless
}

void loop() {
    // useless
} 

// callback for received data
void receiveData(int byteCount) {
  int i = 0;
  while (Wire.available()) {
    number[i] = (char) Wire.read();
    i++;
  }
  number[i] = '\0';
  Serial.println(atoi(number));
  if(atoi(number) != 0) { caseN = atoi(number); }
}  

int SonarSensor(int trigPin,int echoPin)
{
    // uselesss
}

// callback for sending data
void sendData() {
  if(caseN == 1) { Wire.write(distance1);}
  else if(caseN == 2) { Wire.write(distance2);}
  else if(caseN == 3) { Wire.write(distance3);}
  else if(caseN == 4) { Wire.write(distance4);}
  else if(caseN == 5)
  {
    if(state == 0)
    {
      state = 1;
      digitalWrite(ledPin, HIGH);
    }
    else
    {
      state = 0;
      digitalWrite(ledPin, LOW);
    }
  }
  else { Wire.write(0); }
}

I do a first version of the bus "chat" with Python and it works very well :

import smbus
import time

bus = smbus.SMBus(1)


address = 0x04

def writeNumber(value):
    bus.write_byte(address, value)
    return -1

def readNumber():
    number = bus.read_byte_data(address, 1)
    return number

while True:
    data = raw_input("Enter the data to be sent : ")
    data_list = list(data)
    for i in data_list:
        writeNumber(int(ord(i)))
        time.sleep(.1)

    writeNumber(int(0x0A))

I am trying to do the same in C but it looks a little bit more difficult :

#include "i2c-dev.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <string.h>

int main() {
    const int adapter_nr = 1;
    char filename[20];
    snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
    const int file = open(filename, O_RDWR);
    if (file < 0) {
        printf("Unable to connect to Atmega, I2C plugged ? DC ok ?");
        exit(EXIT_FAILURE);
    }

    // Atmega address
    const int addr = 0x04;

    if(ioctl(file, I2C_SLAVE, addr) < 0) 
    {
        printf("Fail to reach Atmega");
        exit(EXIT_FAILURE);
    }

    const __u8 add = 5; // Ask to "distance 5"
    i2c_smbus_write_byte_data(file, 0x04, add); // What is the adress ?


    const __u8 reg = 0x0A;
    const __s32 result = i2c_smbus_read_byte_data(file, reg);
    if(result < 0) 
    {
        printf("Fail to reach Atmega reg");
        exit(EXIT_FAILURE);
    } 
    else 
    {
        printf("Distance %d cm \n", result);
    }

    close(file);

    return(EXIT_SUCCESS);
}

As I mentionned in the code, I don't know which register adress my Arduino slave has. I can see in the Arduino COM terminal a lot of 0 and only 0.

I hope you will understand my problem. Thanks.

Upvotes: 2

Views: 327

Answers (2)

I A
I A

Reputation: 81

You need to know the correct I2C slave address that your Arduino is using.

Luckily, Raspberry Pi has can detect any I2C device connected and show you their address using the following command:

sudo i2cdetect -y 1

or

sudo i2cdetect -y 0

Note: The first command works for all the latest Raspberry Pi3 and Pi2 (models A, B, B +) and Pi Zero. The second command is only if you are using older models.

For more information you can have a look at here (Enable I2C) or here (Configuring I2C). Both are similar and you can just skip to the bottom where they explain how to use the above command.

Upvotes: 0

Hojo.Timberwolf
Hojo.Timberwolf

Reputation: 1091

Why not define the slave address so you will know exactly what it is. Plus this will allow you to set different address if in the future you use more than 1 arduino.

Run this line of code before Setup on the arduino. You can change the address to anything you want as long as it isn't used by another system on the I2C connection.

#define  SLAVE_ADDRESS           0x29  //slave address,any number from 0x01 to 0x7F

Here is a Tutorial discussing using Arduino as a slave

Upvotes: 0

Related Questions