2016-03-08 40 views
5

Połączyłem Raspberry pi 2 model B z arduino uno za pomocą dwukierunkowego przesuwnika poziomu.Jak odczytać dane z Arduino z Raspberry pi przez I2C

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

Mam nadzieję, że moje połączenie I2C jest poprawne?

i mój Arduino jest podłączony do 8-kanałowej płyty przekaźnikowej.

Teraz mam napisany kod, w którym mogę kontrolować płytę przekaźnikową przez Raspberry Pi. Dla przykładu, jeśli i Wciśnij "1", przekaźnik 1 idzie wysoko.

Teraz chcę wysłać dane z arduino do raspberry pi, aby sprawdzić, czy przekaźnik 1 jest wysoki, czy nie, jeśli przekaźnik 1 jest wysoki, powinien wysłać dane z powrotem do Raspberry Pi, lub nie.

Mój kod Rpi jest

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

Mój kod 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); 
} 

Teraz gdybym typu 1 i ze względu na pewne luźne Relay połączenie 1 nie przechodzi w stan wysoki, a więc w tym przypadku chcą, aby Arduino pobierał dane z tablicy przekaźników i wysyłał je do Raspberry pi za każdym razem.

Będzie świetnie, jeśli ktoś może wyjaśnić również, jak to działa.

Mam nadzieję, że udało mi się wyjaśnić problem. Zrobiłem wiele badań, ale nie byłem w stanie znaleźć odpowiedzi.

Jestem początkujący w python, więc proszę mi pomóc.

Z góry dziękuję.

+0

Czy masz dostęp do elektrycznego sprzętu pomiarowego? W takim przypadku idealnym rozwiązaniem byłby analizator logiczny, aby określić, po której stronie ogrodzenia występuje problem. Czy możesz podać numer części swojego dwukierunkowego przesuwnika poziomu? –

Odpowiedz

0

W Arduino kod zmiany sendData() działają jak to

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

Również w sprzęcie podłączyć jeden sworzeń 4. cyfrowego (lub innych szpilki wolne I/O) tak, aby przekazywał wejście.

mam nadzieję, że pomoże :)

0

Ok, wygląda na całkiem dobry początek. Dwie rzeczy, które chcę tutaj zasugerować.

Po pierwsze, w twoim programie Pythona powinieneś wydrukować number, abyś mógł zobaczyć, jak zmienia się wartość. Przechowuje informacje zwrotne od Arduino, więc chcesz wyświetlić te opinie na ekranie. Jest to tak proste, jak zmiana number = readNumber() na print readNumber().

Po drugie, w twoim programie Arduino, jesteś pewien, że wywołanie Wire.read() zwraca to, co myślisz, że robi? Wydaje mi się, że read() zwraca bajt. Jest szansa, że ​​kiedy wpisujesz 1, jest on wysyłany jako "1", a nie 1. Char vs. Int. Ma sens?

Możesz zamiast tego sprawdzić numer if(number == '1'). Tylko moje 2 ¢.

2

Problem polega na tym, że robisz zbyt wiele w numerze receiveData, który jest wywoływany z procedury obsługi przerwań w kodzie narzędziowym I2C, twi.c.Musisz musi szybko obsługiwać dane i nie wywoływać żadnych innych procedur, które zależą od włączonych przerwań (są wyłączone podczas tego ISR).

Oznacza to, że nie można zadzwonić pod numer Serial.print i nie można nawiązywać połączeń z innymi metodami wysyłania. Nawet oddzwanianie się pod numer millis() lub micros() jest odradzane, ponieważ zajmują one sporo czasu i zależą od obsługi przerwań TIMER.

Oczywiście, jesteś wolny pod numerem Wire.available() i Wire.read(). W rzeczywistości byteCount informuje, ile bajtów jest dostępnych, więc nie musisz ponownie wywoływać numeru Wire.available().

Zasadniczo Twoja rutyna receivedData może odczytywać dane wewnątrz procedury, jeśli chcesz ją szybko przetworzyć. W przeciwnym razie można ustawić tylko flagę (lotną), a następnie obejrzeć ją w loop. Z tego co widzę w swoim szkicu, można zrobić coś takiego:

// 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 w loop jest niepotrzebne i może powodować problemy, jeśli dodać coś jeszcze do loop.

Słowo kluczowe volatile uniemożliwia kompilatorowi optymalizację pod kątem loop. Bez tego słowa kluczowego test w pętli znikałby, ponieważ kompilator uważa, że ​​newData nie zmienia się podczas . Po co to testować? volatile newData mówi kompilatorowi, że newData może się zmienić w dowolnej chwili, na przykład podczas ISR receiveData.

I pamiętaj, aby wydrukować kod number w kodzie rpi, jak zasugerował pholtz!

0

Twoja magistrala i2c nie jest prawidłowo podłączona. Usuń przesuwnik poziomu i dodaj pull-ups 4.7k do 3.3v vcc na liniach scl i sda. Chipy I2C powodują jedynie niski poziom linii i wymagają zewnętrznych rezystorów, aby pociągnąć linię wysoko. Pozwala to dość łatwo mieszać poziomy napięcia na magistrali i2c. Następnie możesz wrócić do sprawdzenia, co robi twój kod.

+0

Mam problemy z wysyłaniem danych z arduino do malin. – shivam