Wireless Sensor Networks

Arhitectura unei retele wireless de senzori

Reţelele de senzori wireless sunt o tehnologie care poate oferi o contribuţie semnificativă pentru atingerea paradigmei de “ubiquitous computing”. Acestea ar trebui să reprezinte o nouă revoluţie în domeniul calculatoarelor, la fel cum au fost calculatoarele mainframe şi computerele personale înaintea lor. Importanţa tot mai mare de contextualizării informației a determinat apariția unei suite întregi de aplicații inteligente care facilitează integrarea lumii digitale în cea fizică. Micșorarea consumului de energie, în special, devine un subiect tot mai important în vieţile noastre. Reţelele de senzori wireless sunt supuse unor constrângeri severe, care sunt de obicei dependente de aplicaţiile ce rulează pe acestea. Restricțiile sunt date de obicei de dimensiune, număr de noduri, disponibilitatea unei surse de energie şi capabilități de procesare. Cu toate acestea, o constrângere care prevalează în aproape toate aplicaţiile ce folosesc rețele de senzori este autonomia reţelei, ceea ce se definește prin capabilitatea acesteia de-a se auto-organiza, gestiona şi repara, fără a fi nevoie de intervenția umană.

Arhitectura unei retele de senzori wireless este data in figura de mai jos:

Dupa cum se poate observa, grosul retelei este format din zeci, poate chiar sute de noduri senzoriale care ruleaza toate mai mult sau mai putin acelasi program. De cele mai multe ori programul implica un proces care colecteaza date din mediu si le trimite catre un nod sink si un alt proces care executa eventualele comenzi venite de la coordonatorul retelei (nodul gateway).

De cele mai multe ori este necesara dezvoltarea unui algoritm distribuit care sa ruleze la nivelul intregii retele pentru a permite schimbul de mesaje intre noduri intr-o maniera multi-hop. Implementarea real-life a unui algoritm de acest gen este greoaie, in special din cauza numarului mare de noduri care trebuie reprogramate frecvent in faza de development.

Noduri senzoriale wireless

Nodurile senzoriale sunt componentele principale ale unui WSN. Ele au capabilități limitate de comunicare, senzoriale şi de prelucrare de date, datorate costului lor redus. După cum sugerează şi numele, rolul principal al unui nod senzorial este de a măsura parametri din mediul său înconjurător şi de a disemina datele rezultate în rețea. Comunicarea poate funcționa și invers, în cazul în care nodurile primesc comenzi de la entităţile de supraveghere din reţea.

MicaZ Tmote Sparrowv3
CPU Atmega1281 16Mhz MSP430 8MIPS Atmega128RFA1 16MHz
Memory 128KB program memory, 8KB RAM, 512KB serial flash 48KB program flash, 10KB RAM, 1024KB serial flash 128KB program flash, 32KB RAM
Bandwidth 250kbps 250kbps 2Mbps
Programming TinyOS,SOS Contiki, TinyOS, SOS C

Arhitectura tipică a unui nod senzorial este prezentată în figura de mai jos.

<imgcaption archi | Arhitectura unui nod senzorial wireless> </imgcaption>

Componentele principale ale unui nod senzorial sunt microcontroler-ul, transceiver-ul radio, memoria externă, sursa de alimentare şi ansamblul de senzori.

Microcontrolere sunt preferate în proiectarea nodurilor datorită costurilor reduse şi a capacităţilor bune de calcul. În cadrul nodului, rolul lor este de a coordona şi controla funcţionalitatea fiecărei componente şi de a prelucra datele generate de către acestea.

MCU-urile tipice utilizate în nodurile senzoriale sunt arhitecturi pe 8, 16 sau 32-biți bazate pe logica CMOS şi au cantități rezonabile de memorie flash, EEPROM şi RAM ataşate, împreună cu circuite analogice, cum ar fi convertoare analog-digitale şi transceivere radio. Prin urmare, modelarea consumului de energie pentru un astfel de circuit integrat complex nu este o sarcină trivială şi este strâns legată de curentul absorbit de la sursa de alimentare sau baterie.

De obicei, consumul cel mai mare de energie electrică într-un nod este localizat la nivelul transmițătorului radio. Datorită designului lor, transceivere consuma aproape aceeaşi cantitate de energie atunci când recepţionează ca și atunci când emit date. Această energie este, de obicei, cu trei ordine de mărime mai mare decât bugetul mediu de energie al unui microcontroler. Pentru a conserva energie, transceivere au de obicei unul sau două stări low-power (inactiv sau sleep), care le permit să rămână într-o stare latentă şi să fie pornite rapid în cazul recepţiei sau transmisiei de date.

În majoritatea nodurilor senzoriale, circuitele de memorie sunt prezente doar ca parte integrantă a microcontroller-ului, cum ar fi Flash sau RAM. Resursele de memorie pentru un nod tind să fie limitate din cauza costurilor pentru cele mai multe aplicaţii, iar tendința generală este aceea de-a minimiza alocarea memoriei din cauza costului ridicat de scriere şi citire de date.

Datorită arhitecturii low-power și a costului redus, cele mai multe noduri senzoriale utilizează bateriile ca sursă principală de energie. Există mai multe tipuri de baterii care utilizează tipuri diferite de procese chimice, au capacităţi diferite de stocare a energiei și o gamă largă de dimensiuni și costuri. Prin urmare, nu toate bateriile sunt potrivite pentru a fi folosite la alimentarea un nod senzorial şi anumite caracteristici trebuie selectate cu grijă atunci când trebuie luată o decizie legată de tipul bateriei sau acumulatorului care va alimenta nodul respectiv.Majoritatea bateriilor folosite de nodurile wireless se încadrează în trei categorii: NiMH (NiMH), Li-Ion (Li-Ion), şi Litiu Polimer (Li-Po).

Senzorii sau traductoarele sunt elementul principal de măsură al unui nod wireless. Ei sunt responsabili cu conversia un parametru fizic, cum ar fi temperatura sau umiditatea într-o ieşire măsurabilă care pot fi digitizată şi prelucrată de către circuitele nodului.

În funcţie de tipul de senzor şi de precizie, consumul de energie poate varia în mod semnificativ, de la senzori pasivi low-power, cum ar fi accelerometrele, senzorii de temperatură, luminozitate, umiditate, la cei de mare putere, cum ar fi traductoare ultrasonice de nivel, senzori digitali de imagine sau traductoare industriale de presiune.

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.

<imgcaption sparrow | Arhitectura nodului senzorial Sparrow> </imgcaption>

După cum se poate vedea din figură, în centrul nodului senzorial se află microcontroller-ul Atmega128RFA1.

Un microcontroller 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.

Din cauza integrării unui număr mare de periferice şi a costului redus de producţie, un µC operează la frecvenţe reduse, în general la zeci sau sute de MHz. Cu toate acestea, microcontrollerele 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 microcontroller-ul execută un program încărcat pe acesta şi dedicat unei singure funcţionalităţi.

ATmega128RFA1 reprezintă un microcontroller 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.

<imgcaption micro | Microcontroller-ul ATMega128RFA1> </imgcaption> 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:

<imgcaption uc_ports | Porturile digitale de intrare/ieșire pentru ATMega128RFA1> </imgcaption>

Mediul de dezvoltare

Arduino

Arduino este un proiect hardware open source bazat pe microcontroller-ele ATMEGA8 sau ATMEGA168, produse de Atmel. Poate fi folosit pentru a construi obiecte interactive, primind date de intrare de la o gamă variată de senzori şi controlând diverse periferice. Hardware-ul poate fi extins prin diverse module, ale căror scheme sunt publice, astfel încât pot fi la rândul lor extinse şi îmbunătăţite de utilizatori.

Arduino IDE

Mediul integrat de dezvoltare Arduino a fost proiectat astfel încât să fie uşor de folosit de oameni care nu au cunoştinţe avansate de hardware sau software. În acelaşi timp, Arduino IDE este suficient de flexibil pentru a putea fi folosit şi de utilizatorii avansaţi. Bazat pe mediul de dezvoltare Processing, Arduino IDE este open source şi poate fi extins prin librării C++. Nu în ultimul rând, Arduino IDE este disponibil în versiuni pentru Windows, Mac OS şi Linux, cross-platform-ul fiind unul dintre marile sale avantaje.

Sparrow v3

Sparrow v3 este nodul senzorial folosit în cadrul laboratorului de Wireless Sensor Networks şi este echipat cu trei tipuri de senzori: temperatură, umiditate și luminozitate ambientală. Acesta dispune de un microcontroller Atmega128RFA1, care încorporează un transmiţător radio conform cu standardul IEEE 802.15.4, peste care se poate implementa popularul protocol Zigbee.

<imgcaption sparrowv3 | Nodul senzorial Sparrow v3.2></imgcaption>

Zigduino

Zigduino este un shield compatibil cu Arduino care prezintă, ca şi Sparrow v3, un microcontroller Atmega128RFA1. În ceea ce priveşte suportul software, creatorii Zigduino au realizat un fork la repository-ul oficial de Arduino, în care au adus modificările necesare pentru a programa dispozitivul folosind Arduino IDE. Acest suport va fi folosit pentru a programa şi nodul senzorial Sparrow v3.

Configurarea IDE-ului Arduino pentru a suporta Zigduino

Pentru a introduce suportul de Zigduino în Arduino IDE este nevoie să se urmeze paşii de mai jos:

  1. Se instalează Arduino IDE: http://www.arduino.cc/en/Main/Software (versiunea 1.0.5 - Zigduino-1.0 este compatibil doar cu Arduino-1.0x);
  2. Se înlocuieşte folder-ul Arduino\hardware\tools\avr cu Zigduino-1.0-new-extension\hardware\tools\avr;
  3. Se copiază în Arduino\hardware\arduino\cores folder-ul Zigduino-1.0-new-extension\hardware\arduino\cores\zigduino;
  4. Se înlocuieşte fişierul Arduino\hardware\arduino\boards.txt cu Zigduino-1.0-new-extension\hardware\arduino\boards.txt;
  5. Se copiază în Arduino\hardware\arduino\variants folder-ele zigduino _r1 şi zigduino_r2 din Zigduino-1.0-new-extension\hardware\arduino\variants

După aceşti paşi ar trebui să fie vizibile doua intrări pentru Zigduino în Tools→Boards (în meniul Arduino IDE).

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

Instalarea bootloader-ului

Bootloader-ul folosit este Zigduino-1.0-new-extension\hardware\arduino\bootloaders\atmega\ATmegaBOOT_168_atmega128rfa1.hex. Pentru a îl scrie în memoria flash se poate folosi Flash Programmer-ul din AtmelStudio (Tools→Device Programming).

Primii pași: Porturile digitale de I/O

Microntrollerul ATMega128RFA1 oferă 6 porturi I/O, iar intern, fiecare port are asociat trei registre prin care utilizatorul poate controla la nivel de pin fluxul datelor: poate scrie sau citi date din portul respectiv. Aceste trei registre sunt:

DDRn - Data Direction Register în el se stabilește direcţia pinilor portului, dacă sunt de ieşire(1) sau de intrare(0) PORTn - se scriu date pt ieşire sau se activează rezistenţele de pull-up. PINn - se citesc date de pe portul respectiv n poate să fie A, B, C sau D în funcţie de portul selectat.

Exemplu:

  • pe pinul 1 de pe portul B avem un led și pe pinul 2 avem un buton
  • bitul cu indexul 1 (PB1) din registrul DDRB va fi 1
  • bitul cu indexul 2 (PB2) din registrul DDRB va fi 0
  • se va scrie 1/0 bitul 1 din registrul PORTB pentru aprinde/stinge ledul
  • se va citi bitul 2 din registrul PINB pentru a verifica dacă butonul este apăsat sau nu

Descrierea detaliată porturilor şi registrelor corespunzătoare acestora se găseşte în datasheet-ul ATmega128RFA1, în capitolul I/O Ports.

Registrele DDRn, PORTn, PINn, precum şi registrele perifericelor nu fac parte din cele 32 de registre de uz general. Ele nu sunt folosite pentru stocarea datelor, ci au ca rol comunicarea cu perifericul corespunzător. Pentru a face accesul la acestea mai simplu, ele sunt mapate în memorie. Astfel, pentru a scrie o valoare într-un registru este necesar să se scrie valoarea la adresa de memorie corespunzătoare registrului. Adresele lor se pot vedea în datasheet, în capitolul Register Summary, iar în avr-libc sunt definite macrouri pentru fiecare dintre aceste adrese.

Pentru a scrie valoarea unui registru, se poate face direct atribuirea unei valori, însă acest mod nu face codul foarte ușor de înteles, recomandarea fiind de a folosi măștile pe biți sau macro-ul _BV(x) care este echivalent cu (1 << x). De asemenea recomandăm folosirea numelui pinului în loc de a indexului acestuia, pentru ca numele acestora sunt sugestive pentru funcția pe care o îndeplinesc (e.g. la registrul ADCSRA de la convertorul analog-digital, bitul ADEN este bitul de enable). Numele pinilor, ca și în cazul registrelor, sunt deja definite în avr-libc.

<tabcaption op_bytes|Lucrul cu bytes>

Operație Formă
Scriere bit pe 1
Byte |= (1 << Bit_index)
Scriere bit pe 0
 Byte &= ~(1 << Bit_index) 
Toggle bit
 Byte ^= (1 << Bit_index) 
Selectare bit
 Byte & (1 << Bit_index) 

</tabcaption>

DDRB = 8;            // directia pinului 3 este de iesire <--- ASA NU
DDRB = (1<<3);       // nici așa, este hardcodat indexul pinului
DDRB |= (1<<PB3);     // ASA DA
DDRB &= ~(1<<PB3);   // directia pinului 3 devine de intrare

Hello LED cu Arduino IDE si Sparrow v3

Vom testa un program care stinge și aprinde un LED la interval de 1000ms. Acest lucru se face modificând voltajul unuia din pinii microcontroller-ului, în cazul nostru pinul 5 din portul B.

void setup()                    // run once, when the sketch starts
{
  DDRB |= (1<<PB5);      // sets the digital pin PB5 as output
}
 
 
void loop()                     // run over and over again
{
  PORTB ^= (1<<PB5);            //toggles bit
  delay(1000);                  // waits for a second
}

În programul de mai sus se observă folosirea unor macrouri: DDRB și PORTB. Acestea sunt expandate de compilator în locația de memorie unde este mapat registrul de I/O respectiv.

Alternativ, puteți folosi funcțiile de bibliotecă Arduino:

/*
 * Blink
 *
 * The basic Arduino example.  Turns on an LED on for one second,
 * then off for one second, and so on...  We use pin 13 because,
 * depending on your Arduino board, it has either a built-in LED
 * or a built-in resistor so that you need only an LED.
 *
 * http://www.arduino.cc/en/Tutorial/Blink
 */
 
 
int ledPin = 11;                // LED (PB5) 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 on
  delay(1000);                  // waits for a second
  digitalWrite(ledPin, LOW);    // sets the LED off
  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→Programmer se alege USBasp;
  3. În Tools→Board selectaţi Zigduino_r1;
  4. Se alege portul COM la care a fost conectat nodul din Tools→Serial Port;
  5. Se încarcă proiectul, folosind butonul de Upload.

Task 0

Rulați exemplul de mai sus.

Task 1

Implementați folosind cele 3 LED-uri de pe placa de extensie o secvență de aprindere dinamică: *– -*- –*

Led-urile sunt legate la portul B, pinii PB5, PB6 și PB7 (pinii 11, 10, respectiv 9 pentru Arduino).

Cum facem să clipească LED-ul folosind 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.

// 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:
  DDRB |= (1<<PB5);      
}
 
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;
        PORTB |= 1<<PB5;
    }
    else
    {
      ledState = LOW;
      PORTB &= ~(1<<PB5);
    }
 
  }
}

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.

/*
 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 0: Rulați codul de mai sus

Task 1: 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 și a luminozității 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:

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 0: 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ă.

APDS-9002 este un senzor integrat pentru măsurarea iluminării ambientale în capsulă miniatură SMD chipLED produs de compania Agilent.

<imgcaption light | Senzorul de lumină și schema de conectare la microcontroller> </imgcaption>

Task 1: Senzorul de lumină este conectat la canalul A2. Citiți valoarea acestuia și trimiteți-o pe serială.

Senzorul digital de temperatură și umiditate

SHT21 este un senzor integrat pentru măsurarea temperaturii și a umidității ambientale produs de compania Sensirion. 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.

<imgcaption humid | Senzorul de umiditate SHT21 și conectarea lui la microcontroller> </imgcaption>

Pentru a citi date de la acest senzor s-au folosit fişierele sht21.c si sht21.h oferite ca suport în această arhivă:

  1. În folder-ul Arduino\libraries se creează un nou folder, numit sht21;
  2. Se copiază sht21.c si sht21.h în folder-ul creat anterior;
  3. Se schimbă extensia fişierului .c în .cpp;

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

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

#include "sht21.h"
 
float temp, humid;
 
void setup() {
  DDRE |= 1<<PE7; //sensor on/off control
  PORTE &= ~(1<<PE7); //enable all sensors
 
  // initialize the serial communication:
  Serial.begin(9600);
  twiInit();
 
  delay(100);
}
 
void loop() {
 
   // Read data from sht21 sensor (humid and temp)
  uint16_t value16 = SHTReadValue(0xE3);
  TWCR = 0;
  temp = ((float)value16) / 374.23 - 46.85;
  value16 = SHTReadValue(0xE5);
  humid = ((float) value16) / 524.288 - 6;	
 
  // Send data on the serial port. Useful for debugging non-gateway nodes
  Serial.print("humid, temp: ");
  Serial.print((int)humid);
  Serial.print(", ");
  Serial.println((int)temp);
 
 
  // wait a bit 
  delay(1000);
}

Afișarea datelor de la senzori cu Processing

î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 Processing. Puteți să descărcați programul de aici: http://processing.org/download/ Pur și simplu dezarhivați în directorul Arduino și rulați fișierul .exe

Încărcați următorul program pe placa Sparrow:

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(A2));
 
  digitalWrite(controlPin, HIGH); //disable all sensors
 
 
}

După cum puteți vedea, programul trimite pe serială datele citite de la senzorul de lumină. Pentru a le afișa în mod grafic, încărcați următoarea schiță în Processing:

// Graphing sketch
 
 
 // This program takes ASCII-encoded strings
 // from the serial port at 9600 baud and graphs them. It expects values in the
 // range 0 to 1023, followed by a newline, or newline and carriage return
 
 // Created 20 Apr 2005
 // Updated 18 Jan 2008
 // by Tom Igoe
 // This example code is in the public domain.
 
 import processing.serial.*;
 
 Serial myPort;        // The serial port
 int xPos = 1;         // horizontal position of the graph
 
 void setup () {
 // set the window size:
 size(400, 300);        
 
 // List all the available serial ports
 println(Serial.list());
 // I know that the first port in the serial list on my mac
 // is always my  Arduino, so I open Serial.list()[0].
 // Open whatever port is the one you're using.
 myPort = new Serial(this, Serial.list()[3], 9600);
 // don't generate a serialEvent() unless you get a newline character:
 myPort.bufferUntil('\n');
 // set inital background:
 background(0);
 }
 void draw () {
 // everything happens in the serialEvent()
 }
 
 void serialEvent (Serial myPort) {
 // get the ASCII string:
 String inString = myPort.readStringUntil('\n');
 
 if (inString != null) {
 // trim off any whitespace:
 inString = trim(inString);
 // convert to an int and map to the screen height:
 float inByte = float(inString);
 inByte = map(inByte, 0, 1023, 0, height);
 
 // draw the line:
 stroke(127,34,255);
 line(xPos, height, xPos, height - inByte);
 
 // at the edge of the screen, go back to the beginning:
 if (xPos >= width) {
 xPos = 0;
 background(0);
 }
 else {
 // increment the horizontal position:
 xPos++;
 }
 }
 }
 
 
 
/* Max/MSP v5 patch for this example
 ----------begin_max5_patcher----------
1591.3oc0YszbaaCD9r7uBL5RalQUAO3CvdyS5zVenWZxs5NcfHgjPCIfJIT
RTxj+6AOHkoTDooroUs0AQPR73a+1cwtK3WtZxzEpOwqlB9YveAlL4KWMYh6
Q1GLo99ISKXeJMmU451zTUQAWpmNy+NM+SZ2y+sR1l02JuU9t0hJvFlNcMPy
dOuBv.U5Rgb0LPpRpYBooM3529latArTUVvzZdFPtsXAuDrrTU.f.sBffXxL
vGE50lIHkUVJXq3fRtdaoDvjYfbgjujaFJSCzq4.tLaN.bi1tJefWpqbO0uz
1IjIABoluxrJ1guxh2JfPO2B5zRNyBCLDFcqbwNvuv9fHCb8bvevyyEU2JKT
YhkBSWPAfq2TZ6YhqmuMUo0feUn+rYpY4YtY+cFw3lUJdCMYAapZqzwUHX8S
crjAd+SIOU6UBAwIygy.Q1+HAA1KH6EveWOFQlitUK92ehfal9kFhUxJ3tWc
sgpxadigWExbt1o7Ps5dk3yttivyg20W0VcSmg1G90qtx92rAZbH4ez.ruy1
nhmaDPidE07J+5n2sg6E6oKXxUSmc20o6E3SPRDbrkXnPGUYE.i5nCNB9TxQ
jG.G0kCTZtH88f07Rt0ZMMWUw8VvbKVAaTk6GyoraPdZff7rQTejBN54lgyv
HE0Ft7AvIvvgvIwO23jBdUkYOuSvIFSiNcjFhiSsUBwsUCh1AgfNSBAeNDBZ
DIDqY.f8.YjfjV1HAn9XDTxyNFYatVTkKx3kcK9GraZpI5jv7GOx+Z37Xh82
LSKHIDmDXaESoXRngIZQDKVkpxUkMCyXCQhcCK1z.G457gi3TzMz4RFD515F
G3bIQQwcP3SOF0zlkGhiCBQ1kOHHFFlXaEBQIQnCwv9QF1LxPZ.A4jR5cyQs
vbvHMJsLll01We+rE2LazX6zYmCraRrsPFwKg1ANBZFY.IAihr8Ox.aH0oAL
hB8nQVw0FSJiZeunOykbT6t3r.NP8.iL+bnwNiXuVMNJH9H9YCm89CFXPBER
bz422p8.O4dg6kRxdyjDqRwMIHTbT3QFLskxJ8tbmQK4tm0XGeZWF7wKKtYY
aTAF.XPNFaaQBinQMJ4QLF0aNHF0JtYuHSxoUZfZY6.UU2ejJTb8lQw8Fo5k
Rv6e2PI+fOM71o2ecY1VgTYdCSxxUqLokuYq9jYJi6lxPgD2NIPePLB0mwbG
YA9Rgxdiu1k5xiLlSU6JVnx6wzg3sYHwTesB8Z5D7RiGZpXyvDNJY.DQX3.H
hvmcUN4bP1yCkhpTle2P37jtBsKrLWcMScEmltOPv22ZfAqQAdKr9HzATQwZ
q18PrUGt6Tst2XMCRUfGuhXs6ccn23YloomMqcTiC5iMGPsHsHRWhWFlaenV
XcqwgCQiGGJzptyS2ZMODBz6fGza0bzmXBj7+DA94bvpR01MffAlueO7HwcI
pWCwmzJdvi9ILgflLAFmyXB6O7ML0YbD26lenmcGxjVsZUN+A6pUK7AtTrPg
M+eRYG0qD9j4I7eEbco8Xh6WcO.or9XDC6UCiewbXHkh6xm5LiPEkzpJDRTu
mEB44Fgz4NCtJvX.SM1vo2SlTCZGAe7GZu6ahdRyzFOhYZ+mbVVSYptBw.K1
tboIkatIA7c1cTKD1u.honLYV04VkluHsXe0szv9pQCE9Ro3jaVB1o15pz2X
zYoBvO5KXCAe0LCYJybE8ZODf4fV8t9qW0zYxq.YJfTosj1bv0xc.SaC0+AV
9V9L.KKyV3SyTcRtmzi6rO.O16USvts4B5xe9EymDvebK0eMfW6+NIsNlE2m
eqRyJ0utRq13+RjmqYKN1e.4d61jjdsauXe3.2p6jgi9hsNIv97CoyJ01xzl
c3ZhUCtSHx3UZgjoEJYqNY+hYs5zZQVFW19L3JDYaTlMLqAAt1G2yXlnFg9a
53L1FJVcv.cOX0dh7mCVGCLce7GFcQwDdH5Ta3nyAS0pQbHxegr+tGIZORgM
RnMj5vGl1Fs16drnk7Tf1XOLgv1n0d2iEsCxR.eQsNOZ4FGF7whofgfI3kES
1kCeOX5L2rifbdu0A9ae2X.V33B1Z+.Bj1FrP5iFrCYCG5EUWSG.hhunHJd.
HJ5hhnng3h9HPj4lud02.1bxGw.
-----------end_max5_patcher-----------
 
 */

La prima rulare vi se va afișa o listă cu porturi COM disponibile, aveți grijă să selectați portul pe care este conectată placa Sparrow. Pentru aceasta va trebui probabil să modificați programul de mai sus și să îl re-rulați.

Datele eșantionate de la senzorul de lumină ar trebui să fie vizibile în fereastra deschisă de către schița Processing.

<imgcaption processing | Graficul afișat de la senzor în fereastra Processing></imgcaption>

iothings/workshop.txt · Last modified: 2021/10/12 19:16 (external edit)
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