Go Down

Topic: I2C - passare valori dallo Slave al Master (Read 679 times) previous topic - next topic

Ciao. Sto implementando una comunicazione I2C tra due chip Atmega 328P, il cui circuito é su breadboard, e riesco a passare un valore dal Master allo Slave. Se poi voglio ottenere un certo valore dallo Slave, mediante un Wire.requestFrom() ottengo valori strani.
Oltre alla libreria Wire.h utilizzo anche la libreria I2C_Anything.h per convertire i valori letti e scritti, da byte a integer.
Posto il codice:
[Master]
Code: [Select]

#include <Wire.h>
#include <I2C_Anything.h>

#define LED 13
const byte SLAVE_ADDRESS = 42;
int timeBlink;
int blinkMaster;
byte highByte;
byte lowByte;
boolean checkX=false;

void setup()
{
  Serial.begin(115200);
  pinMode(LED,OUTPUT);
  Wire.begin ();
   timeBlink = 2000;
   
    Wire.beginTransmission (SLAVE_ADDRESS);
    I2C_writeAnything (timeBlink);
    Wire.endTransmission ();
    blinkMaster=0;
     
}  // end of setup

void loop()
{
  delay(1000);
  if(timeBlink > 0){
  timeBlink-=100;
  }else{
    timeBlink=2000;
   
  }
   timeBlink--;
   Wire.beginTransmission(42);      //inizio comunicazione
   I2C_writeAnything(timeBlink);    //scrivo timeBlink sullo stream
   Wire.endTransmission();           //chiudo comunicazione
   
    Wire.requestFrom(42,2);       //Richiedo 2 byte allo Slave
   // while(Wire.available()){
      I2C_readAnything(blinkMaster); // leggo i dati inviati dallo slave
   // }
    Serial.print("receive from SLAVE=");
    Serial.println(blinkMaster);
}  /


[Slave]
Code: [Select]

#include <Wire.h>
#include <I2C_Anything.h>
#define LED 13
const byte MY_ADDRESS = 42;
int timeBlink;
void setup()
{
  Wire.begin (MY_ADDRESS);
  Serial.begin (115200);
  Wire.onReceive (receiveEvent);
  Wire.onRequest(requestEvent);
  pinMode(LED,OUTPUT);
   timeBlink=2000;

}  // end of setup


void loop()
{
  delay(1000);
   
Serial.print("slave timeblink="); 
Serial.println(timeBlink);


void receiveEvent (int howMany) //routine per dati in arrivo dal master
{
  while(Wire.available()){
   I2C_readAnything (timeBlink);
   
  }
 
}

void requestEvent()
{
  //questo evento viene generato quando il master
  //richiede ad uno specifico slave
  //una richiesta di dati

  //spedisco il dato al Master
  I2C_writeAnything(timeBlink);
  Serial.print ("Sended to master requested = ");
    Serial.println (timeBlink);
 
}



La libreria I2C_Anything.h ha questo codice:
Code: [Select]

#include <Arduino.h>
#include <Wire.h>

template <typename T> int I2C_writeAnything (const T& value)
  {
    const byte * p = (const byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          Wire.write(*p++);
    return i;
  }  // end of I2C_writeAnything

template <typename T> int I2C_readAnything(T& value)
  {
    byte * p = (byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          *p++ = Wire.read();
    return i;
  }  // end of I2C_readAnything


Il problema é che ottengo in risposta dallo Slave valori tipo -249, -250 ecc, anziché valori del tipo 2000, 1900 ecc

Tutte le comunicazioni seriali inviano un byte per volta e il valore decimale massimo di un byte è 255. Un intero è grande 2 byte per cui ricevi prima io byte più significativo (quello a sinistra) e poi quello meno significativo, quindi ogni due byte devi ricomporre il valore unendo i due byte.

Ciao.
AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

leo72


Tutte le comunicazioni seriali inviano un byte per volta e il valore decimale massimo di un byte è 255. Un intero è grande 2 byte per cui ricevi prima io byte più significativo (quello a sinistra) e poi quello meno significativo, quindi ogni due byte devi ricomporre il valore unendo i due byte.

Ciao.

Ma lui dovrebbe usare questa libreria I2CAnything che dovrebbe spezzettare nei singoli byte qualunque variabile e ricomporre il dato in ricezione. Difatti vedo:
I2C_readAnything (timeBlink);
nello sketch di ricezione.

Forse non c'è corrispondenza fra i tipi di dato trasmesso e quello in cui viene poi memorizzato il valore. Ma non avendo mai visto quella lib non so come operi.

Leo hai ragione.

Comunque non capisco il valore ritornato i che cosa contiene, dovrebbe contenere il numero di bit processato.

booh.

Ciao.
AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Ho provato anche con :

Code: [Select]

byte highByte;
byte lowByte;
while(Wire.available()){
  highByte = Wire.read();           //reads the byte as an integer
   lowByte = Wire.read();
   int blinkMaster = ((highByte<<8)+lowByte)/10;
}


In questo caso anziché 2000, al primo ciclo, ottengo 2047.

Cmq potreste dirmi se nella:
Code: [Select]
Wire.requestForm(address,2)

I byte da ricevere sono sempre 2 per ottenere numeri maggiori di 255?

Si, Wire.available() ritorna il numero di byte

PaoloP

Controlla bene gli esempi applicativi della libreria
qui --> http://www.bajdi.com/i2c-communication-between-2-arduinos/
ma soprattutto qui --> http://www.gammon.com.au/forum/?id=10896

Prova a definire i tipi volatile.

L'argomento, anche se tratta I2C, è più da sezione Software.  ;)

Go Up