2016年3月2日 星期三

Raspberry Pi: Connected Arduino Using I2C

since: 2016/02/25
update: 2016/03/03

reference:
1.Raspberry Pi and Arduino Connected Using I2C - OscarLiang.net
2. [I2C] onRequest and onReceive as slave with Raspberry Pi Master

A. 檢查 Raspberry Pi:
   
1. Linux 版本

    $ uname -a
Linux raspberrypi 4.1.17-v7+ #843 SMP Mon Feb 15 23:35:33 GMT 2016 armv7l GNU/Linux

    2. python 版本
    $ python -V
Python 2.7.9

-----------------------------------------------------------------------------------------------

B. 安裝 I2C 與 python相關套件:
    $ sudo apt-get install python-smbus
    $ sudo apt-get install python3-smbus // for python3
    $ sudo apt-get install i2c-tools

    // check
    $ sudo aptitude search smbus
p   pypy-smbus-cffi        - This Python module allows SMBus access through the I2C /dev              
i   python-smbus            - Python bindings for Linux SMBus access through i2c-dev                   
v   python2.7-smbus      -                                                                          
i   python3-smbus          - Python 3 bindings for Linux SMBus access through i2c-dev


-----------------------------------------------------------------------------------------------

C. 安裝 I2C 的 Kernel Support:
     $ sudo raspi-config
        > 9 Advanced Options

        > A7 I2C

        > Yes
       ....
        > Yes

-----------------------------------------------------------------------------------------------

D. 檢查設定(選擇性)
     $ cat /etc/modules
....
i2c-dev
    
     $ cat /etc/modprobe.d/raspi-blacklist.conf
# ...
# ...


    $ cat /boot/config.txt
....
dtparam=i2c_arm=on

    $ cat /etc/group | grep i2c
i2c:x:998:pi
      // $ sudo adduser pi i2c

-----------------------------------------------------------------------------------------------

E. I2C 測試:
    $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- 


    $ ls /dev/i2c*
/dev/i2c-1
-----------------------------------------------------------------------------------------------

F. Arduino Code:
#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int number = 0;
int state = 0;

void setup() {
    pinMode(13, OUTPUT);
    Serial.begin(9600); // start serial for output
    // initialize i2c as slave
    Wire.begin(SLAVE_ADDRESS);

    // define callbacks for i2c communication
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);
    //Serial.println(“Ready!”);
}

void loop() {
    delay(100);
}

// callback for received data
void receiveData(int byteCount){

    while(Wire.available()) {
        number = Wire.read();
        //Serial.print(“data received: “);
        //Serial.println(number);


        if (number == 1){

            if (state == 0){
                digitalWrite(13, HIGH); // set the LED on
                state = 1;
            }
            else{
                digitalWrite(13, LOW); // set the LED off
                state = 0;
            }
        }
    }
}

// callback for sending data
void sendData(){
    Wire.write(number);
}


-----------------------------------------------------------------------------------------------

G. Raspberry Pi's  Python Code:
#!/usr/bin/python
#encoding: utf-8

import smbus
import time

# for RPI version 1, use "bus = smbus.SMBus(0)"
bus = smbus.SMBus(1)

# This is the address we setup in the Arduino Program
address = 0x04

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

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

while True:
    var = input("Enter 1 – 9:")
    if not var:
        continue

    writeNumber(var)
    print "RPI: Hi Arduino, I sent you ", var
    # sleep one second
    time.sleep(1)

    number = readNumber()
    print "Arduino: Hey RPI, I received a digit ", number
    print


-----------------------------------------------------------------------------------------------

H. 備註:
When we use read_i2c_block_data(), It was too fast to write a command byte and read the data.

In that time, if we use Serial.println() to print log to serial. Arduino will can not follow the speed. and it missing the i2c read flag.

So, the dataReceive() funtion will not be run at all.

The solution is simple: just do not use Serial library until the i2c is free.

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。