Sări la conţinut

5 exerciții Arduino utilizând un singur shield

Primii pași în înțelegerea modului de funcționare și de programare a plăcilor de dezvoltare Arduino sunt însoțiți inevitabil de multe încercări dificile datorită montajelor electronice ce trebuie realizate pentru a duce la bun sfârșit exercițiile propuse. În cadrul materialului de față vă propune depășirea acestei probleme și accelerarea implementării unor exerciții interesante utilizând un shield Arduino multifuncțional ce include mai multe componente hardware: afișaj cu 4 caractere pe 7 segment, buzzer, 3 butoane, potențiometru, 4 LED-uri și interfețe de conectare pentru alte componente. Mai este necesară o placă de dezvoltarea Arduino UNO și ne putem apuca de lucru.

Exercițiul 1 – Să învățăm să numărăm în binar

În cadrul acestui exercițiu vom implementa un numărător:

  • pe ecran se va afișa un număr între 0 și 15;
  • numărul va fi incrementat de apăsarea butonului B1, decrementat de apăsarea butonului B2 și resetat la 0 de apăsarea butonului B3;
  • cele 4 leduri vor afișa „în binar” valoarea afișată în baza 10 pe ecran (pentru 1 va fi aprins primul LED, pentru 2 va fi aprins al doilea LED, pentru 3 vor fi aprinse primul și al doilea LED ș.a.m.d.).

Programul va realiza în primul rând inițializările necesare (mai ales pinii la care sunt conectate componentele shield-ului și valorile necesare afișării pe ecranul pe 7 segmente):

const byte LED[] = {13,12,11,10};

#define BUTTON1 A1

#define BUTTON2 A2

#define BUTTON3 A3

#define LATCH_DIO 4

#define CLK_DIO 7

#define DATA_DIO 8

const byte SEGMENT_MAP[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};

const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8};

int number;

În secțiunea setup() se vor inițializa pinii plăcii de dezvoltare:

void setup() {

pinMode(LED[0], OUTPUT);

pinMode(LED[1], OUTPUT);

pinMode(LED[2], OUTPUT);

pinMode(LED[3], OUTPUT);

pinMode(BUTTON1, INPUT);

pinMode(BUTTON2, INPUT);

pinMode(BUTTON3, INPUT);

pinMode(LATCH_DIO,OUTPUT);

pinMode(CLK_DIO,OUTPUT);

pinMode(DATA_DIO,OUTPUT);

number=0; }

Secțiunea loop() implementează comportamentul de numărare și afișare pe ecran și pe cele 4 LED-uri. Funcția WriteNumberToSegment() este utilizată pentru a transmite configurația segmentelor către afișaj.

void loop() {

if(!digitalRead(BUTTON1)) {

  number++;

  if (number==16) number=0;

  delay(200);

}

if(!digitalRead(BUTTON2)){

  number–;

  if (number==-1) number=15;

  delay(200);

}

if(!digitalRead(BUTTON3)) {

  number=0;

  delay(200);

}

WriteNumberToSegment(3 , number%10);

WriteNumberToSegment(2 , number/10);

digitalWrite(LED[3],!(number%2));

digitalWrite(LED[2],!((number/2)%2));

digitalWrite(LED[1],!((number/4)%2));

digitalWrite(LED[0],!((number/8)%2));

}

void WriteNumberToSegment(byte Segment, byte Value) {

digitalWrite(LATCH_DIO,LOW);

shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_MAP[Value]);

shiftOut(DATA_DIO, CLK_DIO, MSBFIRST,  SEGMENT_SELECT[Segment] );

digitalWrite(LATCH_DIO,HIGH); }

Exercițiul 2 – Numărătoare inversă

În cel de al doilea exercițiu vom implementa un sistem de numărătoare inversă plecând de la un interval de tip MM:SS (minute și secunde). Cu ajutorul butoanelor B1 și B2 vom stabili intervalul (minutele și secundele) iar butonul B3 va porni numărătoarea inversă. Numărătoare nu poate fi întreruptă decât dacă apăsăm butonul de RESET. La sfârșitul numărării se va declanșa o alarmă sonoră (spre deosebire de exercițiul precedent vom utiliza buzzerul prezent pe shield). Programul folosește funcția millis() pentru a estima trecerea unei secunde.

#define BUTTON1 A1

#define BUTTON2 A2

#define BUTTON3 A3

#define LATCH_DIO 4

#define CLK_DIO 7

#define DATA_DIO 8

#define BEEPER_PIN 3

const byte SEGMENT_MAP[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};

const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8};

int m, s, onoff;

static unsigned long lastSampleTime;

void setup() {

  pinMode(BUTTON1, INPUT);

  pinMode(BUTTON2, INPUT);

  pinMode(BUTTON3, INPUT);

  pinMode(LATCH_DIO,OUTPUT);

  pinMode(CLK_DIO,OUTPUT);

  pinMode(DATA_DIO,OUTPUT);

  pinMode(BEEPER_PIN, OUTPUT);

  digitalWrite(BEEPER_PIN, HIGH);

  m=0; s=0; onoff=0;

}

void loop() {

  WriteNumberToSegment(3 , s%10);

  WriteNumberToSegment(2 , s/10);

  WriteNumberToSegment(1 , m%10);

  WriteNumberToSegment(0 , m/10);

  if (onoff) {

    if ((s==0)&&(m==0)) {

        onoff=!onoff;

        for(int hz = 440; hz < 1000; hz++){

          tone(BEEPER_PIN, hz, 50);

          delay(5);

        }

        noTone(BEEPER_PIN);

        for(int hz = 1000; hz > 440; hz–){

            tone(BEEPER_PIN, hz, 50);

            delay(5);

        }

        noTone(BEEPER_PIN);

        digitalWrite(BEEPER_PIN, HIGH);

        }

   else {

      if (millis()-lastSampleTime>=1000) {

        lastSampleTime+=1000;

        s–;

        if (s==-1) { m–; s=59; }

    } }

  }

  else {

    if(!digitalRead(BUTTON1)) {

      s++;

      if (s==60) s=0;

      delay(200);

    }

    if(!digitalRead(BUTTON2)){

      m++;

      if (m==60) m=0;

      delay(200);

    }

    if(!digitalRead(BUTTON3)) {

       onoff=!onoff;

       lastSampleTime=millis();

       delay(200);

    }

  }

}

void WriteNumberToSegment(byte Segment, byte Value) {

  digitalWrite(LATCH_DIO,LOW);

  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_MAP[Value]);

  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_SELECT[Segment] );

  digitalWrite(LATCH_DIO,HIGH); }

Exercițiul 3 – Ceasul falsificat

Exercițiul 3 propune implementarea unui ceas – ecranul va afișa ora (HH:MM – ore și minute). Butonul B1 va permite potrivirea orei iar butonul B2 potrivirea minutelor. În cadrul acestui exercițiu vom exemplifica și utilizarea potențiometrului aflat pe shield. Cu ajutorul acestuia vom ajusta (falsifica) durata unei secunde. Citirea potențiometrului returnează valori între 0 și 1023 – aceste valori vor fi folosite ca număr de microsecunde pentru o secundă, cu alte cuvinte putem face ca ceasul să meargă mai repede sau mai încet. Cele patru LED-uri de pe shield vor indica nivelul aproximativ al falsificării.

const byte LED[] = {13,12,11,10};

#define BUTTON1 A1

#define BUTTON2 A2

#define LATCH_DIO 4

#define CLK_DIO 7

#define DATA_DIO 8

#define POT 0

const byte SEGMENT_MAP[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};

const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8};

int m, h, s, sec, secled;

static unsigned long lastSampleTime;

void setup() {

  pinMode(LED[0], OUTPUT);

  pinMode(LED[1], OUTPUT);

  pinMode(LED[2], OUTPUT);

  pinMode(LED[3], OUTPUT);

  pinMode(BUTTON1, INPUT);

  pinMode(BUTTON2, INPUT);

  pinMode(LATCH_DIO,OUTPUT);

  pinMode(CLK_DIO,OUTPUT);

  pinMode(DATA_DIO,OUTPUT);

  m = 0; h = 0; s=0;

  lastSampleTime=millis();

}

void loop() {

  sec = analogRead(POT);

  WriteNumberToSegment(3 , m%10);

  WriteNumberToSegment(2 , m/10);

  WriteNumberToSegment(1 , h%10);

  WriteNumberToSegment(0 , h/10);

  secled = map(sec, 0, 1025, 0, 16);

  digitalWrite(LED[3],!(secled%2));

  digitalWrite(LED[2],!((secled/2)%2));

  digitalWrite(LED[1],!((secled/4)%2));

  digitalWrite(LED[0],!((secled/8)%2));

  if(!digitalRead(BUTTON1)) {

    m++;

    if (m==60) m=0;

    delay(200);

  }

  if(!digitalRead(BUTTON2)) {

    h++;

    if (h==24) h=0;

    delay(200);

  }

  if (millis()-lastSampleTime>=sec) {

        lastSampleTime+=sec;

        s++;

        if (s==60) {

          s=0;

          m++;

          if (m==60) { h++; m=0; if(h==24) h=0; }

        }

   }

}

void WriteNumberToSegment(byte Segment, byte Value) {

digitalWrite(LATCH_DIO,LOW);

shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_MAP[Value]);

shiftOut(DATA_DIO, CLK_DIO, MSBFIRST,  SEGMENT_SELECT[Segment] );

digitalWrite(LATCH_DIO,HIGH); }

Exercițiul 4 – Ghicește numărul

La fel ca și în exercițiul precedent vom stabili cu ajutorul potențiometrului o valoare între 0 și 1023 pe care va trebui să o ghicim. Cu ajutorul butoanelor B1 (incrementare) și B2 (decrementare) vom stabili valoarea pe care o propunem iar cu ajutorul butonului B3 vom verifica dacă valoarea stabilită este egală cu valoarea de ghicit. Dacă valoarea este greșită se va genera un sunet de eroare, dacă valoarea este corectă se declanșează un joc de lumini pe cele 4 LED-uri ale shield-ului și programul se blochează (se poate relua prin apăsarea butonului RESET).

#define BUTTON1 A1

#define BUTTON2 A2

#define BUTTON3 A3

#define LATCH_DIO 4

#define CLK_DIO 7

#define DATA_DIO 8

#define POT 0

#define BEEPER_PIN 3

const byte LED[] = {13,12,11,10};

const byte SEGMENT_MAP[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};

const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8};

int nr1, nr2;

void setup() {

  pinMode(LED[0], OUTPUT);

  pinMode(LED[1], OUTPUT);

  pinMode(LED[2], OUTPUT);

  pinMode(LED[3], OUTPUT);

  digitalWrite(LED[0], HIGH);

  digitalWrite(LED[1], HIGH);

  digitalWrite(LED[2], HIGH);

  digitalWrite(LED[3], HIGH);

  pinMode(BUTTON1, INPUT);

  pinMode(BUTTON2, INPUT);

  pinMode(BUTTON3, INPUT);

  pinMode(LATCH_DIO,OUTPUT);

  pinMode(CLK_DIO,OUTPUT);

  pinMode(DATA_DIO,OUTPUT);

  pinMode(BEEPER_PIN, OUTPUT);

  digitalWrite(BEEPER_PIN, HIGH);

  nr2=0;

}

void loop() {

  nr1 = analogRead(POT);

  WriteNumberToSegment(3 , nr2%10);

  WriteNumberToSegment(2 , (nr2/10)%10);

  WriteNumberToSegment(1 , (nr2/100)%10);

  WriteNumberToSegment(0 , nr2/1000);

  if(!digitalRead(BUTTON1)) {

    nr2++;

    if (nr2==1024) nr2=0;

    delay(200);

  }

  if(!digitalRead(BUTTON2)) {

    nr2–;

    if (nr2==-1) nr2=1023;

    delay(200);

  }

  if(!digitalRead(BUTTON3)) {

    if(nr1==nr2) {

      while(1) {

        for(int i=0; i<4; i++) {

          digitalWrite(LED[i],LOW);

          delay(200);

        }

        for(int i=0; i<4; i++) {

          digitalWrite(LED[i],HIGH);

          delay(200);

        }

      }

    }

    else {

        for(int hz = 1000; hz > 440; hz–){

          tone(BEEPER_PIN, hz, 50);

          delay(5);

        }

        noTone(BEEPER_PIN);

        digitalWrite(BEEPER_PIN, HIGH);

    }

    delay(200);

  }

}

void WriteNumberToSegment(byte Segment, byte Value) {

digitalWrite(LATCH_DIO,LOW);

shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_MAP[Value]);

shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_SELECT[Segment] );

digitalWrite(LATCH_DIO,HIGH);}

Exercițiul 5 – Termometru cu alarmă

Pentru ultimul exercițiu vom utiliza o componentă suplimentară: un senzor de temperatură digital DS18B20. Acesta se va conecta la shield în conectorul U5 (aveți grijă la polaritate):

2

Programul va prelua de la senzor și va afișa pe ecran valoarea temperaturii. Funcția WriteNumberToSegment() a fost modificată față de exercițiile precedente pentru a afișa punctul zecimal. În cazul în care temperatura citită este peste o limită (în programul de mai jos limita este 33C) se declanșează o alarmă sonoră. Programul folosește bibliotecile OneWire și DallasTemperature pentru comunica cu senzorul de temperatură.

#include <OneWire.h>

#include <DallasTemperature.h>

#define LATCH_DIO 4

#define CLK_DIO 7

#define DATA_DIO 8

#define BEEPER_PIN 3

#define ONE_WIRE_BUS A4

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

const byte SEGMENT_MAP[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};

const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8};

float temp;

static unsigned long lastSampleTime;

void setup() {

  sensors.begin();

  pinMode(LATCH_DIO,OUTPUT);

  pinMode(CLK_DIO,OUTPUT);

  pinMode(DATA_DIO,OUTPUT);

  pinMode(BEEPER_PIN, OUTPUT);

  digitalWrite(BEEPER_PIN, HIGH);

  lastSampleTime=millis();

}

void loop() {

  if (millis()-lastSampleTime>=5000) {

    sensors.requestTemperatures();

    temp = sensors.getTempCByIndex(0);

    lastSampleTime=millis();

    if (temp>33) {

      for(int hz = 440; hz < 1000; hz++){

          tone(BEEPER_PIN, hz, 50);

          delay(5);

        }

      noTone(BEEPER_PIN);

      for(int hz = 1000; hz > 440; hz–){

            tone(BEEPER_PIN, hz, 50);

            delay(5);

        }

      noTone(BEEPER_PIN);

      digitalWrite(BEEPER_PIN, HIGH);

    }

  }

  WriteNumberToSegment(3 , (int)(temp*100)%10, false);

  WriteNumberToSegment(2 , (int)(temp*10)%10, false);

  WriteNumberToSegment(1 , (int)temp%10, true);

  WriteNumberToSegment(0 , (int)temp/10, false); 

}

void WriteNumberToSegment(byte Segment, byte Value,

boolean dot) {

  digitalWrite(LATCH_DIO,LOW);

  if (dot)

    shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, (SEGMENT_MAP[Value] – 0x80));

  else

    shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_MAP[Value]);

  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_SELECT[Segment] );

  digitalWrite(LATCH_DIO,HIGH);

}

Pentru mai multe exemple utilizând shield-ul din această lecție puteți parcurge și materialul: „Using an Arduino Multi-function Shield”.