繁体   English   中英

如何使用带有 I2C 的 Raspberry Pi 从 Arduino 读取数据

[英]How to read data from Arduino with Raspberry Pi with I2C

我正在尝试使用 python smbus 模块将数据从 Arduino UNO 读取到 Raspberry Pi。 我能在 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 函数。

我正在使用数据电平转换器,描述说它可能有点缓慢。

有没有人让这个工作?

我设法启动了 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 代码:

#!/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 0i2c-detect -y 1来验证您的 Raspberry Pi 是否检测到您的 Arduino。

我知道这是一篇旧帖子,但我也取得了一些类似的成功,这似乎是我的成功的后裔。

很长一段时间以来,我一直试图将高 RPM 的计算转移到 ATTiny85 上。 我想将 i2c 请求上的 RPM 发送到 Pi,而不是在 pi 上使用 GPIO 引脚中断和处理器时间。 我今天终于完成了。 这是我想出的。 希望它可以帮助某人。 如果有人想批评我的代码,那就来吧!

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
}

这是树莓派 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")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM