2016-03-08 12 views
5

Ich habe Raspberry Pi 2 Modell B mit Arduino Uno über Bidirektionale Level Shifter verbunden.Wie man Daten von Arduino mit Raspberry Pi über I2C liest

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

Hoffe, dass meine I2C-Verbindung korrekt ist?

und mein Arduino ist mit 8-Kanal-Relaiskarte verbunden.

Jetzt habe ich Code geschrieben, in dem ich die Relaisplatine von Raspberry Pi steuern kann. Wenn zB '1' gedrückt wird, wird das Relais 1 hochgeschaltet.

Jetzt möchte ich Daten zurück von arduino zu raspberry Pi senden, um zu überprüfen, ob Relais 1 hoch ist oder nicht, wenn Relais 1 hoch ist, sollte es einige Daten zurück zu Raspberry Pi oder auch nicht senden.

Mein Rpi Code ist

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() 

My Arduino Code:

#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); 
} 

Nun, wenn ich 1 geben und aufgrund einiger lose Verbindung Relais 1 nicht geht nicht hoch, also in diesem Fall I möchte, dass das arduino Daten von der Relaiskarte nimmt und es jedes Mal an Raspberry Pi sendet.

Es wird großartig sein, wenn jemand auch erklären kann, wie es funktioniert.

Ich hoffe, ich konnte das Problem erklären. Ich habe viel geforscht, konnte aber keine Antwort finden.

Ich bin ein Anfänger in Python, also bitte helfen Sie mir.

Vielen Dank im Voraus.

+0

Haben Sie Zugang zu einer elektrischen Messausrüstung? Ein Logikanalysator wäre in diesem Fall ideal, um zu bestimmen, auf welcher Seite des Zauns das Problem existiert. Kannst du auch die Teilenummer deines bidirektionalen Level Shifters angeben? –

Antwort

0

Arduino Code Änderung senddata() Funktion wie diese

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

auch in Hardware eine 4. Digitalstift (oder einen anderen freien I/O-Pins) verbinden Eingang weiterzuleiten.

hoffen, es hilft :)

0

Ok, sieht aus wie ein ziemlich guter Anfang. Zwei Dinge, die ich hier vorschlagen möchte.

Zuerst, in Ihrem Python-Programm sollten Sie number drucken, so dass Sie sehen können, dass der Wert sich ändert. Es speichert Ihre Rückmeldungen vom Arduino, sodass Sie diese Rückmeldungen auf dem Bildschirm anzeigen möchten. Dies ist so einfach wie das Ändern number = readNumber() zu print readNumber().

Zweitens, in Ihrem Arduino-Programm sind Sie sicher, dass Wire.read() zurückgibt, was Sie denken, dass es tut? Es sieht für mich so aus, als würde read() ein Byte zurückgeben. Wenn Sie 1 eingeben, wird es wahrscheinlich als "1" gesendet, nicht als 1. Char vs. Int. Sinn ergeben?

Sie sollten also stattdessen if(number == '1') überprüfen. Nur meine 2 ¢.

2

Das Problem ist, dass Sie zu viel innerhalb receiveData tun, die aus der Interrupt-Service-Routine des I2C-Dienstprogrammcodes, twi.c aufgerufen wird.Sie müssen behandeln die Daten schnell, und rufen Sie keine anderen Routinen, die abhängig von Unterbrechungen aktiviert sind (sie sind während dieser ISR deaktiviert).

Das bedeutet, dass Sie Serial.print nicht aufrufen können und Sie keine anderen Methoden zum Senden von Draht aufrufen können. Es wird sogar davon abgeraten, millis() oder micros() anzurufen, da sie eine ziemlich lange Zeit benötigen und von TIMER-Interrupts abhängig sind.

Natürlich sind Sie frei Telefon Wire.available() und Wire.read(). Tatsächlich teilt byteCount Ihnen mit, wie viele Bytes verfügbar sind, so dass Sie Wire.available() nicht erneut aufrufen müssen.

Im Wesentlichen kann Ihre receivedData Routine die Daten innerhalb der Routine lesen, wenn Sie schnell über die Verarbeitung sind. Ansonsten, Sie können nur ein (flüchtiges) Flag setzen und dann in loop darauf achten.

// 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); 
    } 
} 

Die delay in loop nicht erforderlich ist, und kann zu Problemen führen, wenn Sie etwas anderes zu loop hinzufügen: Von dem, was ich in der Skizze sehen, könnten Sie etwas tun.

Das Schlüsselwort volatile hält den Compiler davon ab, loop zu optimieren. Ohne dieses Schlüsselwort würde der Test für newData in Schleife verschwinden, weil der Compiler denkt, dass sich newData während loop nicht ändert. Warum es testen? volatile newData sagt dem Compiler, dass newData jederzeit ändern kann, wie während der receiveData ISR.

Und sicher sein, die number im Rpi-Code zu drucken, wie pholtz vorgeschlagen!

0

Ihr i2c-Bus ist nicht richtig angeschlossen. Entferne den Level Shifter und füge 4.7k Pull-ups zu den 3.3v vcc auf scl und sda hinzu. I2C-Chips treiben nur die Leitung niedrig und erfordern externe Widerstände, um die Leitung hoch zu ziehen. Dadurch können Sie die Spannungspegel Ihres i2c-Busses relativ einfach mischen. Dann können Sie wieder herausfinden, was Ihr Code macht.

+0

Ich habe Probleme mit dem Senden von Daten von Arduino zu Himbeere. – shivam