marți, 14 octombrie 2014

Comunicatii intre placi Arduino prin 2 fire (protocol i2c)

   Avand la dispozitie 2 placi de dezvoltare Arduino, am considerat ca e timpul sa testez si modul de comunicare i2c, despre care puteti gasi informatii pe net.
   Pe scurt comunicarea se face pe 2 "fire": SDA (A4 la Arduino Uno)  si SCL (A5 la Arduino Uno), necesitand si firul de masa (GND).
   In mod normal, cele 2 "fire" se conecteaza la plus (5V) prin rezistente de 1..10kohmi, dar pentru o placa Master (stapan) si una Slave (sclav), pot lipsi, cum am facut eu in montajul de test.
   Sursa de inspiratie a fost articolul Comunicarea i2c de pe site-ul roroid, care are schema de conexiuni pentru teste:
   Eu voi folosi placuta (brick, shield/semishield) cu un LED multicolor si 3 rezistente, cu conector pentru zona digitala D8...D13 si GND
   Schema mea de testare are doar 4 fire, plus 5V, masa (GND), SDA(A4) si SCL(A5); ea permite alimentarea din cablul USB folosit la una din placi:
   Practic, montajul arata asa:
   Pentru inceput, am adaptat sketch-urile din articolul mentionat mai sus, schimband doar partea de conectare a led-ului de la pinul D8 la D8 cum are placuta mea.
   Ulterior, am modificat sketch-urile pentru a comanda cele 3 led-uri componente ale led-ului multicolor, obtinand:
   Sketch-urile pentru comanda celor 3 led-uri sunt:
- sketch-ul pentru "master" (stapan):
// MASTER ver1
// sketch de inspiratie de la http://www.roroid.ro/comunicarea-i2c/
// sketch adaptat pentru led multicolor de niq_ro de la http://nicuflorica.blogspot.ro/
// si http://arduinotehniq.blogspot.com/
//se incarca biblioteca pentru comunicarea pe I2C
#include <Wire.h>
void setup()
{
// initializeaza bus pentru i2c
Wire.begin();
Serial.begin(9600);
}

void loop()
{

Serial.println("MASTER:Toate LED-urile stinse");
Wire.beginTransmission(4); // transmit dispozitivului de la adresa #4
//in functie de cate dispozitive aveti legate pe I2C acest numar variaza

//comenzile de mai jos comanda ledurile de pe pinii 9, 10 si 11
//comenzile sunt de formatul LPPS; unde L- inseamna LED;PP-reprezinta numarul pinului;S-inseamna starea pinului
//Ex. L100;-va stinge ledul de pe pinul 10;L081 va aprinde ledul de pe pinul8
//L100;L081;-va stinge ledul de pe pinul 10 si aprinde ledul de pe pinul 8 concomitent.
Wire.write("L09"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.write("L10"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.write("L11"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.requestFrom(4, 15); // se citesc 15 biti de raspuns de la dispozitivul
//de pe adresa 4

while(Wire.available()) //atata timp cat se primeste ceva
{
char c = Wire.read();
Serial.print(c); // tipareste caracterele primite
}
Serial.println("");
Wire.endTransmission(); // intrerupe transmisia

delay(2000); //asteptam un pic dupa care reluam cu 0

Serial.println("MASTER:Aprind LED-ul 1");
Wire.beginTransmission(4); // transmit dispozitivului de la adresa #4
//in functie de cate dispozitive aveti legate pe I2C acest numar variaza

//comenzile de mai jos comanda ledurile de pe pinii 9, 10 si 11
//comenzile sunt de formatul LPPS; unde L- inseamna LED;PP-reprezinta numarul pinului;S-inseamna starea pinului
//Ex. L100;-va stinge ledul de pe pinul 10;L081 va aprinde ledul de pe pinul8
//L100;L081;-va stinge ledul de pe pinul 10 si aprinde ledul de pe pinul 8 concomitent.
Wire.write("L09"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("1"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.write("L10"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.write("L11"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.requestFrom(4, 15); // se citesc 15 biti de raspuns de la dispozitivul
//de pe adresa 4

while(Wire.available()) //atata timp cat se primeste ceva
{
char c = Wire.read();
Serial.print(c); // tipareste caracterele primite
}
Serial.println("");
Wire.endTransmission(); // intrerupe transmisia

delay(2000); //asteptam un pic dupa care reluam cu 0


Serial.println("MASTER:Aprind LED-ul 2");
Wire.beginTransmission(4); // transmit dispozitivului de la adresa #4
//in functie de cate dispozitive aveti legate pe I2C acest numar variaza

//comenzile de mai jos comanda ledurile de pe pinii 9, 10 si 11
//comenzile sunt de formatul LPPS; unde L- inseamna LED;PP-reprezinta numarul pinului;S-inseamna starea pinului
//Ex. L100;-va stinge ledul de pe pinul 10;L081 va aprinde ledul de pe pinul8
//L100;L081;-va stinge ledul de pe pinul 10 si aprinde ledul de pe pinul 8 concomitent.
Wire.write("L09"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.write("L10"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("1"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.write("L11"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.requestFrom(4, 15); // se citesc 15 biti de raspuns de la dispozitivul
//de pe adresa 4

while(Wire.available()) //atata timp cat se primeste ceva
{
char c = Wire.read();
Serial.print(c); // tipareste caracterele primite
}
Serial.println("");
Wire.endTransmission(); // intrerupe transmisia

delay(2000); //asteptam un pic dupa care reluam cu 0

Serial.println("MASTER:Aprind LED-ul 3");
Wire.beginTransmission(4); // transmit dispozitivului de la adresa #4
//in functie de cate dispozitive aveti legate pe I2C acest numar variaza

//comenzile de mai jos comanda ledurile de pe pinii 9, 10 si 11
//comenzile sunt de formatul LPPS; unde L- inseamna LED;PP-reprezinta numarul pinului;S-inseamna starea pinului
//Ex. L100;-va stinge ledul de pe pinul 10;L081 va aprinde ledul de pe pinul8
//L100;L081;-va stinge ledul de pe pinul 10 si aprinde ledul de pe pinul 8 concomitent.
Wire.write("L09"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.write("L10"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("0"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.write("L11"); // trimite numarul ledului care sa fie aprins/stins
Wire.write("1"); // trimite starea acestuia
Wire.write(";"); // trimite separator
Wire.requestFrom(4, 15); // se citesc 15 biti de raspuns de la dispozitivul
//de pe adresa 4

while(Wire.available()) //atata timp cat se primeste ceva
{
char c = Wire.read();
Serial.print(c); // tipareste caracterele primite
}
Serial.println("");
Wire.endTransmission(); // intrerupe transmisia

delay(2000); //asteptam un pic dupa care reluam cu 0

}

- sketch-ul pentru "slave" (sclav):

// SLAVE ver.1
// sketch de inspiratie de la http://www.roroid.ro/comunicarea-i2c/
// sketch adaptat pentru led multicolor de niq_ro de la http://nicuflorica.blogspot.ro/
// si http://arduinotehniq.blogspot.com/
//se incarca biblioteca pentru comunicarea pe I2C
#include <Wire.h>

int LED[] = {99,4,5,6,7,8,9,10,11,12,13};//se definesc pinii pe care sunt conectate LED-urile
char comanda[15]; //vectorul in care va fi receptionata comanda pe I2c
char *i;
String p="";
void setup()
{
Serial.begin(9600);
for(int i = 0; i <= 10; i++){
pinMode(LED[i],OUTPUT);//initializeaza toti pini pe care sunt legate leduri ca output
}

Wire.begin(4);//suntem dispozitivul de la adresa #4
Wire.onReceive(receptie);//datele primite pe i2c le interpretam in functia receptie
Wire.onRequest(da_sefu); // activam functia da_Sefu
}

void loop()
{
delay(100);
}

// aici interpretam datele
void receptie(int howMany)
{
byte index = 0;
//se salveaza comanda primita pe I2C intr-un string
while(Wire.available())
{
comanda[index++] = Wire.read();
}
//se interpreteaza comanda
p=strtok_r(comanda,";",&i);
while(p!="")
{
if (p.startsWith("L")) //se verifica daca trebuie sa aprindem un led
{//daca este led stim ca urmatoarele 2 caractere reprezinta pinul iar urmatorul caracter starea
String pin=p.substring(1,3);//cauta valoarea pin in comanda
String stare=p.substring(3,4);//cauta valoarea stare in comanda

digitalWrite(pin.toInt(),stare.toInt());//trimite valorile pinului respectiv
}
p=strtok_r(NULL,";",&i);//verific daca mai am ceva de executat
}

}

void da_sefu()
{
Wire.write("ARDUINO:Da sefu"); // raspunde cu un mesaj de 15 bytes
}

   Am facut un filmulet numit i2c: un Arduino comanda, celalalt executa si raporteaza in care se vede mai bine ce am descris eu mai sus:
   Dupa ce am vazut cum "lucreaza", atat "stapanul", cat si "sclavul", am rescris cele 2 sketck-uri pentru a aprinde led-urile cu intensitate regabila (cu factor de umplere variabil - PWM), dupa cum se vede in filmuletul i2c: un Arduino comanda, celalalt executa si raporteaza (2)
   Sketch-ul pentru "stapan" este:
// MASTER ver2
// sketch de inspiratie de la http://www.roroid.ro/comunicarea-i2c/
// sketch adaptat pentru led multicolor de niq_ro de la http://nicuflorica.blogspot.ro/
// si http://arduinotehniq.blogspot.com/
//se incarca biblioteca pentru comunicarea pe I2C
#include <Wire.h>

int r, g, b; // variabile pentru intensitate culori
int r1, g1, b1; // alte variabile
int intarziere = 1000; // intarziere intre comenzile mari, in ms
int fadespeed = 100; // intarziere intre trepte de intensitate, in ms
String ghe1;

void setup()
{
// initializeaza bus pentru i2c
Wire.begin();
Serial.begin(9600);
}

void loop()
{
// trecere de la stins la alb
  for (r = 0; r < 25; r++) { 
    Serial.println(r);
  r1 = r *10;
  ordin (r1, r1, r1);
  delay(fadespeed); 
  }
  delay(intarziere);

// trecere de la alb la stins
  for (r = 25; r > 0; r--) {
    Serial.println(r); 
  r1 = r *10; 
  ordin (r1, r1, r1);
  delay(fadespeed); 
  }
  delay(intarziere);


// trecere de la stins la rosu
  for (r = 0; r < 25; r++) { 
    Serial.println(r);
  r1 = r *10;
  ordin (0, 0, r1);
  delay(fadespeed); 
  }
  delay(intarziere);

// trecere de la rosu la stins
  for (r = 25; r > 0; r--) {
    Serial.println(r); 
  r1 = r *10; 
  ordin (0, 0, r1);
  delay(fadespeed); 
  }
  delay(intarziere);


// trecere de la stins la verde
  for (r = 0; r < 25; r++) { 
    Serial.println(r);
  r1 = r *10;
  ordin (r1, 0, 0);
  delay(fadespeed); 
  }
  delay(intarziere);

// trecere de la verde la stins
  for (r = 25; r > 0; r--) {
    Serial.println(r); 
  r1 = r *10; 
  ordin (r1, 0, 0);
  delay(fadespeed); 
  }
  delay(intarziere);


// trecere de la stins la albastru
  for (r = 0; r < 25; r++) { 
    Serial.println(r);
  r1 = r *10;
  ordin (0, r1, 0);
  delay(fadespeed); 
  }
  delay(intarziere);

// trecere de la albastru la stins
  for (r = 25; r > 0; r--) {
    Serial.println(r); 
  r1 = r *10; 
  ordin (0, r1, 0);
  delay(fadespeed); 
  }
  delay(intarziere);


}




void ordin (int er, int ghe, int be)
{
Serial.println("MASTER:ordon sa executi comanda - ");
Wire.beginTransmission(4); // transmit dispozitivului de la adresa #4
//in functie de cate dispozitive aveti legate pe I2C acest numar variaza

//comenzile de mai jos comanda ledurile de pe pinii 9, 10 si 11
//comenzile sunt de formatul LPPSSS; unde L-inseamna LED;PP-reprezinta numarul pinului;SSS-inseamna numarul PWM pentru aprindere reglabila
//Ex. L10000;-va stinge ledul de pe pinul 10;L09255 va aprinde ledul de pe pinul9 la maxim, iar L11123 va aprinde ledul de la pinul 11 la jumatate

Wire.write("L11"); // trimite numarul ledului care sa fie aprins/stins (aici e rosu, la pinul 11)
Serial.print("L11");
Serial.println(er);
// starea trebuie sa fie din 3 cifre, dar trebuie sa le transmit drept caractere
Serial.print("=");
int er1 = er/100;
Wire.write(er1+48); // trimit cifra sutelor
Serial.print(er1);
er = er-100*er1;
er1 = er/10;
Wire.write(er1+48); // trimit cifra zecilor
Serial.print(er1);
er = er-er1*10;
Serial.println(er);
Wire.write(er+48); // trimit cifra unitatilor
Wire.write(";"); // trimite separator

Wire.write("L09"); // trimite numarul ledului care sa fie aprins/stins (aici e verde, la pinul 9)
// starea trebuie sa fie din 3 cifre, dar trebuie sa le transmit drept caractere
Serial.print("L09");
Serial.println(ghe);
// starea trebuie sa fie din 3 cifre, dar trebuie sa le transmit drept caractere
Serial.print("=");
int ghe1 = ghe/100;
Wire.write(ghe1+48); // trimit cifra sutelor
Serial.print(ghe1);
ghe = ghe-100*ghe1;
ghe1 = ghe/10;
Wire.write(ghe1+48); // trimit cifra zecilor
Serial.print(ghe1);
ghe = ghe-ghe1*10;
Serial.println(ghe);
Wire.write(ghe+48); // trimit cifra unitatilor
Wire.write(";"); // trimite separator

Wire.write("L10"); // trimite numarul ledului care sa fie aprins/stins (aici e albastru, la pinul 10)
// starea trebuie sa fie din 3 cifre, dar trebuie sa le transmit drept caractere
Serial.print("L10");
Serial.println(be);
// starea trebuie sa fie din 3 cifre, dar trebuie sa le transmit drept caractere
Serial.print("=");
int be1 = be/100;
Wire.write(be1+48); // trimit cifra sutelor
Serial.print(be1);
be = be-100*be1;
be1 = be/10;
Wire.write(be1+48); // trimit cifra zecilor
Serial.print(er1);
be = be-be1*10;
Serial.println(be);
Wire.write(be+48); // trimit cifra unitatilor
Wire.write(";"); // trimite separator

Wire.requestFrom(4, 15); // se citesc 15 biti de raspuns de la dispozitivul
//de pe adresa 4

while(Wire.available()) //atata timp cat se primeste ceva
{
char c = Wire.read();
Serial.print(c); // tipareste caracterele primite
}
Serial.println("");
Wire.endTransmission(); // intrerupe transmisia
}
   Sketch-ul pentru "sclav" este:
// SLAVE ver.2
// sketch de inspiratie de la http://www.roroid.ro/comunicarea-i2c/
// sketch adaptat pentru led multicolor de niq_ro de la http://nicuflorica.blogspot.ro/
// si http://arduinotehniq.blogspot.com/
//se incarca biblioteca pentru comunicarea pe I2C
#include <Wire.h>

int LED[] = {99,4,5,6,7,8,9,10,11,12,13};//se definesc pinii pe care sunt conectate LED-urile
char comanda[21]; //vectorul in care va fi receptionata comanda pe I2c
char *i;
String p="";
void setup()
{
Serial.begin(9600);
for(int i = 0; i <= 10; i++){
pinMode(LED[i],OUTPUT);//initializeaza toti pini pe care sunt legate leduri ca output
}

}
void loop()
{
Wire.begin(4);//suntem dispozitivul de la adresa #4
Wire.onReceive(receptie);//datele primite pe i2c le interpretam in functia receptie
Wire.onRequest(da_sefu); // activam functia da_Sefu

 delay(5);
}

// aici interpretam datele
void receptie(int howMany)
{
byte index = 0;
//se salveaza comanda primita pe I2C intr-un string
while(Wire.available())
{
comanda[index++] = Wire.read();
}
//se interpreteaza comanda
p=strtok_r(comanda,";",&i);
while(p!="")
{
//  Serial.print(p);
if (p.startsWith("L")) //se verifica daca trebuie sa aprindem un led
{//daca este led stim ca urmatoarele 2 caractere reprezinta pinul iar urmatorul caracter starea
//Serial.println("---------------------------");
String pin=p.substring(1,3);//cauta valoarea pin in comanda
//Serial.print(pin);
String stare=p.substring(3,6);//cauta valoarea stare in comanda
//Serial.print(stare);
//digitalWrite(pin.toInt(),stare.toInt());//trimite valorile pinului respectiv
analogWrite(pin.toInt(),stare.toInt());//trimite valorile pinului respectiv
//digitalWrite(pin.toInt(),);//trimite valorile pinului respectiv
}
p=strtok_r(NULL,";",&i);//verific daca mai am ceva de executat
}
}

void da_sefu()
{
Wire.write("ARDUINO:Da sefu"); // raspunde cu un mesaj de 15 bytes
}
   Pentru moment, cred ca e suficient ce am invatat despre acest mod de comunicare...

Niciun comentariu:

Trimiteți un comentariu