2016-03-08 21 views
5

Ho collegato Raspberry pi 2 modello B con arduino uno tramite cambio di livello bidirezionale.Come leggere i dati da Arduino con Raspberry pi via I2C

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

spero che la mia connessione I2C è corretta?

e il mio Arduino è collegato alla scheda relè a 8 canali.

Ora ho scritto codice in cui posso controllare la scheda Relè di Raspberry pi. Ad esempio se si preme '1' il relè 1 diventa alto.

Ora voglio inviare i dati da arduino a raspberry pi per poter verificare se il relè 1 è alto o no, se il relè 1 è alto, allora dovrebbe restituire alcuni dati a Raspberry pi oppure no.

Il mio codice è 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() 

Il mio codice di 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); 
} 

Ora, se io tipo 1 e causa di alcuni relè connessione allentata 1 non va alto, così in questo caso io vuoi che l'arduino prenda i dati dalla scheda relay e li invii a Raspberry pi ogni volta.

Sarebbe bello se qualcuno potesse spiegare anche come funziona.

Spero di essere stato in grado di spiegare il problema. Ho fatto molte ricerche ma non sono riuscito a trovare una risposta.

Sono un principiante in python quindi per favore aiutatemi.

Grazie in anticipo.

+0

Avete accesso a un apparecchio di misura elettrico? In questo caso, un analizzatore di stati logici sarebbe l'ideale per determinare su quale lato della barriera si trova il problema. Inoltre, puoi dare il numero di parte del tuo cambio di livello bidirezionale? –

risposta

0

In arduino codice cambiamento funzione sendData() come questo

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

anche in hardware collegare un perno 4a digitale (o qualsiasi altra perni liberi I/O) per l'inoltro ingresso.

Speranza che aiuta :)

0

Ok, sembra un buon inizio. Due cose che voglio suggerire qui.

Per prima cosa, nel programma Python dovresti stampare number in modo che tu possa vedere il suo valore cambiare. Memorizza il tuo feedback da Arduino, quindi vuoi mostrare quel feedback sullo schermo. Questo è semplice come cambiare number = readNumber() a print readNumber().

Secondo, nel tuo programma Arduino, sei sicuro che chiamare Wire.read() restituisca quello che pensi che faccia? Mi sembra che read() restituisca un byte. Le probabilità sono che quando si digita 1 viene realmente inviato come '1', non 1. Char vs. Int. Ha senso?

Quindi potresti controllare lo if(number == '1'). Solo il mio 2 ¢.

2

Il problema è che si sta facendo troppo all'interno di receiveData, che viene chiamato dalla routine di servizio di interruzione del codice di utilità I2C, twi.c necessario gestire i dati rapidamente e non chiamare le altre routine che dipendono da interrupt essere abilitato (sono disabilitati durante questo ISR).

Ciò significa che non è possibile chiamare Serial.print e non è possibile chiamare altri metodi di invio filo. Anche chiamare millis() o micros() è sconsigliato, poiché richiede molto tempo e dipende dagli interrupt TIMER gestiti.

Ovviamente, si è liberi di chiamare Wire.available() e Wire.read(). In realtà, byteCount indica quanti byte sono disponibili, quindi non è necessario chiamare nuovamente Wire.available().

In sostanza, la tua routine receivedData può leggere i dati all'interno della routine se si è pronti a elaborarla. Altrimenti, è possibile impostare solo un flag (volatile) e quindi guardarlo per lo loop. Da quello che vedo nel tuo disegno, si potrebbe fare qualcosa di simile:

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

Il delay in loop non è necessaria, e può causare problemi se si aggiunge qualcos'altro da loop.

La parola chiave volatile impedisce al compilatore di ottimizzare loop. Senza tale parola chiave, il test per il ciclo newData in corso scompare perché il compilatore ritiene che newData non cambi durante loop. Perché provarlo? volatile newData dice al compilatore che newData può cambiare in qualsiasi momento, come durante l'ISR receiveData.

E assicuratevi di stampare lo number nel codice rpi, come suggerito da pholtz!

0

Il bus i2c non è collegato correttamente. Rimuovi il level shifter e aggiungi 4.7k pull-up al 3.3cc vcc sulle linee scl e sda. I chip I2c guidano solo la linea in basso e richiedono resistori esterni per alzare la linea. Ciò consente di mixare i livelli di tensione sul tuo bus i2c abbastanza facilmente. Quindi puoi tornare indietro per capire cosa sta facendo il tuo codice.

+0

Ho problemi con l'invio di dati da Arduino a Raspberry. – shivam