luni, 5 februarie 2018

ARDUINO - Efect de urmărire cu leduri ( led chase effect )



Vom folosi un număr de 10 led-uri pentru a realiza ”Led Chase Effect”. Led Chase Effect constă în a aprinde pe rând câte un led, bineînțeles cele din spate vor fi stinse, până când ajungem la ultimul led iar apoi repetăm operațiunea în sens invers. În cazul în care nu ați înțeles am câteva imagini sper eu mai exemplificatoare.



Pentru a realiza practic acest montaj avem nevoie de 10 led-uri și 10 rezistori.
Valoare rezistorilor fiind de 100Ω. Calculul se realizează cu ajutorul legii lui OHM. 


Mai jos avem schema electronică realizată în Proteus și în Frizzing:

După cum observați pinii folosiți, de la placa Arduino, sunt: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11.


Ținând cont de ce trebuie să facă aplicația noastră va trebui să facem următoarele: 
  • 1. Să aprindem ledul 1 conectat la pinul 2. Pentru asta va trebui ca la pinul 2 să avem 1 logic.
  • 2.       Îl lăsăm aprins puțin iar apoi îl stingem. Pentru al lăsa aprins o perioadă de timp folosim Delay (ms), iar pentru al stinge dăm 0 ( zero ) logic la pinul 2.
  • 3.       Aprindem imediat , după stingerea ledului de dinainte, pe ledul 2 conectat la pinul 3. Pentru asta trebuie ca la pinul 3 să dăm un 1 logic.
  • 4.       Îl lăsăm aprins puțin, apoi îl stingem.
  • 5.       .....
  • 6.       ....și așa mai departe pana la ledul 10 iar apoi vom relua pașii în ordine inversă, adică de la ledul 10 la ledul 1.

Varianta I

Varianta de program ( brută, mai ciobănească...dar funcțională )
int timpAsteptare=100;
int led1=2;
int led2=3;
int led3=4;
int led4=5;
int led5=6;
int led6=7;
int led7=8;
int led8=9;
int led9=10;
int led10=11;

void setup()
                {
                                pinMode(led1, OUTPUT);
                                pinMode(led2, OUTPUT);
                                pinMode(led3, OUTPUT);
                                pinMode(led4, OUTPUT);
                                pinMode(led5, OUTPUT);
                                pinMode(led6, OUTPUT);
                                pinMode(led7, OUTPUT);
                                pinMode(led8, OUTPUT);
                                pinMode(led9, OUTPUT);
                                pinMode(led10, OUTPUT);
}

void loop()
{

digitalWrite(led1, HIGH);
                delay(timpAsteptare);
                digitalWrite(led1, LOW);
digitalWrite(led2, HIGH);
                delay(timpAsteptare);
                digitalWrite(led2, LOW);
digitalWrite(led3, HIGH);
                delay(timpAsteptare);
                digitalWrite(led3, LOW);
digitalWrite(led4, HIGH);
                delay(timpAsteptare);
                digitalWrite(led4, LOW);
digitalWrite(led5, HIGH);
                delay(timpAsteptare);
                digitalWrite(led5, LOW);
digitalWrite(led6, HIGH);
                delay(timpAsteptare);
                digitalWrite(led6, LOW);
digitalWrite(led7, HIGH);
                delay(timpAsteptare);
                digitalWrite(led7, LOW);
digitalWrite(led8, HIGH);
                delay(timpAsteptare);
                digitalWrite(led8, LOW);
digitalWrite(led9, HIGH);
                delay(timpAsteptare);
                digitalWrite(led9, LOW);
digitalWrite(led10, HIGH);
                delay(timpAsteptare);
                digitalWrite(led10, LOW);
digitalWrite(led9, HIGH);
delay(timpAsteptare);
digitalWrite(led9, LOW);
digitalWrite(led8, HIGH);
delay(timpAsteptare);
digitalWrite(led8, LOW);
digitalWrite(led7, HIGH);
delay(timpAsteptare);
digitalWrite(led7, LOW);
digitalWrite(led6, HIGH);
delay(timpAsteptare);
digitalWrite(led6, LOW);
digitalWrite(led5, HIGH);
delay(timpAsteptare);
digitalWrite(led5, LOW);
digitalWrite(led4, HIGH);
delay(timpAsteptare);
digitalWrite(led4, LOW);
digitalWrite(led3, HIGH);
delay(timpAsteptare);
digitalWrite(led3, LOW);
digitalWrite(led2, HIGH);
delay(timpAsteptare);
digitalWrite(led2, LOW);
digitalWrite(led1, HIGH);
delay(timpAsteptare);
digitalWrite(led1, LOW);



}

După cum ați observat programul pe care l-am scris mai sus este unul foarte lung ( și sunt doar 10 leduri ) dar corect și funcțional. Abordarea este una ”brută”, ”băbească”, folosindu-ne de ceea ce am învățat până acum. Deși ați înțeles programul software îmi asum responsabilitatea unei explicări pentru începători.

int timpAsteptare = am declarat variabila timpAsteptare.după cum am explicat pașii ce trebuiesc urmați, led-ul nostru trebuie să stea o perioadă de timp aprins. Acest timp este înmagazinat în variabila timpAsteptare și are valoarea 100ms.



În funcția loop() avem:


Varianta II - utilizând instrucțiunea for


După cum am afirmat, programul este lung pentru 10 led-uri iar pentru mai multe led-uri va fi enorm de lung; așa că vă propun o variantă mai scurtă de program folosind aceiași schemă bineînțeles.


Această nouă variantă va folosi instrucțiunea ” FOR ”.

Sintaxa instrucțiunii FOR:
                for ( condiție_start; condiție_continuare; re-evaluare)
                                {                             
                                                execută                instrucțiune1
                                }
Cum funcționează instrucțiunea  ” for ”:
  • ·         condiție_start  → constituie inițializarea ciclului și se execută o singură dată , la începutul ciclului.
  • ·         condiție_continuare → reprezintă condiția care controlează ciclul. Dacă această condiție este adevărată se va executa ” instrucțiune1 ”, dacă este falsă se va întrerupe executarea ciclului.
  • ·         re-evaluare → constă de cele mai multe ori în modificarea valorii variabilei de control al ciclului, adică modifică o variabilă din ” condiție_continuare ” astfel încât la un moment dat  ” condiție_continuare ” să fie falsă și ” instrucțiune1 ” să nu se mai execute.


Pentru a exemplifica și mai mult vom scrie programul pentru cazul nostru și îl vom comenta amănunțit.

int timpAsteptare=100;
int i;
void setup()
{
                for ( i=2; i<=11; i++ )  {
                                                                pinMode( i, OUTPUT );
                                                        }
}
void loop()
{
                for ( i=2; i<=11; i++ )        {
                                                                                digitalWrite( i-1, LOW);
                                                                                digitalWrite( i, HIGH);
                                                                                delay( timpAsteptare );
                                                                }
                for ( i=11; i >= 2; i-- )        {
                                                                                digitalWrite( i, LOW );
                                                                                digitalWrite( i-1, HIGH );
                                                                                delay( timpAsteptare );
                                                                }
}


După cum știți în funcția ” setup () ” vom pune datele de configurare a microcontrolerului ( pini folosiți, starea pinilor, etc....). În cazul nostru, ca și în prima variantă, vom configura pinii folosiți și starea lor ( de intrare sau de ieșire ). În prima variantă de program am scris fiecare pin și starea lui, acum am făcut același lucru doar că am scris mult mai puțin.
În continuare am să explic cum funcționează instrucțiunea ” for ” :
                for ( i=2; i<=11; i++ )  {
                                                                pinMode( i, OUTPUT );
                                                        }
  • ·         i = 2 → variabila de inițializare, adică i va porni de la valoarea 2.
  • ·         i <= 11 → condiție_continuare, adică instrucțiunea pinMode( i, OUTPUT); se va executa până când condiție_continuare va fi falsă.
  • ·         i++ → re-evaluare, modifică variabila de control ( i ) astfel încât la un moment dat, știut de noi, condiție_continuare va fi falsă și se va opri executarea instrucțiunii pinMode( i , OUTPUT );

Iată funcționarea pas cu pas:
  • ·         i = 2 → se verifică dacă i <= 11 ( 2 <= 11), ceea ce este adevărat; fiind adevărată se va executa instrucțiunea pinMode(2, OUTPUT), care inițializează pinul 2 ca fiind de ieșire. După aceasta se va executa i ++ , în cazul nostru i va fi 3.
  • ·         i = 3 → se verifică daca i <= 11 ( 3 <=11) ceea ce este adevărat; fiind adevărată se va executa instrucțiunea pinMode( 3, OUTPUT) , care inițializează pinul 3 ca fiind de ieșire. După aceasta se va executa i ++ , în cazul nostru i va fi 4.
  • ·         ...............................................................................................
  • ·         ................................................................................................
  • ·         i = 12 → se verifică dacă i <= 11 ( 12 <= 11), ceea ce este fals și în acest caz nu se mai execută instrucțiunea pinMode( 12,OUTPUT ) iar execuția lui ”for” se va termina.

Acestea fiind spuse vă voi scrie mai jos ambele variante a funcției  setup() ” și vă las pe voi să decideți dacă merită folosirea instrucțiunii  for ” sau nu :


Prima variantă ( varianta I )
void setup()
{
                pinMode( led1, OUTPUT );
                pinMode( led2, OUTPUT );
                pinMode( led3, OUTPUT );
                pinMode( led4, OUTPUT );
                pinMode( led5, OUTPUT );
                pinMode( led6, OUTPUT );
                pinMode( led7, OUTPUT );
pinMode( led8, OUTPUT );
                pinMode( led9, OUTPUT );
                pinMode( led10, OUTPUT );
}


Varianta a doua ( cu ” for ” )
void setup()
{
                for ( i=2; i <= 11; i++ )
 {
                                pinMode( i, OUTPUT );
                  }
}


Acum trecem  la funcția  ” loop () ”:
 for ( i=2; i<=11; i++ )      
{
                                                digitalWrite( i-1, LOW);
                                                digitalWrite( i, HIGH);
                                                delay( timpAsteptare );
                                }
  • ·         i = 2 → verifică condiția i<=11 ( 2 <= 11 ), este adevărată și se va executa următoarele instrucțiuni:

ü  digitalWrite( i-1, LOW) în cazul nostru digitalWrite( 1, LOW ) ceea ce înseamnă că la pinul 1 vom avea 0 ( zero) logic rezultând stingerea ledului conectat la pinul 1. Această instrucțiune va stinge ledurile din urma celui ce urmează a fi aprins.
ü  digitalWrite( i, HIGH ), în cazul nostru digitalWrite(2, HIGH ) ceea ce înseamnă că la pinul 2 vom avea 1 logic rezultând aprinderea ledului conectat la pinul 2.
ü  delay( timpAsteptare), ledul 2 va sta aprins timp de 100ms.
După executarea acestor instrucțiuni se va executa i ++, din cadrul instrucțiunii ” for ”, ceea ce înseamnă în cazul nostru că i va lua valoarea 3 ( i = 3 ).
  • ·         i = 3 → funcționare identică, dar cu i = 3.

·         ...........
  • ·         i = 12 → se verifică condiția de continuare i <= 11 ( 12 <= 11 ), neadevărată de data aceasta rezultând oprirea executării instrucțiunilor și implicit a instrucțiunii ” for ”.

Pentru cealaltă instrucțiune ” for ” din cadrul funcției ” loop() ” explicațiile sunt identice.
Sper că m-am făcut înțeles cu privire la cele două variante de program și la condițiile de utilizare.

Varianta III ( utilizând vectori )

Următoarea variantă de program este pentru cazul general, ca și prima variantă, dar folosind instrucțiunea ” for ” și tablouri unidimensionale sau vector. Caz general înseamnă că putem conecta led-urile la orice pin, în orice ordine, etc.... .
O scurtă introducere pentru noțiunea de tablou unidimensional sau vector.
De multe ori am vrea să lucrăm cu o colecție de date, de un anumit tip, fără a avea multe variabile de declarat.
                Ex. Vreau să am o zonă de memorie în care să înmagazinez 100 de numere întregi și apoi să mă joc cu ele dar fără a declara 100 de variabile pentru a le accesa.

Def: Tablou unidimensional → o colecție finită de elemente de același tip care ocupă un spațiu continuu de memorie.
Pentru a fi mai explicit încerc să dau un exemplu grafic : 

Ex: Dacă vreau să memorez numerele întregi de la 1 la 10, tabloul unidimensional ( vector ) va arăta așa:



              Ex: Dacă vrem să memorăm 10 numere aleatoare, tabloul unidimensional va arăta astfel:


Acestea fiind spuse, pentru a crea, declara un vector vom avea nevoie de:
  • ·         dimensiune ( câte locații de memorie avem nevoie )
  • ·         tip ( ce fel de date vom memora:întregi, caractere, etc... .)
  • ·         nume ( vectorul trebuie să aibă un nume )

Sintaxa de declarare și creare:
                tip nume_tablou[ dimensiune ] = { data1, data2,.... };
                ex: declarăm un vector care să conțină 5 numere întregi:


ex: declarăm un vector care să conțină caractere dar cu dimensiunea ce o vom specifica în timpul programului sau în interiorul acestuia.
                                char c[ n ];    
      
Am văzut ce înseamnă un vector, cum îl declarăm dar mai trebuie să îl prelucrăm, adică să accesăm datele din el. În această etapă intervine instrucțiunea ” for ” pe care am prezentat-o la crearea programului anterior.

Avem vectorul :
                                                  
0
1
7
4
5
10
200
1
  • ·         ca să accesăm datele din el ne vom folosi de o variabilă index ce va trece pe la fiecare locație ( căsuță ) din vector 

  • ·         folosim instrucțiunea ” for ” pentru a deplasa variabila index

                         for ( i=1; i <= 8; i++ )
                                   i = 1 → accesăm a[ i ] = a[ 1 ] → prima locație → valoarea 0

                                   i = 2 → accesăm a[ i ] = a[ 2 ] → a doua locație → valoarea  1

                                   .......s.a.m.d. până la i=8.......................................................

Sper că ați înțeles ceva până acum !!!!!!!!!

În continuare vom scrie programul pentru cazul general ( nu contează ordinea de conectare a led-urilor ) folosind vectori.

Schema va fi identică, ceea ce implică că și pinii folosiți sunt aceiași.

byte pinled[ 10 ] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

int timpAsteptare=100;
void setup()
{
                                                   for ( int i=1; i <= 10; i++ )
                                                                pinMode( pinled[i], OUTPUT);
}
void loop ()
{
                                                   for (int i=1; i <= 10; i++)
                                                   {
                                                                digitalWrite( pinled[i-1], LOW);
                                                                digitalWrite( pinled[ i ], HIGH);
                                                                delay(timpAsteptare);
                                                   }
                                                   for(int i = 10; i >= 1; i--)
                                                   {
                                                                digitalWrite( pinled[i], LOW);
                                                                digitalWrite( pinled[ i-1 ], HIGH);
                                                                delay(timpAsteptare);
                                                   }
}

Observăm că acest program seamănă mult cu cel de dinainte, diferența fiind apariția vectorului.
Să începem explicațiile:
·        
  •       am declarat vectorul pinled[ 10 ] având dimensiunea 10, tipul este ” byte ” în care am memorat pinii la care sunt conectate cele 10 led-uri





Acum în funcția setu() am transformat acești pini în pini de ieșire, bineînțeles ca să putem aprinde și stinge led-urile.
                                                   for ( int i=1; i <= 10; i++ )
                                                                pinMode( pinled[i], OUTPUT);

  • ·         Pentru i = 1 → pinMode(pinled[ 1 ], OUTPUT); la pinled[ 1 ] avem pinul 2 și rezultă că pinul 2 este transformat în pin de ieșire. Apoi i se incrementează cu 1 ( i++ )

  • ·         Pentru i = 2 → pinMode(pinled[ 2 ], OUTPUT); la pinled[ 2 ] avem pinul 3 și rezultă că pinul 3 este transformat în pin de ieșire. Apoi i se incrementează cu 1 ( i++ )

  • ·         .......

  • ·         Și așa mai departe

  • ·         ......

  • ·         Pentru i = 10 → pinMode(pinled[ 10 ], OUTPUT); la pinled[ 10 ] avem pinul 11 și rezultă că pinul 11 este transformat în pin de ieșire. Apoi i se incrementează cu 1 ( i++ )

  • ·         Pentru i = 11 → se oprește execuția lui ” for ” pentru că condiția de verificare ” i<=10 ” devine falsă.


În funcția  ” loop() ” lucrurile sunt la fel ca și în funcția  ” setup () ”, explicația fiind asemănătoare.