簡體   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