Как читать данные из Arduino с помощью Raspberry Pi с I2C

Я пытаюсь прочитать данные из Arduino UNO в Raspberry Pi с помощью модуля python smbus. Единственная документация, которую я смог найти по модулю smbus, - это здесь. Я не уверен, что означает cmd в модуле. Я могу использовать запись для отправки данных в Arduino. Я написал две простые программы: одну для чтения, а другую - для записи.

Тот для записи

import smbus
b = smbus.SMBus(0)
while (0==0):
    var = input("Value to Write:")
    b.write_byte_data(0x10,0x00,int(var))

Тот для чтения

import smbus
bus = smbus.SMBus(0)
var = bus.read_byte_data(0x10,0x00)
print(var)

Код Arduino:

#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
#include <Wire.h>
LiquidCrystal lcd(8,9,4,5,6,7);

int a = 7;

void setup() 
{ 
  Serial.begin(9600);
  lcd.begin(16,2);
  // define slave address (0x2A = 42)
  #define SLAVE_ADDRESS 0x10

  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);

  // define callbacks for i2c communication
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData); 
}
void loop(){
}

// callback for received data
void receiveData(int byteCount) 
{
 Serial.println(byteCount);
  for (int i=0;i <= byteCount;i++){
  char c = Wire.read();
  Serial.println(c);
 }
}

// callback for sending data
void sendData()
{ 
  Wire.write(67);
  lcd.println("Send Data");
}

Когда я запускаю программу чтения, она каждый раз возвращает «33». Arduino возвращает, что вызывается функция sendData.

Я использую сдвиг уровня данных, и в описании говорится, что он может быть немного медленным.

Кто-нибудь заставил это работать?


person TheGreenToaster    schedule 20.01.2013    source источник


Ответы (2)


Мне удалось инициировать связь между Arduino и Raspberry Pi. Эти два соединены с помощью двух подтягивающих резисторов 5 кОм (см. Эту страницу). Arduino записывает байт на шину i2c для каждого запроса. На Raspberry Pi hello печатается каждую секунду.

Код Arduino:

#include <Wire.h>
#define SLAVE_ADDRESS 0x2A

void setup() {
    // initialize i2c as slave
    Wire.begin(SLAVE_ADDRESS);
    Wire.onRequest(sendData); 
}

void loop() {
}

char data[] = "hello";
int index = 0;

// callback for sending data
void sendData() { 
    Wire.write(data[index]);
    ++index;
    if (index >= 5) {
         index = 0;
    }
 }

Код Python на Raspberry Pi:

#!/usr/bin/python

import smbus
import time
bus = smbus.SMBus(1)
address = 0x2a

while True:
    data = ""
    for i in range(0, 5):
            data += chr(bus.read_byte(address));
    print data
    time.sleep(1);

На моем Raspberry Pi шина i2c равна 1. Используйте команду i2c-detect -y 0 или i2c-detect -y 1, чтобы проверить, обнаруживает ли ваш Raspberry Pi ваш Arduino.

person StebQC    schedule 26.01.2013

Я знаю, что это старый пост, но у меня был аналогичный успех, и мне показалось, что это место для спуска, чтобы добавить мой успех.

Я давно пытался переложить расчет высоких оборотов на ATTiny85. Я хотел отправить RPM по запросу i2c на Pi, а не использовать прерывание вывода GPIO и время процессора на Pi. Я наконец-то добился этого сегодня. Вот что я придумал. Надеюсь, это может кому-то помочь. Если кто-то хочет раскритиковать мой код, действуйте!

Ino-код AtTiny 85: тактовая частота 1 МГц

#include <TinyWire.h>

//            _____
//     RST  -|o AT |- VDD (1.8-5.5v)
//   A3/D3  -| Tiny|- D2
//   A2/D4  -|  85 |- D1     (PWM)  Can use analogWrite(pin_0_or_1, 255);
//     GND  -|_____|- D0 SDA (PWM)  on pwm pins. (8 bit resolution=0-255)

#define own_address 0x26    // I2C address - change this in arduino code if changed
#define LED_pin 4 
#define hallPin 3 //Melexis US5881 Hall Effect Sensor  (Put a 50K Ohm pull up resistor
                  //                                    between VDD and OUT pins
bool pulseState = false;
const int sample_rate_ms = 1000;

volatile uint32_t timeCheck = 0;  //uint32_t is same as "unsigned long"

volatile uint32_t pulse1 = 0;  //uint32_t is same as "unsigned long"
volatile uint32_t pulse2 = 0;  //uint32_t is same as "unsigned long"    

volatile uint8_t i2c_regs[2] = { 0, 0 };
volatile uint16_t RPM = 0; 
volatile int counter = 0;   //int is same as short

void setup() {
  pinMode(LED_pin, OUTPUT);      // If you want to enable an LED for status.
  pinMode(hallPin, INPUT);       
  digitalWrite(LED_pin, HIGH);   // Turn on the LED to indicate alive status
  delay(2000);                   // Leave it on for 2 seconds
  digitalWrite(LED_pin, LOW);    // Turn it off
  
  TinyWire.begin( own_address );
  TinyWire.onRequest( onI2CRequest );
  
  timeCheck = millis() + sample_rate_ms;   // Set a time in the future to calculate
  pulse1 = micros();                       // Take an initial time hack
  sei();     // Enable interrupts
}

void loop() {
  if (digitalRead(hallPin)!=pulseState){       // Look at the hall state
    pulseState = !pulseState;                  // If the pin isn't what it was before
    if (!pulseState){                          // Check if the pin was pulled low
      pulse1 = pulse2;                         // Start time was previous pulse
      pulse2 = micros();                       // End time is this pulse  
      ++counter;                               // Count pulses for determining 0 RPM
      delay(0.0016);                           // Wait for 1/600th of a second (to 
                                               //  prevent bounces) Should be good up 
                                               //  to about 20,000rpm. This may not be
    }                                          //  necessary but it works.
  }

  if(millis() > timeCheck){   // Every so often (once per second in my code)
                              // calculate RPM or lack thereof. 
        timeCheck = millis() + sample_rate_ms;
        if (counter < 2){     //  Less than 2 pulses, it's not rotating
          RPM = 0;
        }else{
          RPM = 60000000 / (pulse2 - pulse1);  // Revs per minute at 1000000 ticks per 
                                               // second using micros()
        }
        i2c_regs[0] = (RPM & 0xFF00) >>8;    // Prepare the two bytes to send
        i2c_regs[1] = (RPM & 0x00FF);        // and place them into an array
        counter = 0;                         // Reset the counter for the next loop
     }
  }
void onI2CRequest() {
  TinyWire.send(i2c_regs, sizeof(i2c_regs));   // Send the two bytes over i2c
}

Вот код Raspberry Pi Python 3:

from smbus2 import SMBus, i2c_msg
# https://pypi.org/project/smbus2/
# To install on raspberry pi execute the following:
# pip install smbus2
# or 
# sudo python3 -m pip install smbus2
# or
# sudo python3 -m pip3 install smbus2

import time
from datetime import datetime, timedelta


def bytes_to_int(bytes):
    result = 0

    for b in bytes:
        result = result * 256 + int(b)

    return result

def int_to_bytes(value, length):
    # This routine is unused for now
    result = []

    for i in range(0, length):
        result.append(value >> (i * 8) & 0xff)

    result.reverse()

    return result


last_good_data_at = datetime.utcnow()
with SMBus(1) as bus:
    address=0x26
    while True:
     
        time.sleep(0.25)

        try:
            read = i2c_msg.read(address, 2)
            bus.i2c_rdwr(read)
            bytes = list(read)
        except:
            bytes = []

        if bytes:
            last_good_data_at = datetime.utcnow()
            rpm = bytes_to_int(bytes)

            print(f"                     " + "\r", end="")
            print(f"RPM: {rpm}   Bytes: {bytes}" + "\r", end="")

        elif datetime.utcnow() > last_good_data_at + timedelta(seconds=10):
            break
    print("No data received for 10 seconds.")
    print("Terminating program")
person James Hunt    schedule 23.11.2020