Laboratorul 02: Rețele de senzori wireless - Basics

Microcontrolere

Ca să recapitulăm ce ați învățat la cursurile de Proiectarea cu Microprocesoare, un microcontroler este un tip de circuit care integrează un microprocesor şi alte dispozitive periferice într-un singur chip punandu-se accent pe un cost redus de producţie şi consum redus de energie electrică. Principala diferenţă dintre un microcontroller (µC) şi un microprocesor (µP) o constituie faptul că un µC integrează memoria de program, memoria de date şi alte interfeţe de intrare-ieşire sau periferice.

Pentru că integrează un număr mare de periferice şi au un cost redus de producţie, un µC operează la frecvenţe reduse, în general la zeci sau sute de MHz. Cu toate acestea, microcontrolerele se pretează la o gamă variată de aplicaţii fiind folosite atât în mediul industrial cât şi în produse de larg consum, de la sisteme din industria aerospaţială până la telefoane mobile, cuptoare cu microunde şi jucării. Spre deosebire de µP, microcontroler-ul execută un program încărcat pe acesta şi dedicat unei singure funcţionalităţi.

ATmega128RFA1 reprezintă un microcontroler cu o arhitectură pe 8 biţi. Ca urmare, registrele şi magistrala internă de date sunt pe 8 biţi. Totuşi, în codul C se pot folosi variabile întregi pe 32 de biţi şi chiar în virgulă mobilă. Compilatorul este cel care se ocupă de translatarea instrucţiunilor cu variabile pe 32 de biţi în cod asamblare care lucrează pe 8 biţi.

Caracteristicile procesorului folosit în cadrul laboratorului - Atmega128RFA1:

  • 128KB Flash, sau dimensiunea maximă a programului care poate fi scris in microcontroller
  • 4KB EEPROM
  • 16KB RAM
  • transceiver radio IEEE 802.15.4 în banda de 2.4GHz încorporat
  • frecvența maximă de lucru de 16Mhz
  • tensiune de alimentare între 1.8 și 3.6V
  • timere cu canale PWM multiple
  • canale de ADC multiple, precizie de 10 biți (situate pe portul F)
  • cinci porturi de I/O digitale (de la portul B la G)
  • interfeţe seriale: USART, SPI, TWI (two-wire serial interface)
  • interfaţă programare JTAG

Perifericele interne chip-ului pot fi accesate din exterior prin intermediul pinilor porturilor (cinci porturi B, D, E, F a câte 8 pini, respectiv portul G cu doar 6 pini), prezentați în figura de mai jos:

Nodurile senzoriale Sparrow

Sparrow este o arhitectură de reţea wireless de senzori care a fost construită ca o platformă de cercetare pentru rețelele wireless de senzori, în special pentru a pune în practică tehnici de recoltare de energie. Acesta a fost, de asemenea, folosită pentru a implementa şi testa o serie de aplicaţii fără fir, inclusiv IEEE 802.15.4, 6LoWPAN şi reţele ZigBee. Arhitectura unui nod Sparrow este dată în figura de mai jos.

 Arhitectura nodului senzorial Sparrow

După cum se poate vedea din figură, în centrul nodului senzorial se află microcontroler-ul Atmega128RFA1, la care sunt legați o serie de senzori pe interfața I2C. Veți folosi acești senzori în timpul lucrărilor de laborator.

Mediul de dezvoltare

Configurarea IDE-ului Arduino pentru Sparrow

  1. Instalați ultima versiune a Arduino IDE
  2. În IDE, mergeți la File → Preferences
  3. La Additional Boards Manager URLs adăugați textul următor:
     http://clkdiv8.com/download/package_clkdiv8pre_index.json
  4. Închideți fereastra
  5. Mergeți la Tools → Board → Boards Managerși căutați Sparrow, apoi apăsați Install
  6. După o instalare de succes, o să vedeți la meniul Tools → Board un nou tip de placă în listă numit Sparrow, selectați-l
  7. Introduceți cablul USB al plăcii în calculator, ar trebui să vi se instaleze un port serial nou
  8. Asigurați-vă că portul nou este selectat în meniul Tools → Port

You're all set up!

Hello LED cu Arduino IDE si Sparrow V4

Vom testa un program care stinge și aprinde un LED la interval de 1000ms. Acest lucru se face modificând starea logică a unuia din pinii microcontroller-ului.

Vom folosi funcțiile de bibliotecă Arduino:

int ledPin = 11;                // LED (Green) connected to digital pin 11
 
void setup()                    // run once, when the sketch starts
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
}
 
 
void loop()                     // run over and over again
{
  digitalWrite(ledPin, HIGH);   // sets the LED off (reverse logic)
  delay(1000);                  // waits for a second
  digitalWrite(ledPin, LOW);    // sets the LED on
  delay(1000);                  // waits for a second
}

Pentru a compila şi executa codul de mai jos pe un nod Sparrow folosind Arduino IDE paşii sunt următorii:

  1. Se creează un proiect nou şi se copiază codul de mai jos (File→New);
  2. În Tools→Board selectaţi Sparrow;
  3. Se alege portul COM la care a fost conectat nodul din Tools→Serial Port;
  4. Se încarcă proiectul, folosind butonul de Upload.

Task 0

Rulați exemplul de mai sus.

Task 1

Scrieți un program care să cicleze prin toate culorile posibile pentru led-ul RGB.

Led-urile sunt legate la portul B, pinii PB4, PB5 și PB6 (pinii 8, 11, respectiv 10 pentru Arduino). Comanda led-urilor este pe logică inversă (vezi schema de mai jos). Astfel, un led se va aprinde la setarea pin-ului de output pe LOW și se va stinge la o setare a pin-ului pe HIGH.

LED GPIO Pin Pin Arduino
R PB4 8
G PB5 11
B PB6 10







Cum facem să clipească LED-ul fără a folosi delay()

Câteodată trebuie să executăm două acțiuni în paralel. De exemplu, putem să facem un LED să clipească în timp ce interogăm un senzor de efracție. În acest caz nu putem să folosim delay() pentru că am opri întreaga execuție a programului timp de o secundă și programul ar putea să rateze detecția unui eveniment de la senzor. Sketch-ul de mai jos demonstrează cum putem să realizăm aceste task-uri fără a folosi delay(). Programul contorizează numărul de intervale de timp de când starea LED-ului a fost schimbată și modifică starea LED-ului atunci când expiră un anumit număr de intervale de timp.

Codul de mai jos folosește funcția millis() ce returnează numărul de milisecunde ce au trecut de la lansarea în execuție a programului.

Codul C

Codul C

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated
 
// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)
 
void setup() {
  // set the digital pin as output:
  pinMode(11, OUTPUT);     
}
 
void loop()
{
  // here is where you'd put code that needs to be running all the time.
 
  // check to see if it's time to blink the LED; that is, if the
  // difference between the current time and last time you blinked
  // the LED is bigger than the interval at which you want to
  // blink the LED.
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;  
 
    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
    {
        ledState = HIGH;
        digitalWrite(11, HIGH);
    }
    else
    {
      ledState = LOW;
      digitalWrite(11, LOW);
    }
 
  }
}

Task 2

Rulați exemplul de mai sus.

Comunicația serială

Câteodată este foarte util ca nodul senzorial să comunice cu calculatorul de pe care este programat, pentru a trimite datele citite de la senzori sau ca modalitate facilă de debug pentru program.

Codul de mai jos inițializează interfața serială și trimite înapoi caracterele primite de la calculator.

Click to display ⇲

Click to hide ⇱

/*
 Echo
 Reads data from serial, when available, and prints the result to the serial monitor 
 
 This example code is in the public domain.
 */
int incomingByte = 0;
 
void setup() {
  //start serial communication with a baud rate of 9600
  Serial.begin(9600);
}
 
void loop() {
  if(Serial.available() > 0) {
      //read the incoming byte
      incomingByte = Serial.read();
 
      //NOTE: the byte you sent from serial monitor is considered of type char
      //the value of the character '0' is 48 
      //by subtracting 48 from the value returned by the Serial.read() function you get  
      //the actual number you entered in serial monitor
      incomingByte = incomingByte - 48;
 
      //confirm the byte you just received
      Serial.print("I received ");
      Serial.println(incomingByte);
}
}

Task 3: Rulați codul de mai sus

Task 4: Trimiteți pe serială starea LED-ului din primul exemplu de mai sus (cel care clipea LED-ul la o secundă)

Senzori

Măsurarea tensiunii de la baterie folosind convertorul analog-digital

Pentru a putea măsura semnalele analogice într-un sistem de calcul digital, acestea trebuie convertite în valori numerice discrete. Un convertor analog – digital (ADC) este un circuit electronic care convertește o tensiune analogică de la intrare într-o valoare digitală.

Bibliotecile Arduino ne pun la dispoziție funcții dedicate pentru citirea intrărilor analogice. De exemplu, dacă dorim să măsurăm valoarea tensiunii de pe bateria nodului Sparrow, va trebui să citim intrarea analogică A0, la care este conectată bateria:

Măsurarea tensiunii bateriei

Măsurarea tensiunii bateriei

int controlPin = 7; //sensor ON/OFF control pin (PE7)
 
void setup() {
 
  pinMode(controlPin, OUTPUT);  //sensor on/off control
 
  // initialize the serial communication:
  Serial.begin(9600);
}
 
void loop() {
  digitalWrite(controlPin, LOW); //enable all sensors
 
  // wait a bit for the analog-to-digital converter
  // to stabilize after the last reading:
  delay(100);
 
  // send the value of analog input 0:
  Serial.println(analogRead(A0));
 
  digitalWrite(controlPin, HIGH); //disable all sensors
 
 
}

Task 5: Rulați codul de mai sus. Observați că valoarea tensiunii de la baterie nu este exprimată tocmai în Volți. Pentru asta, va trebui să o scalați: convertorul vostru analog digital măsoară în intervalul 0-1.8V cu o precizie de 10 biți. Prin urmare, intervalul de măsură va fi împărțit în 1024 segmente (0 corespunde valorii de 0V iar 1024 valorii de 1.8V). Scalați valoarea de la iețirea ADC-ului astfel încât să fie exprimată în Volți folosind regula de trei simplă.

Senzorul digital de temperatură și umiditate

Si7021 este un senzor integrat pentru măsurarea temperaturii și a umidității ambientale produs de compania SiliconLabs. Avantajele acestuia față de senzorii similari sunt dimensiunile reduse (3mm x 3mm) și faptul că posedă o interfață digitală de comnicație a parametrilor măsurați. Circuitul este construit în tehnologie CMOS și încorporează un senzor capacitiv de umiditate precum și un senzor foarte precis de temperatură ce suferă un process de auto-calibrare la fiecare punere în funcțiune. Rezoluția parametrilor măsurați poate fi selectată din software între 8/12 biți pentru umiditate și 12/14 biți pentru temperatură. Comunicația cu microcontroller-ul se face peste o interfață standard I2C ce permite transferul rapid al datelor și al comenzilor.

Trebuie să instalați o bibliotecă cu driverele pentru acest senzor. Pentru asta mergeți în IDE-ul Arduino la Tools - Manage Libraries și căutați Sodaq_SHT2x, apoi instalați.

După aceşti paşi se va putea importa header-ul SHT2x.h în proiectul Arduino: #include “SHT2x.h”, aşa cum se va vedea în proiectul următor.

Notă: Dacă IDE-ul era pornit, va fi nevoie de un restart.

Codul pentru măsurarea temperaturii

Codul pentru măsurarea temperaturii

#include <Wire.h>
#include <Sodaq_SHT2x.h>
 
int controlPin=7;
 
void setup()
{
  pinMode(controlPin, OUTPUT);  //sensor on/off control
 
  Wire.begin();
  Serial.begin(9600);
}
 
void loop()
{
  digitalWrite(controlPin, LOW); //enable all sensors
 
  Serial.print("Humidity(%RH): ");
  Serial.print(SHT2x.GetHumidity());
  Serial.print("     Temperature(C): ");
  Serial.println(SHT2x.GetTemperature());
 
  digitalWrite(controlPin, HIGH); //disable all sensors
 
  delay(1000);
}

Senzorul digital de măsurare a luminozității

Pentru a citi date de la acest senzor s-a folosit biblioteca Adafruit_SI1145.

La fel ca mai sus, căutați biblioteca Adafruit_SI1145 în fereastra Manage Libraries și instalați-o.

După aceşti paşi se va putea importa header-ul Adafruit_SI1145.h în proiectul Arduino: #include “Adafruit_SI1145.h”, aşa cum se va vedea în proiectul următor.

Notă: Dacă IDE-ul era pornit, va fi nevoie de un restart.

Măsurarea luminozității

Măsurarea luminozității

#include <Wire.h>
#include "Adafruit_SI1145.h"
 
int controlPin = 7;
Adafruit_SI1145 uv = Adafruit_SI1145();
 
void setup() {
  pinMode(controlPin, OUTPUT);  //sensor on/off control
  digitalWrite(controlPin, LOW);
  delay(1000);
 
  Serial.begin(9600);
 
  Serial.println("Adafruit SI1145 test");
 
  if (! uv.begin()) {
    Serial.println("Didn't find Si1145");
    while (1);
  }
 
  Serial.println("OK!");
}
 
void loop() {
 
  Serial.println("===================");
  Serial.print("Vis: "); Serial.println(uv.readVisible());
  Serial.print("IR: "); Serial.println(uv.readIR());
 
  // Uncomment if you have an IR LED attached to LED pin!
  //Serial.print("Prox: "); Serial.println(uv.readProx());
 
  float UVindex = uv.readUV();
  // the index is multiplied by 100 so to get the
  // integer index, divide by 100!
  UVindex /= 100.0;  
  Serial.print("UV: ");  Serial.println(UVindex);
 
  delay(1000);
}

Senzorul barometric

Nodurile Sparrow folosesc senzorul MS5637 pentru măsurarea presiunii atmosferice și altimetrie. Vom folosi biblioteca Freetronics pentru a interfața cu el.

La Manage Libraries căutați BaroLibrary MS5637 și apoi instalați

Măsurarea presiunii

Măsurarea presiunii

#include <Wire.h>
#include <BaroSensor.h>
int controlPin = 7;
 
void setup()
{
  pinMode(controlPin, OUTPUT);  //sensor on/off control
  delay(100);
 
  digitalWrite(controlPin, LOW);
 
  Serial.begin(9600);
  BaroSensor.begin();
}
 
void loop()
{
  if(!BaroSensor.isOK()) {
    Serial.print("Sensor not Found/OK. Error: "); 
    Serial.println(BaroSensor.getError());
    BaroSensor.begin(); // Try to reinitialise the sensor if we can
  }
  else {
    Serial.print("Temperature: "); 
    Serial.println(BaroSensor.getTemperature());
    Serial.print("Pressure:    ");
    Serial.println(BaroSensor.getPressure());
  }
  delay(1000);
}

Task 6: Instalați bibliotecile pentru cei trei senzori și rulați exemplele de cod de mai sus.

Afișarea datelor de la senzori cu Serial Plotter

În exemplul de mai jos vom vedea cum putem să trimitem un octet de date de la placa Sparrow la PC și să afișam grafic rezultatul. Comunicația se va face peste interfața serială, dar datele vor fi preluate de către un alt program care va fi responsabil pentru desenarea graficului pe ecran.

Bineînțeles, puteți folosi Serial Monitor ca și până acum pentru a vizualiza datele în formă text, dar pentru a le afișa sub formă grafică avem nevoie de Serial Plotter (tot din meniul Arduino).

Sintaxa Serial Plotter este simplă și poate fi consultată pe pagina dedicată.

Task 7: Folosind sintaxa Serial Plotter și exemplele de cod de mai sus, scrieți un program care să citească date de la toți senzorii de pe placa Sparrow și să îi trimită pe serială pentru a fi afișati simultan. Folosiți etichetele “Temperature: ”, “Humidity: ”, “Light: ”, “IR: ”, “Pressure: ” pentru Serial Plotter

priot/laboratoare/02.txt · Last modified: 2024/10/15 19:11 by alexandru.bala
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0