Stație meteo

Proiectul are ca scop deprinderea programării microcontrolerelor ATmega644P, folosind cadrul Arduino, în vederea comunicării între acestea a diferitelor mărimi. Transmiterea între cele două microcontrolere se va realiza prin radio folosind transceiverul nRF24L01 dezvoltat de Nordic Semiconductor. Mărimile ce se dorește a fi transmise sunt temperatura și umiditatea.
Placa de dezvoltare folosită în vederea realizării programului și a testelor este EVB 4.3 - v4.

Microcontrolerul

Partea centrală a dispozitivului va fi realizat cu microcontrolerul ATmega644P atât pentru placa TX cât și pentru placa RX.
Caracteristicile principale ale microcontrolerului:

  • Arhitectură RISC avansată:
    • 131 de instrucțiuni;
    • 32x8 registre de lucru cu scop general;
    • operează complet static;
    • până la 20 MIPS la 20 MHz;
    • multiplicator de 2 cicluri;
  • Memorie:
    • 64kBytes memorie Flash programabilă;
    • 2kBytes EEPROM;
    • 4kBytes SRAM;
    • cicluri de scriere/ștergere: 10.000 pentru Flash și 100.000 pentru EEPROM;
    • păstrarea datelor: 20 de ani la 85°C sau 100 de ani la 25°C;
    • blocare programare în vederea securității software;
  • Suport librărie QTouch®
    • butoane, potențiometre liniare și rotative capacitive;
    • metode pentru achiziția prin atingere: QTouch și QMatrix;
    • până la 64 canale de sens;
  • Suportă interfață JTAG
  • Caracteristicile pinilor
    • 2 numărătoare/timer-e pe 8 biți cu prescalere separate și mod de comparație;
    • 1 numărător/timer pe 16 biți cu prescalare separat, mode comparație și mod de achiziție;
    • contor de timp real cu oscilator separat;
    • 6 canale PWM;
    • 8 canale analogice pe 10 biți:
      • suportă mod diferențial cu amplificare selectabilă: 1x, 10x sau 200x;
    • 1 comunicare serială pe 2 fire I2C;
    • 2 comunicații seriale programabile;
    • 1 comunicare serială SPI master/slave;
    • timer Watchdog programabil cu oscilator intern separat;
    • comparator analog intern;
    • Wake-up la schimbarea stării pinului;
  • Caracteristici speciale ale microcontrolerului
    • oscilator RC calibrat intern;
    • resetare la pornire și detectare programabilă în caz de dezactivare;
    • surse externe și interne de întrerupere;
    • 6 moduri de așteptare;
  • Intrări/ieșiri
    • 32 de intrări/ieșiri programabile;
    • capsulă pini 40 PDIP; 44 TQFP; 44 VQFN/QFN;
  • Tensiunea de operare
    • 2,7 - 5,5V pentru ATmega644P;
    • 1,8 - 5,5V pentru ATmega644PV;
  • Viteze de operare
    • ATmega644PV:
      • 0 - 4MHz @ 1,8V - 5,5V;
      • 0 - 10MHz @ 2,7V - 5,5V;
    • ATmega644P:
      • 0 - 10MHz @ 2,7V - 5,5V;
      • 0 - 20MHz @ 4,5V - 5,5V;
  • Consum la 1MHz, 1,8V, 25°C
    • mod active: 0,4mA;
    • mod Power-down: 0,1μA;
    • mod Power-save: 0,6μA (inclusiv 32kHz RTC)

Transceiverul - modulul radio

În vederea comunicării radio între cele două plăci de dezvoltare EVB se va folosi transceiverul nRF24L01 dezvoltat de Nordic Semiconductor.
Principalele caracterisitici, de care vom ține seama în proiectarea sistemului, conform datelor din catalog:

  • Radio
    • folosește banda radio liberă ISM (industrial, scientific and medical) de 2,4GHz;
    • 126 de canale RF;
    • pinii comuni pentru emitere și recepție;
    • modulare GFSK;
    • 1 și 2 Mbps rata de date prin aer;
    • 1MHz ecart între canale la o rată de 1Mbps;
    • 2MHz ecart între canale la o rată de 2Mbps;
  • Emițător
    • putere de ieșire programabilă: 0dBm, -6dBm, -12dBm sau -18dBm;
    • consum 11,3mA la putere de ieșire de 0dBm;
  • Receptor
    • filtre integrate pentru canalele de comunicație;
    • consum 12,3mA la 2Mbps;
    • sensibilitate de -82dBm la 2Mbps;
    • sensibilitate de -85dBm la 1Mbps;
    • aplicare programabilă a amplificatorului de zgomot redus - LNA;
  • Sinteza de radio frecvență
    • conține integrat în totalitate componentele necesare pentru sinteza de frecvență;
    • acceptă cristal oscilator de 16MHz având cost redus;
  • Alimentare
    • conține integrat regulator de tensiune;
    • tensiune de alimentare 1,9V - 3,6V;
    • mod de așteptare cu pornire rapidă pentru managementul puterii consumate;
    • consum 22μA în modul "Standby";
    • consum 900nA în modul "Power down";
    • pornire în 1,5ms din modul "Power down";
    • pornire în 130μs din modul "Standby";
  • Manipularea automată a pachetelor
  • 6 fire de execuție MultiCeiver®
  • 1 până la 32 de biți lungimea datelor utile transmise/recepționate
  • Interfața de comunicare
    • comunicare serială SPI prin 4 pini;
    • maxim 8Mbs;
    • suportă 5V la intrările prin comunicația SPI;
    • suportă 3 separate 32biți TX și RX de tip FIFO;

Senzorul de temperatură și umiditate

În vederea achiziției temperaturii și umidități se va folosi senzorul DHT22, principalele caracterisitici ale acestuia sunt:

  • Tensiunea de lucru: între 3,5V și 5,5V;
  • Curent nominal: 0,3mA și 60μA în "Standby";
  • Tip date de ieșire: serial;
  • Gama temperaturii măsurate: între -40°C și 80°C;
  • Gama umidității măsurate: de la 0% la 100%;
  • Rezoluția: 16 biți pentru temperatură și umiditate;
  • Eroarea de măsurare: ±0.5°C pentru temperatură și ±1% pentru umiditate.

Modulul emițător

Schema electronică a modului emițător este următoarea:

Pentru realizarea acestui modul am prevăzut 4 blocuri:

  • Blocul de alimentare, format din:
    • Dioda D1 cu rolul de a proteja circuitul la alimentarea inversă;
    • Dioda D2 pentru a modifica tensiunea de referința a regulatorului de tensiune MCP1700-3002E deoarece acesta scoate o tensiune de 3V (la măsurătoare voltmetru indica 2,7V), am obținut astfel 3,3V (măsurat);
    • Dioda D3 de tip LED având rol de a ne indica alimentarea circuitului, iar R1 are rolul de a limita curentul prin aceasta;
    • Condensatoarele C1 - C4 au rol de filtrare și de buffer a tensiunii. În timpul testelor condensatorul C4 de 1μF a făcut diferența, în sensul că, fără acest condensator transmisia avea de suferit prin pierderea unui număr însemnat de pachete;
    • Regulatorul de tensiune 5V - L7805 în vederea alimentării blocului de comandă, realizat cu ATmega644P, respectiv a blocului de măsură, realizat cu senzorului de temperatură și umiditate DHT22;
    • Regulatorul de tensiune 3V - MCP1700-3002E necesar obținerii tensiunii de alimentare a blocului radio, realizat cu nRF24L01.
  • Blocul de comandă, format din:
    • Microcontrolerul ATmega644P-20PU, alimentat la tensiunea de 5V, care inițial a fost programat cu bootloader-ul de la Sanguino;
    • Oscilatorul realizat cu C5, C6 și cristalul Y1 ce impune frecvența de (16MHz) lucru a microcontrolerului ATmega644P;
  • Blocul de măsură, realizat cu:
    • Senzorul de temperatură DHT22;
  • Blocul radio, realizat cu:
    • Transceiverul nRF24L01, alimentat la o tensiune de 3,3V.

      Atenție: Tensiunea de alimentare a circuitului nRF24L01 este de maxim 3,6V. Numai pinii de comandă suportă tensiuni de intrare de 5V.

Codul programului modulului TX

Codul a fost editat folosind mediul de dezvoltare Visual Studio Code la care s-a activat extesia PlatformIO. Astfel s-a putut crea un proiect pentru plăcile EVB 4.3 v4 cu Sanguino folosind cadrul celor de Arduino.
Librăriile necesare comunicării cu:

Codul folosit pentru programarea microcontrolerului din cadrul modului de transmisie este următorul:

/*
TX - Stație Meteo
//
DHT22    Sanguino   Atmega644P
VCC   -> +5V
OUT   -> 2        -> PB2
GND   -> GND
//
Radio    Sanguino              Atmega644P
CE    -> 3                      -> PB3
CSN   -> 4 (Hardware SPI SS)    -> PB4
MOSI  -> 5 (Hardware SPI MOSI)  -> PB5
MISO  -> 6 (Hardware SPI MISO)  -> PB6
SCK   -> 7 (Hardware SPI SCK)   -> PB7
IRQ   -> No connection
VCC   -> No more than 3.6 volts
GND   -> GND
*/
//
#include <Arduino.h>
//librăriile necesare pt. transcieverul nRF24L01
#include <SPI.h>
#include <NRFLite.h>
//librăriile necesare pt. senzorul DHT22
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
//
// definesc constantele
// pentru nRF24L01
const static uint8_t ID_RADIO_TRANSMITERE = 1; // Identificatorul (ID-ul) transmițătorului
const static uint8_t ID_RADIO_RECEPTIE    = 0; // Identificatorul (ID-ul) radioului recepție
const static uint8_t PIN_RADIO_CE         = 3; // Pinul unde este conectat pinul CE  de la nRF24L01 
const static uint8_t PIN_RADIO_CSN        = 4; // Pinul unde este conectat pinul CSN de la nRF24L01
// pentru DHT22
#define DHTPIN 1 //Pinul unde este conectată ieșire digitală de la senzorul DHT22
#define DHTTYPE DHT22 // definim modelul DHT22 (AM2302)
//
//
struct RadioPacket // Un packet la transmitere poate avea până la 32 bytes
{
  //temperatura, umiditate;
  float date[2];
};
//
NRFLite _radio; //definesc obiectul _radio
RadioPacket _radioData; // definesc structura _radioData
DHT_Unified dht(DHTPIN, DHTTYPE); // definesc obiectul dht
//
void setup() {
  // codul din acestă funcție este rulat numai odată după alimentarea microcontrolerului
  Serial.begin(115200); //inițializez comunicația serială folosită numai pentru debug
  // inițializez nRF24L01 cu parametrii definiți anterior 
  if (!_radio.init(ID_RADIO_TRANSMITERE, PIN_RADIO_CE, PIN_RADIO_CSN))
  {
    Serial.println("Nu pot comunica cu nRF24L01!");
    Serial.println("Este conectat si functional? ");
    while (1); //Dacă nu se inițializează nRF24L01 așteptăm aici la infinit
  }
  // inițializez senzorul DHT22
  dht.begin();
}
//
void loop() {
  // codul din funcția loop se rulează la infinit:
  sensors_event_t event;
  dht.temperature().getEvent(&event);
  _radioData.date[0] = event.temperature;
  dht.humidity().getEvent(&event);
  _radioData.date[1] = event.relative_humidity;
  if (_radio.send(ID_RADIO_RECEPTIE, &_radioData, sizeof(_radioData)))
  {
    Serial.println("Datele au fost transmise cu succes...:-)");
  }
  else
  {
    Serial.println("Datele nu au ajuns la destinatie!...:-(");
  }
  delay(1000);
}

Modulul receptor

Schema electrică a modulului receptor este următoarea:

Pentru realizarea acestui modul am prevăzut 4 blocuri:

  • Blocul de alimentare, format din:
    • Dioda D1 cu rolul de a proteja circuitul la alimentarea inversă;
    • Dioda D2 pentru a modifica tensiunea de referința a regulatorului de tensiune MCP1700-3002E deoarece acesta scoate o tensiune de 3V (la măsurătoare voltmetru indica 2,7V), am obținut astfel 3,3V (măsurat);
    • Dioda D3 de tip LED având rol de a ne indica alimentarea circuitului, iar R1 are rolul de alimita curentul prin aceasta;
    • Condensatoarele C1 - C4 au rol de filtrare și de buffer a tensiunii. În timpul testelor condesatorul C4 de 1μF a făcut diferența, în sensul că, fără acest condensator transmisia avea de suferit prin pierderea unui număr însemnat de pachete;
    • Regulatorul de tensiune 5V - L7805 în vederea alimentării blocului de comandă, realizat cu ATmega644P, respectiv a blocului de afișare, realizat cu LCD 16x2;
    • Regulatorul de tensiune 3V - MCP1700-3002E necesar obținerii tensiunii de alimentare a blocului radio, realizat cu nRF24L01.
  • Blocul de comandă, format din:
    • Microcontrolerul ATmega644P-20PU, alimentat la tensiunea de 5V, care inițial a fost programat cu bootloaderul de la Sanguino;
    • Oscilatorul realizat cu C5, C6 și cristalul Y1 ce impune frecvența de (16MHz) lucru a microcontrolerului ATmega644P;
  • Blocul de afișare, realizat cu:
    • LCD 16x2 - HY1602 compatibil Hitachi HD44780, unde s-a prevăzut posibilitatea ca din jumper să activăm/inactivăm iluminarea afișorului iar din semireglabilul RV1 să reglăm contrastul;
  • Blocul radio, realizat cu:
    • Transceiverul nRF24L01, alimentat la o tensiune de 3,3V.

      Atenție: Tensiunea de alimentare a circuitului nRF24L01 este de maxim 3,6V. Numai pinii de comandă suportă tensiuni de intrare de 5V.

Codul programului modulului RX

Codul a fost editat folosind mediul de dezvoltare Visual Studio Code la care s-a activat extesia PlatformIO. Astfel s-a putu crea un proiect pentru plăcile cu Sanguino folosind cadrul celor de Arduino.
Librariile necesare comunicării cu:

Codul folosit pentru programarea microcontrolerului din cadrul modului de transmisie este următorul:

/*
RX - Stație Meteo
//
Radio    Sanguino                  Atmega644P
CE    -> 3                      -> PB3
CSN   -> 4 (Hardware SPI SS)    -> PB4
MOSI  -> 5 (Hardware SPI MOSI)  -> PB5
MISO  -> 6 (Hardware SPI MISO)  -> PB6
SCK   -> 7 (Hardware SPI SCK)   -> PB7
IRQ   -> No connection
VCC   -> No more than 3.6 volts
GND   -> GND
//
LCD      Sanguino   Atmega644P
RS    -> 23       ->  PC7
E     -> 22       ->  PC6
D4    -> 21       ->  PC5
D5    -> 20       ->  PC4
D6    -> 19       ->  PC3
D7    -> 18       ->  PC2
VCC   -> 5V
R/W   -> GND
VSS   -> GND
*/
//
#include <Arduino.h>
//librăriile necesare pt. transcieverul nRF24L01
#include <SPI.h>
#include <NRFLite.h>
//librăria necesră pentru LCD
#include <LiquidCrystal.h>
//
// definesc constantele
// pentru nRF24L01
const static uint8_t ID_RADIO_RECEPTIE    = 0; // Identificatorul (ID-ul) transmițătorului
const static uint8_t PIN_RADIO_CE         = 3; // Pinul unde este conectat pinul CE  de la nRF24L01 
const static uint8_t PIN_RADIO_CSN        = 4; // Pinul unde este conectat pinul CSN de la nRF24L01
// pentru LCD
const int rs = 23, en = 22, d4 = 21, d5 = 20, d6 = 19, d7 = 18; // pinii unde este conectat LCD
LiquidCrystal lcd(rs, en, d4, d5, d6, d7); // configurez LCD-ul
//
struct RadioPacket // Un packet la transmitere poate avea până la 32 bytes
{
  //temperatura, umiditate;
  float date[2];
};
//
NRFLite _radio; //definesc clasa _radio
RadioPacket _radioData; // definesc structura _radioData
//
void setup()
  // codul din acestă funcție este rulat numai odată după alimentarea microcontrolerului
{
  Serial.begin(115200); //inițializez comunicația serială folosită numai pentru debug

  lcd.begin(16,2);//inițializez LCD-ul și setez numărul de coloane și numărul de rânduri
  lcd.print("Statie meteo !!!");//Afișez mesajul de întânpinare
//
  // inițializez nRF24L01 cu parametrii definiți anterior
  if (!_radio.init(ID_RADIO_RECEPTIE, PIN_RADIO_CE, PIN_RADIO_CSN))
  {
    Serial.println("Nu pot comunica cu nRF24L01!");
    Serial.println("Este conectat si functional? ");
    while (1); //Dacă nu se inițializează nRF24L01 așteptăm aici la infinit
  }
//    
    /*
    În mod implicit, 'init' configurează nRF24L01 să folosească o rată de transfer de 2MBPS în canalul 100 (0-125 canale valabile).
    Atât nRF24L01 folosit în mod RX cât și cel în mod TX trebuie să aibă setat aceeași rată de transfer (bitrate) și același canal de comunicații,
    pentru a comunica unul cu celălalt.
    Pentru configurarea ratei de transfer și a canalului prezint mai jos câteva exemple.
    _radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE250KBPS, 0)
    _radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE1MBPS, 75)
    _radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE2MBPS, 100) // ÎN MOD IMPLICIT
    */
}
//
void loop()
    // codul din funcția loop va rula în buclă în mod continuu
{
    while (_radio.hasData())
    {
        _radio.readData(&_radioData); // '&' trebuie scris înaintea numelei variabilei

        lcd.clear();//șterg ecranul
        lcd.setCursor(0,0);//poziționez cursorul pe rândul 1 coloana 1 (relativ pt. citirea umană)
        lcd.print("Temp. ");//Afișez Temp.
        lcd.print(_radioData.date[0]);//Afișez temperatura recepționată
        lcd.print(" ");//Introduc un spațiu
        lcd.print((char)223);//Afișez caracterul pentru "grade"
        lcd.print("C");//Afișez C - unitatea de măsură a temperaturii
        lcd.setCursor(0,1);//Poziționez cursorul pe rândul 2 coloana 1 (relativ pt. citirea umană) 
        lcd.print("Umid. ");//Afișez Umid.
        lcd.print(_radioData.date[1]);//Afișez umiditatea relativă recepționată
        lcd.print(" %");//Afișez unitatea de măsură
//      
        //Urmatoarele date sunt trimise pe serială pentru debug
        String msg = "Temperatura ";
        msg += _radioData.date[0];
        msg += " C, Umiditatea ";
        msg += _radioData.date[1];
        msg += " '%', ";
        Serial.println(msg);
    }
}

Testarea codurilor și a schemelor

Realizarea practică a legăturilor, conform schemelor de mai sus, la plăcile de dezvolate EVB 4.3 v4 se realizează cu fire Dupont mamă-mamă.
În imaginea de mai jos se prezintă o astfel de realizare cât și funcționarea acestora cu ajutorului codului sursă de mai sus:

În următoarea imagine prezint o captură a mesajelor transmise prin comunicația serială a fiecărei plăci de dezvoltare: