Arduino:
To get I2C running on the Arduino is really easy with the "Wire" library. http://arduino.cc/en/Reference/Wire
My use of the library is the Arduino as the slave.
First you will need to import the wire library
- Code: Select all
#include "Wire.h"
Also in the header part of the Arduino code you will need to define you slave address for the Arduino (if you using the Adruino as the slave if not then no need for a address define)
- Code: Select all
#define SLAVE_ADDRESS 0x2A
We also need an Array for the receiving data that is coming in from the master.
char thisArray[7];
In the "Setup" code you will initialize the i2c communication.
first we need to use the
- Code: Select all
being()
- Code: Select all
Wire.begin();
- Code: Select all
Wire.begin(SLAVE_ADDRESS);
I personally like to define events instead of just looping though in a conditional loop.
So in the "Setup" I also define the "onRecieve" event and the "onRequest" event. You pass into them the method to call as the arg.
- Code: Select all
Wire.onReceive(recData);
- Code: Select all
Wire.onRequest(sendData);
So now we have the "setup" finished we need to define the two methods we used as arg's.
The "onReceive" pass in the number of bytes being read from the master as an int.
so we are defining our method signaure as
- Code: Select all
void recData(int bytesIn)
I used a byte indexer for the incoming data.
- Code: Select all
Byte index = 0;
Here we will use a while loop to keep recieving data as its coming into us.
- Code: Select all
while(Wire.available())
While we are inside the loop we will read in the data into the array we create earlyer and increase the indexer as we go though the data.
- Code: Select all
{
thisArray[index] = Wire.read();
index++;
}
Now depending on your use you can use this data or as I wanted is a usable string for a later switch condition. So I also in the recData method I create a array to string loop
- Code: Select all
String array_ ="";// this can be a global define or a local depending on you useage of it.
for(int i = 1; i <= byteCount -1; i++)
{
array_ += thisArray[i];
}
Now for the reply method "sendData".
Its singure has no arg's. so it will be
- Code: Select all
void sendData()
its up to your app what you reply with but here we are just replying with a single
byte to the master.
- Code: Select all
{
Wire.write(1);
}
So the Arduino code put all together looks like this.
- Code: Select all
#include "Wire.h"
#define SLAVE_ADDRESS 0x2A
char thisArray[7];
void setup()
{
Serial.begin(9600);
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);
// define callbacks for i2c communication
Wire.onReceive(recData);
Wire.onRequest(sendData);
}
void loop()
{
}
void recData(int byteCount)
{
byte index = 0;
while(Wire.available())
{
thisArray[index] = Wire.read();
index++;
}
String array_ ="";
for(int i = 1; i <= byteCount -1; i++)
{array_ += thisArray[i];}
Serial.println(array_);
}
void sendData()
{
Wire.write(0);
}
now for the Raspberry Pi
Raspberry Pi:
By default I2C is disabled on the Pi. Instead of explaining the steps here to enable it. This link will explain it for me http://www.instructables.com/id/Raspberry-Pi-I2C-Python/step2/Enable-I2C/
So we will start with the belief you have i2c ready to go on the Pi.
There was plenty of c, c++ code for I2C to use, But I wanted to use Python as my controlling language. There is a library for python and i2c called "quick2wire" and it looks ok, but I thought it looked as complex as just writing the code without the library.
I am choosing to keep it simple in this example to show how it can work.
Just to make sure you know something about python it is indentation based.
So lets do our imports
we need smbus and time for this example.
- Code: Select all
import smbus
import time
Now we need to define a instance of smbus and pass in the I2c bus of the raspberry pi.
- Code: Select all
bus = smbus.SMBus(0)
Now we will define our address of the slave (the Arduino)
- Code: Select all
slave_address = 0x2a
We are going to define three methods for us to call in a endless loop.
The first one is call stringtobytes, it coverts the string passed into it to bytes.
- Code: Select all
def stringtobytes(val):
retval = []
for c in val:
retval.append(ord(c))
return retval
next we will create our write to slave function. We first define our message, then convert it to bytes and then send it to the slave.
- Code: Select all
def helloSlave(input):
message = stringtobytes(input)
bus.write_i2c_block_data(address,0,message)
Our next one is our read function. It just reads the incoming byte.
- Code: Select all
def read():
info = bus.read_byte_data(address,0)
return info
Now we have our functions we will write our endless loop and just to show the usage of the functions. So our complete python script will look like this
- Code: Select all
import smbus
import time
bus = smbus.SMBus(0)
slave_address = 0x2a
def stringtobytes(val)
retval = []
for c in val:
retval.append(ord(c))
return retval
def helloSlave(input):
message = stringtobytes(input)
bus.write_i2c_block_data(address,0,message)
def read()
info = bus.read_byte_data(address,0)
return info
# this is the endless loop
while True:
helloSlave("hey")
time.sleep(0.7)
print read()
If you use this sample codes you should see "hey" in the Arduino serial screen
and a 0 in the Pi terminal screen.
If you have any question let me know and I will help as much as I can. Also please over look any goofy grammar errors plz.
Dan