繁体   English   中英

如何通过I2C使用Raspberry pi从Arduino读取数据

[英]How to Read Data from Arduino with Raspberry pi via I2C

我已通过双向液位转换器将Raspberry pi 2 B型与arduino uno连接。

Raspberry pi    GND    ----------   GND     Arduino
                3.3v   ----------   5v
                SCL    ----------   A5
                SDA    ----------   A4

希望我的I2C连接正确吗?

我的Arduino已连接到8通道中继板。

现在,我已经编写了可以通过Raspberry pi控制中继板的代码。 例如,如果我按“ 1”,则继电器1变高。

现在,我想将数据从arduino发送回覆盆子pi,以便交叉检查Relay 1是否为高电平,如果Relay 1为高电平,则应该将一些数据发送回Raspberry pi或否则。

我的Rpi代码是

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, value)
    # bus.write_byte_data(address, 0, value)
    return -1

def readNumber():
    number = bus.read_byte(address)
    # number = bus.read_byte_data(address, 1)
    return number

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

    writeNumber(var)
    number = readNumber()

我的Arduino代码:

#include <Wire.h>

#define SLAVE_ADDRESS 0x04
#define RELAY1 9

int number = 0;
int state = 0;

void setup() {
    pinMode(RELAY1, OUTPUT);

    Serial.begin(9600); // 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!");
}

void loop() {
    delay(100);
}

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

    while(Wire.available()) {
        number = Wire.read();
        Serial.print("data received: ");
        Serial.println(number);

        if (number == 1){

            if (state == 0){
                digitalWrite(RELAY1, HIGH); // set the LED on
                state = 1;
            }
            else{
                digitalWrite(RELAY1, LOW); // set the LED off
                state = 0;
            }
        }
    }
}

// callback for sending data
void sendData(){
    Wire.write(number);
}

现在,如果我键入1并且由于连接松动,中继1不会变高,那么在这种情况下,我希望arduino每次从中继板上获取数据并将其发送到Raspberry pi。

如果有人也可以解释它是如何工作的,那就太好了。

希望我能解释这个问题。 我做了很多研究,但找不到答案。

我是python的初学者,所以请帮助我。

提前致谢。

问题在于,您在receiveData里面做的太多了,这是从I2C实用程序代码twi.c的中断服务例程twi.c 必须快速处理数据,并且不要调用任何其他取决于使能中断的例程(在此ISR期间它们被禁用)。

这意味着您不能调用Serial.print ,也不能调用任何其他Wire发送方法。 甚至不鼓励调用millis()micros() ,因为它们确实花费大量时间,并且它们依赖于正在处理的TIMER中断。

当然,您可以免费调用Wire.available()Wire.read() 实际上, byteCount告诉您有多少字节可用,因此您无需再次调用Wire.available()

从本质上讲,你receivedData如果你快点处理这程序可读取的程序里面的数据。 否则 ,您只能设置(volatile)标志,然后在loop对其进行监视。 根据我在草图中看到的内容,您可以执行以下操作:

// variables that allow signalling between receiveData ISR and loop
volatile bool    newData = false;
volatile uint8_t state   = false;

// callback for received data
void receiveData(int byteCount)
{
    // Read all the bytes; only the last one changes the relay state
    while (byteCount-- > 0)
      number = Wire.read();

    if (state != number) {
      state   = number;
      newData = true;
    }
}

// callback for sending data
void sendData(){
    Wire.write(number);
}

void loop()
{
  if (newData) {
    newData = false; // clear the flag for next time

    if (number == 1){
        digitalWrite(RELAY1, HIGH); // set the LED on
    } else {
        digitalWrite(RELAY1, LOW); // set the LED off
    }

    Serial.print("data received: ");
    Serial.println( number );
  }
}

delayloop是不必要的,如果你添加别的东西可能会引起问题loop

volatile关键字使编译器无法优化loop 没有该关键字,对newData in loop的测试将消失,因为编译器认为newDataloop期间不会改变。 为什么要测试? volatile newData告诉编译器newData可以随时更改,例如在receiveData ISR期间。

并确保按照pholtz的建议在rpi代码中打印number

在arduino代码中更改如下的sendData()函数

void sendData(){
    int relay_status;
    relay_status=digitalRead(4);
    Wire.write(relay_status);
    }

同样在硬件中,将第四个数字引脚(或任何其他空闲的I / O引脚)连接到继电器输入。

希望能帮助到你:)

好的,看起来是个不错的开始。 我想在这里建议两件事。

首先,在python程序中,您应该打印number以便可以看到它的值在变化。 它存储了来自Arduino的反馈,因此您希望将该反馈显示在屏幕上。 这就像更改number = readNumber()print readNumber()一样简单。

其次,在您的Arduino程序中,您确定调用Wire.read()返回您认为的内容吗? 在我看来,read()返回一个字节。 可能是,当您键入1时,它实际上是作为“ 1”而不是1发送的。Char vs. Int。 说得通?

因此,您可能想改为检查if(number == '1') 只是我的2美分。

您的i2c总线未正确连接。 拆下电平转换器,并在scl和sda线路的3.3v vcc上增加4.7k上拉电阻。 I2c芯片仅将线驱动为低电平,并且需要外部电阻将线拉高。 这使您可以轻松地在i2c总线上混合电压电平。 然后,您可以返回来确定您的代码在做什么。

暂无
暂无

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

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