Arduino Raspberry Pi I2C коммуникация

laviritel
Offline
Зарегистрирован: 07.01.2014

Добрый день!

Делаю систему которая следит за дверьми и окнами. На концах стоят герконы, а на рамах магниты. Если дверь открыли, то цепь размыкается и на входе (12 пин) ардуины (UNO) логический ноль.

Ардуина у меня соеденена с Raspberry Pi по средствам I2C. Вот собственно с этим и есть проблема. У меня была идея, на ардуине проверять входы (состояние герконов) и их показания записывать в массив байтов. Записать данные в массив не проблема, но вот как передать эти данные Raspberry и как их прочитать в  Python на Raspberry никак не могу понять. С одним датчиком проблем нет, но вот с массивом беда.

Вот мой код для Arduino:

#include <Wire.h>
#define SLAVE_ADDRESS 0x04
int state = 0;
int Command =99;
/*
Available commands:
  99 - DEFAULT: Nothing to do
  1 - CHECK DOORS
*/
int mainDoorPin = 12;
int ledPin = 13;
byte systemState[8];
void setup(){
 pinMode(ledPin,OUTPUT);
 Serial.begin(9600);
 Wire.begin(SLAVE_ADDRESS);
 
 digitalWrite(ledPin,LOW);
 Wire.onReceive(receiveData);
 Wire.onRequest(sendData);
}

void loop()
{
 delay(100); 
}

void receiveData(int byteCount)
{
 while (Wire.available()) {
  Command = Wire.read();
 }
 Serial.print("Received value: ");
 Serial.println(Command);
 switch (Command){
   case 99:
     //Set system to initial state
     Serial.println("Initial state...");
     systemState[0]=0;
     systemState[1]=0;

     break;
   case 1: 
    Serial.println("Checking doors");
    checkDoors();
    break;
 }
}

void checkDoors()
{
  if(systemState[0] == 0){
    systemState[0] = digitalRead(mainDoorPin);
    systemState[1] = 0;
  }
}
void sendData(){
  Wire.write(systemState,sizeof(systemState));
}

 

Как видно из кода, в массиве systemState у меня два значения и отправляю я Raspberry я этот массив, но получаю только первое значение.

 вот для Python:

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(address))
        return number

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

        writeNumber(var)
        print "RPI: Hi Arduino, I sent you ", var

        time.sleep(1)

        number = readNumber()

        print "Arduino: Hey RPi, I received a digit ", number
        print

Перерыл уже весь интернет, ничего не нашел. Может кто-то сталкивался, как в Python прочитать массив байтов полчаемый по I2C. Или может кто на толкнет, что почитать. Спасибо.

inspiritus
Offline
Зарегистрирован: 17.12.2012

А почему ббы Вам не использовать напрямую GPIO малинки, их там много ... Проблемы с 3.3в  ? Их решить несложно... Прощщее, чем изобретать протокол для и2с...

laviritel
Offline
Зарегистрирован: 07.01.2014

Как то изначально не хотелось использовать машинку для этого. На малине хотелось только обрабатывать данные полученные от ардуины, и запихивать их в БД. Это раз. А второе, интересней связать два устройства и наладить связь между ними. Может видел кто статью или какой другой материал? Можно и на английском. Спасибо.

Vasia.Z
Vasia.Z аватар
Offline
Зарегистрирован: 30.11.2013

http://wiringpi.com/reference/i2c-library

гляньте на это 

 

laviritel
Offline
Зарегистрирован: 07.01.2014

Vasia.Z пишет:

http://wiringpi.com/reference/i2c-library

гляньте на это 

Спасибо. Судя повсему, это поможет, есть возможность считать 16-и битовое значение :)

vipace
Offline
Зарегистрирован: 09.02.2016

А можно поподробнее как Raspberry Pi и Arduino связаны?

Vasia.Z
Vasia.Z аватар
Offline
Зарегистрирован: 30.11.2013

vipace пишет:

А можно поподробнее как Raspberry Pi и Arduino связаны?

>Ардуина у меня соеденена с Raspberry Pi по средствам I2C.

Если написано i2c - значит

- sda ардуины подключен к sda распбери

- scl ардуины подключен к scl распбери

- земля ардуины соединена с землей распбери

Согласование уровней - нужно

vipace
Offline
Зарегистрирован: 09.02.2016

тоесть 2 ардуины к одному распбери не подключить?

vipace
Offline
Зарегистрирован: 09.02.2016

хотел использовать распбери как сервера ардуины как улиенты обрабатывающие инфу от датчиков

Vasia.Z
Vasia.Z аватар
Offline
Зарегистрирован: 30.11.2013

Разрешаю подключить. 
А если серьезно, почитайте про i2c.
Можно подключить, конешн.

vipace
Offline
Зарегистрирован: 09.02.2016

почитать я почитал, но страшновато эксперементировать

kutdusov
Offline
Зарегистрирован: 05.02.2020

Подниму среди уважаемых читателей тему.
Пытался повторить разные варианты с разных источников,
но не всё гладко в нашем королевстве.

Так что есть повод поделиться опытом и по обсуждать.
Итак! Имеем:

Arduino Pro Mini (на самом деле неважно какая) с програмированием в Arduino IDE 1.8.9 (в общем случае тоже неважно)
Raspberry Pi3 (так же неважно какая)  с программированием на Python3 (на самом деле очень важно, потому что Python3 и все предыдущие версии отличаются крайне сильно.

Сразу же скажу, что если с arduino я знаком достаточно давно, то с raspberry и языком программирования Python3 знаком не сильно.

Задача: Отправить несколько байт с малинки на ардуину, в ответ получить несколько байт с ардуины обратно в малинку. Ради унификации, хотелось бы на ардуине использовать универсальны скетч из проекта ESPEasy https://www.letscontrolit.com/wiki/index.php?title=ProMiniExtender

Если внимательно глянуть, то в этом скетче ардуино по i2c принимается команда из 4-х байт. В ответ посылает 0-2 байта как результат.

Для начала, просто попробуем послать число в INT (2 байта). Теперь что получаю и с чем столкнулся в процессе отладки:
Послать Raspberry - > Arduino 2 байта достаточно просто:

#!/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

На ардуино принимаем и отправляем обратно:

#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);
}

В итоге получается какая-то фигня.
С малинки улетает не 2 а 3 байта. 3-йбайт является повторением 2-го. Ладно. На ардуино принимает 3 байта, последний отбрасываем.
Отправляем обратно:
Wire.write(number);
(можно и разбив на 2 байта, без разницы)
или так:
Wire.write(number&0xFF);
Wire.write(number>>8);
Без разницы. На малинку прилетает ТОЛЬКО последний байт.

Я уже голову сломал.

Что многоуважаемый All может сказать на эту тему: Может у кого-нить уже есть достойная повторения реализация многобайтной передачи между этими двумя дейвайсами?