[英]Is there a way for a Raspberry Pi to read data being sent from the Arduino with I2C?
[英]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 );
}
}
在delay
中loop
是不必要的,如果你添加别的东西可能会引起问题loop
。
volatile
关键字使编译器无法优化loop
。 没有该关键字,对newData
in loop的测试将消失,因为编译器认为newData
在loop
期间不会改变。 为什么要测试? 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.