Как да четем данни от 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.

Използвам Data Level Shifter и описанието казва, че може да е малко бавен.

Някой карал ли е това да работи?


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


Отговори (2)


Успях да инициирам комуникация между Arduino и Raspberry Pi. Двете са свързани с помощта на два издърпващи резистора 5k (вижте тази страница). 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

Знам, че това е стара публикация, но имах подобен успех и това изглеждаше като място за слизане, за да добавя успеха си.

Опитвам се да разтоваря изчисляването на високи RPM към ATTiny85 от дълго време. Исках да изпратя RPM при i2c заявка към Pi, вместо да използвам прекъсване на GPIO пин и процесорно време на pi. Днес най-накрая постигнах това. Ето какво измислих. Надявам се, че може да помогне на някого. Ако някой иска да критикува моя код, нека го направи!

AtTiny 85 ino код: 1 Mhz тактова честота

#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