![](/img/trans.png)
[英]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.