Arduino Uno + Raspberry Pi = I2C

Тема в разделе "Arduino & Shields", создана пользователем Pirantel, 19 авг 2013.

  1. Pirantel

    Pirantel Нуб

    Завязал Arduino Uno с Raspberry Pi v.2 по i2c, ардуино (slave),малина (master). На ардуино подключены два аналоговых датчика (датчик газа и датчик пламени), вопрос состоит в том, что нужно внести в код pythona чтобы он мог распознавать информацию отосланной ардуинкой.

    Думал отправлять с ардуино массив целочисленных (int) - но при компиляции выдает ошибку, можно только отсылать массив байтов (byte), но так как у них ограничение до 255, а датчики конечный свои результат выдает и свыше 1000.

    Просто особых навыков программирования на питоне не имею, старался гуглить больше, но мозгов пока хватило только на это. Может кто поможет?

    Предоставляю скет ниже :

    Код (C):

    #include <Wire.h> //библиотека i2c
    #define SLAVE_ADDRESS 0x04 // ардуино объявлена слейвом
    int gas = 0; // переменная газового датчика
    int flame = 0; // переменная датчика пламени
    int number = 0; // переменная

    void setup()
    {
      Serial.begin(9600); //Set serial baud rate to 9600 bps
      Wire.begin(SLAVE_ADDRESS);
      Wire.onReceive(receiveData);
      Wire.onRequest (sendData);
      Serial.println("Ready!");

    }

    void loop()
    {
      delay(1000);
    }

    void receiveData(int byteCount)
    {
      while(Wire.available()) {
        number = Wire.read();
      }
    }

    void sendData()
    {
      gas=analogRead(0);
      flame=analogRead(1);

      Serial.print("Gas in air: ");
      Serial.println(gas,DEC);
      Serial.print("Flame in air: ");
      Serial.println(flame,DEC);
      Wire.write(gas);
      delay(100);
      Wire.write(flame);
    }
     
    И код на Python-e (это уже скрипт для Малинки)

    Код (C):

    import smbus
    import time

    bus = smbus.SMBus(1)

    address = 0x04

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

    def readGas():
         gas = bus.read_byte(address)
         return gas

    time.sleep(0.1)
         
    def readFlame():     
         flame = bus.read_byte(address)
         return flame
         
    while True:
        var = input("Enter number: ")
        if not var:
          continue
        writeNumber(var)
       
      # sleep one second
        time.sleep(1)

        gas = readGas()
        flame = readFlame()

    print "Gas in the air: ", gas
    print
    print "Flame: ", flame
    print
     
     
  2. nailxx

    nailxx Официальный Нерд Администратор

    Направлене мысли совершенно правильное. Вам нужно лишь побить длинные int'ы на байты. Что-то вроде:

    Код (C):

    void sendData()
    {
      gas=analogRead(A0);
      flame=analogRead(A1);

      Wire.write(gas >> 8); // отправляем старший байт
      Wire.write(gas & 0xff); // отправляем младший
      delay(100);
      Wire.write(flame >> 8); // отправляем старший байт
      Wire.write(flame & 0xff); // отправляем младший
    }
     
    на малине:

    Код (Python):

    def readGas():
         gas = (bus.read_byte(address) << 8) | bus.read_byte(address)
         return gas
     
    И да, про I2C: вы точно не забыли решить проблему разницы уровней? На Arduino 5 В, а на GPIO Raspberry 3,3 В. Если на Raspberry прилетит 5 В с Arduino, ей это вряд ли понравится.
     
    Pirantel нравится это.
  3. Pirantel

    Pirantel Нуб

    Мне тоже советовали эту методику решения проблемы, просто не мог представить это в виде кусочка кода, не понимал логику функций библиотеки smbus на малинке :( Благодарю вас, а насчет разницы логики, то это не проблематична, в том случае, если Малина - мастер, а ардуино - слэйв (как в моем случае), так как ардуино не имеет никаких подтягивающих резисторов, а малинка на p1 имеет на 1кОм (+3.3в).

    З.Ы Кстати, хотел поинтересоваться, вы это написали с помощью какой нибудь справочной информации, или по собственному опыту? а то бы я не прочь почитать материальчик :) если он есть, конечно.

    Update: Я хочу обучить малинку, чтобы она принимала сигналы "аналоговые" от ардуинки, несящие в себе результаты показаний датчиков, и в последующем ее внесение в базу Mysql, которая уже стоит на Малинке, поднят веб-сервер, и поддержка пхп присутствует. Проблема в том, что как можно подккоректировать функции библиотеки MySQLdb, так чтобы вносились (обновлялись) и результаты показаний определенного датчика и время его фиксации. А в web-морде я уже буду их "выдергивать" в веб-интерфейс, что конечно не составит особого труда. :)

    Кто хорошо разбирается в Питоне, оссобенно в его библиотеке MySQLdb? Будьте добры, помогите!

    База: Data ; Таблицы: Gas и Flame; и в каждой таблице два столбца - value и data.

    Код (C):

    #!/usr/bin/python
    # -*- coding: utf-8

    import smbus
    import time
    import datetime
    import MySQLdb
    import cgi

    bus = smbus.SMBus(1)

    address = 0x04

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

    def readGas():
         gas = (bus.read_byte(address) << 8) | bus.read_byte(address)
         return gas

    time.sleep(0.1)
         
    def readFlame():     
         flame = (bus.read_byte(address) << 8 | bus.read_byte(address)
         return flame
         
    while True:
        var = input("Enter number: ")
        if not var:
          continue
        writeNumber(var)
       
      # sleep one second
        time.sleep(1)

        gas = readGas()
        flame = readFlame()

    def mysqlConnect():
        db = MySQLdb.connect(host="localhost", user="pi", passwd="*****", db="Data", charset='utf8')
        cur = db.cursor()
        cur.execute('SET NAMES `utf8`')
       
        data = {};
        data['gas_value'] = cgi.escape (gas, True);
        data['flame_value'] = cgi.escape (flame, True);

        cur.execute =("""INSERT INTO gas('gas_value') VALUES);
        cur.execute =("
    ""INSERT INTO flame('gas_value') VALUES);
           
            cur.close()
            db.close()
     
     
  4. denis-odegov

    denis-odegov Нуб

    всем привет! я застрял на более низшем уровне и поэтому прошу помощи!
    идея примерна та же: из формы ПХП передавать ПИТОНУ данные, а Питоновый скрипт уже связывается с ардуиной по i2c. Через IDLE все работает, а если запускать через браузер, то не работает. И выполнение скрипта останавливается на строчке bus = smbus.SMBus(1)
    так же могу сказать, что не работает в браузере такая строчка var = input("Enter number: "). INPUT игнорится :(
    мне кажется что проблемы где-то рядом....
     
  5. vipace

    vipace Нуб

    а как ардуина с распбери связана? Можно поподробнее?
     
  6. lfat66

    lfat66 Нуб

    Доброго времени суток All!
    Подниму тему, потому как внятного результата в экспериментах получить не удалось.
    Проблема в том, что с малинку в ардуино я могу отправить несколько байт и там их получить.
    Но вот отправляя в ответ с ардуины в малинку несколько байт, на малинке получаю только последний байт.
    Причин пока понять не могу.
    Вот скетч на ардуине:

    Код (C++):
    #include <Wire.h>

    #define SLAVE_ADDRESS 0x04
    int number = 0;
    int state = 0;
    byte dat[2];
    byte num=0;
    byte num1=0;
    byte num2=0;

    void setup() {
      pinMode(13, OUTPUT);
      Serial.begin(19200); // 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 555!");
    }

    void loop() {
      delay(100);
      if( state==1 ) {
            Serial.println( "--------------------" );
            state=0;
      }
    }

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

      while(int n=Wire.available()) {
        number = Wire.read();
        if( num==0 ) { num1=number; num=1; }
        else if( num==1 ) { num2=number; num=0; number=num1 + (num2<<8); }
        else num=0;
      }
    }

    // callback for sending data
    void sendData(){
        Serial.println(number);
        Wire.write(number);
    }
    Вот код на малинке в питон3
    Код (Python):
    #!/usr/bin/python3

    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, int(value)&0xFF)
        bus.write_byte(address, int(value)>>8)
    #    bus.write_byte(address, value.to_byte(2, byteorde='big'))  # Рабочий вариант
    #    bus.write_byte_data(address, 0, ord(value))
        return -1

    def readNumber():
    #    num = bus.read_byte(address)
        num = (bus.read_byte(address) << 8) | bus.read_byte(address)
        return num

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

        writeNumber(var)
        print( "RPI: Привет Arduino, Я послал тебе  ", var)
    # sleep one second
        time.sleep(1)

        number = readNumber()
        print( "Arduino: Привет RPI, Я ответил тебе 1: ", number )
        number = readNumber()
        print( "Arduino: Привет RPI, Я ответил тебе 2:", number )
        number=0
        print
     
    В этом коде с малинки отправляется введённое число, в ответ ардуина отправляет это число обратно.
    Непоняток две:
    1. На ардуину приходит 3 байта. 3-й байт повторяет 2-й
    2. На малинку возвращается только последний байт.