我通过Bi-Directional Level Shifter将Raspberry pi 2模型B与arduino uno连接。
Raspberry pi GND ---------- GND Arduino
3.3v ---------- 5v
SCL ---------- A5
SDA ---------- A4
希望我的I2C连接正确吗?
我的Arduino连接到8通道继电器板。
现在我编写了代码,我可以通过Raspberry pi控制Relay板。如果我按下' 1'继电器1走高。
现在我想将数据从arduino发送回raspberry 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的初学者所以请帮助我。
提前致谢。
答案 0 :(得分:2)
问题是你在receiveData
内部做了太多,这是从I2C实用程序代码的中断服务程序twi.c
调用的。您必须快速处理数据,并且不要调用依赖于启用中断的任何其他例程(在此ISR期间它们被禁用)。
这意味着您无法拨打Serial.print
,也无法拨打任何其他电汇发送方式。不鼓励调用millis()
或micros()
,因为它们确实需要相当长的时间,并且它们依赖于正在处理的TIMER中断。
当然,您可以免费致电Wire.available()
和Wire.read()
。实际上,byteCount
会告诉您可用的字节数,因此您无需再次致电Wire.available()
。
基本上,如果你快速处理它,你的receivedData
例程可以读取例程中的数据。 否则,您只能设置一个(易失性)标志,然后在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
的测试将会消失,因为编译器认为newData
在loop
期间没有发生变化。为什么测试呢? volatile newData
告诉编译器newData
可以随时更改,例如在receiveData
ISR期间。
请务必按照pholtz的建议在rpi代码中打印number
!
答案 1 :(得分:0)
在arduino代码中 像这样改变sendData()函数
void sendData(){
int relay_status;
relay_status=digitalRead(4);
Wire.write(relay_status);
}
同样在硬件中连接一个第4个数字引脚(或任何其他空闲I / O引脚)来继电器输入。
希望它有所帮助:)
答案 2 :(得分:0)
好的,看起来是个不错的开始。我想在这里提出两件事。
首先,在你的python程序中,你应该打印number
,这样你才能看到它的价值在变化。它存储了Arduino的反馈,因此您希望将反馈显示在屏幕上。这就像将number = readNumber()
更改为print readNumber()
一样简单。
其次,在你的Arduino程序中,你确定调用Wire.read()
会返回你认为它的作用吗?在我看来,read()返回一个字节。有可能当你输入1时,它实际上被发送为'1',而不是1. Char vs. Int。有意义吗?
因此,您可能需要检查if(number == '1')
。只是我2¢。
答案 3 :(得分:0)
您的i2c总线连接不正确。移除电平移位器,并在scl和sda线上的3.3v vcc上添加4.7k引线。 I2c芯片仅将线路驱动为低电平,并需要外部电阻将线路拉高。这使您可以非常轻松地在i2c总线上混合电压电平。然后你可以回过头来弄清楚你的代码在做什么。