Comunicazione I2C tra più Arduino

Salve a tutti.
Sto realizzando un circuito che mi consente di accendere dei led in base ai valori letti dal potenziometro, collegato ad un pin analogico. Ho realizzato un master che comunica con tre slave attraverso il protocollo I²C. Al master ho collegato un potenziometro. Ad ogni slave ho collegato un led e uno switch ai pin digitali. Arduino dovrà leggere, in base alla combinazione data mediante lo switch, il numero binario. Quest' ultimo lo devo trasformare in un numero decimale. Questo valore sarà l'indirizzo dello slave. Poi devo fare in modo che il primo relè si accenda se il valore letto del potenziometro sarà maggiore di 341, il secondo si accenda se il valore sarà maggiore di 682 e l'ultimo se il valore sarà maggiore di 1000, altrimenti, se queste condizioni non sono verificate, i relè dovranno spegnersi.
Ho due problemi, il primo riguarda la combinazione dello switch. Fino al numero 3, lo converte poi arriva il problema. Infatti, con la combinazione 0100 che dovrebbe essere il 4 in decimale lo legge di nuovo come 3, con la combinazione 0101 che dovrebbe essere il 5 lo legge come 4, con la combinazione 0110 che dovrebbe essere il 6 lo legge come 5, quindi sempre un numero in meno. Il secondo è quello che i led non si accendono in base ai valori detti prima. Potreste aiutarmi?
Grazie.
Allego anche la foto del circuito.


P.S.: gli slave hanno lo stesso codice

//MASTER
#include <Wire.h>
int cambiaTrasmissione = 0;
byte stato_led;
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  Serial.println("start");
}
void loop()
{
  int potenziometro = analogRead(A1);

  Serial.print(potenziometro);
  Serial.print("\t");
  delay(100);
  if (potenziometro > 341)
    indirizzo1_acceso(); //accende il led del primo slave
  if (potenziometro > 682)
    indirizzo2_acceso(); //accende il led del secondo slave
    if (potenziometro > 1000)
      indirizzo3_acceso(); //accende il led del terzo slave
    else {
      indirizzo1_spento(); //spegne il led del primo slave
      indirizzo2_spento(); //spegne il led del secondo slave
      indirizzo3_spento(); //spegne il led del terzo slave
    }
  if (cambiaTrasmissione == 1) //se l'indirizzo è 1
  {
    Wire.beginTransmission(1);
    Wire.write(stato_led);
    Wire.endTransmission();
  }
  if (cambiaTrasmissione == 2) //se l'indirizzo è 2
  {
    Wire.beginTransmission(2);
    Wire.write(stato_led);
    Wire.endTransmission();
  }
  if (cambiaTrasmissione == 3) //se l'indirizzo è 3
  {
    Wire.beginTransmission(3);
    Wire.write(stato_led);
    Wire.endTransmission();
  }
}
void indirizzo1_acceso() {
  stato_led  = 1;
  cambiaTrasmissione = 1;
}
void indirizzo2_acceso() {
  stato_led  = 1;
  cambiaTrasmissione = 2;
}
void indirizzo3_acceso() {
  stato_led = 1;
  cambiaTrasmissione = 3;

}
void indirizzo1_spento() {
  stato_led  = 0;
  cambiaTrasmissione = 1;

}
void indirizzo2_spento() {
  stato_led  = 0;
  cambiaTrasmissione = 2;
}

void indirizzo3_spento() {
  stato_led  = 0;
  cambiaTrasmissione = 3;
}

//SLAVE
#include <Wire.h>
int led1 = 13;
byte stato_led;
int InputPins[] = {6, 5, 4, 3}; //dichiaro i pin dello dip switch

void setup() {
  for (int j = 0; j < 4; j++)
  {
    pinMode(InputPins[j], INPUT);
  }
  Serial.begin(9600);
  pinMode(led1, OUTPUT);
  Wire.onReceive(gestione);
}

void loop() {
  int n = 0; // inizializza la variabile che conterrà la conversione da bin. a dec.
  for (int i = 0; i < 4; i++) {
    int m = digitalRead(InputPins[i]); // lettura del bit i−esimo
    n = n + m * pow(2, (3 - i)); //conversione da bin. a dec.
    Wire.begin(n);
  }
  Serial.println(n);
  delay(100);
}
void gestione(int invia)
{
  stato_led = Wire.read();
  if (stato_led == 1)
  {
    digitalWrite(led1, HIGH);
  }
  else if (stato_led == 0)
  {
    digitalWrite(led1, LOW);
  }
}

Wire.begin() deve essere in setup().

E, non si tratta di convertire binario→decimale, ma di "trasportare" i quattro bit letti dagli switch nei 4 bit bassi della variabile 'n' (che è e rimane binaria anche se la si usa come valore decimale).

Il problema nella procedura aritmetica sono gli arrotondamenti dei risultati della funzione pow durante la conversione implicita float→intero, in pratica invece di ottenere 8 4 2 1, si ottiene 7 3 2 1.

Visto che si stanno solo "copiando" bit meglio usare le operazioni sui bit (or e shift):

int n = 0;
for (int i = 0; i < 4; i++) 
{
    n |= digitalRead(InputPins[i]) << (3 - i);
}

o anche (credo sia più veloce):

    n = (n << 1) | digitalRead(InputPins[i]);

Poi: c'è il collegamento GND tra il primo Arduino e i seguenti?

Grazie mille. Gli switch adesso funzionano correttamente. Provvederò anche a collegare la massa tra il primo e gli altri Arduino.

Potreste aiutarmi anche con il secondo problema?

Da come hai indentato il codice presumo che ti aspetti che il primo if escluda il secondo e cosi via?
In tal caso, non è cosi. Dovevi usare else if nei rami successivi al primo.
Per come lo hai scritto, se potenziometro vale ad esempio 1001, sono veri tutti e 3 gli if contemporaneamente.
Se vale 350, è vero il primo if che comunque non ha alcun effetto perché if (potenziometro > 1000) è falso e quindi ti spegne subito dopo tutti i LED.

Grazie mille.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.