Acest laborator are ca scop familiarizarea voastră cu lucrul cu convertorul analog-digital prezent în microcontroller-ul Atmega328p.
Pentru a putea măsura semnalele analogice într-un sistem de calcul digital, acestea trebuie convertite în valori numerice discrete. Un convertor analog – digital (en. Analog to Digital Converter - ADC) este un circuit electronic care convertește o tensiune analogică de la intrare într-o valoare digitală.
O caracteristică importantă a unui ADC o constituie rezoluția acestuia. Rezoluția indică numărul de biți pe care convertorul poate să reprezinte rezultatul binar. le furnizeze la ieșirea sa în intervalul de măsură. Cuanta de măsurare - cea mai mică valoare care poate fi distinsă de ADC reprezintă raportul între domeniul tensiunii de intrare (diferența între tensiunea maximă și tensiunea minimă ce pot fi aplicate la intrarea în convertor) și numărul maxim de valori binare reprezentabile (2^N).
De exemplu, dacă rezoluția unui convertor este de 10 biți atunci el poate furniza 2^10 = 1024 valori diferite la ieșire. Dacă gama de măsurare este de la 0 la 5V, cuanta de măsurare va fi: (5V-0V)/1024 = 0.0048V adică 4.8mV.
O altă caracteristică importantă a unui convertor analog-digital o constituie rata de eșantionare (e.n. sampling rate). Aceasta depinde de timpul dintre două conversii succesive și afectează modul în care forma de undă originală va fi redată după procesarea digitală. Mai jos observăm cum arată modul în care semnalul eșantionat va fi reconstituit în urma trecerii printr-un convertor digital – analog (DAC). După cum se poate observa, semnalul reprodus nu este identic cu cel original. Dacă rata de eșantionare ar crește semnalul reprodus prin unirea punctelor/eșantioanelor digitale aproximează din ce în ce mai bine originalul.
Care este însa rata minimă de eșantionare pentru a reproduce fără pierderi un semnal de o frecvența data? Teorema lui Nyquist spune că o rată de eșantionare de minimum două ori mai mare decât frecvența semnalului măsurat este necesară pentru acest lucru, teorema aplicându-se și pentru un semnal compus dintr-un intreg spectru de frecvențe, cum ar fi vocea umană sau o melodie. Limitele maxime ale auzului uman sunt 20Hz – 20kHz dar frecvențele obișnuite pentru voce sunt în gama 20-4000Hz, de aceea centralele telefonice folosesc o rată de eșantionare a semnalului de 8000Hz. Rezultatul este o reproducere inteligibilă a vocii umane, suficientă pentru transmiterea de informații într-o convorbire obișnuită. Pentru reproducerea fidelă a spectrului audibil se recurge la rate mai mari de eșantionare. De exemplu, înregistrarea pe un CD are o rată de eșantionare de 44100Hz ceea ce este mai mult decât suficient pentru reproducerea fidelă a tuturor frecvențelor audibile.
In funcție de modul în care se execută conversia, convertoarele analog-digitale pot fi de mai multe tipuri:
Convertorul analog-digital inclus în microcontroller-ul Atmega328p este un ADC cu aproximări succesive. Are o rezoluție de pana la 10 biți și poate măsura orice tensiune din gama 0-5V de pe opt intrări analogice multiplexate (6 disponibile pe arduino).
Acest convertor poate fi controlat prin doua registre de stare și control (ADCSRA si ADCSRB) și un registru cu biți de selecție pentru multiplexoare (ADMUX). În primele, putem stabili când să se efectueze conversia, dacă să se genereze întrerupere la finalul unei conversii etc. Folosind registrul pentru multiplexoare se alege ce canal va genera input pentru convertor si tensiunea de referință. De asemenea, în afară de aceste două registre mai avem registrul ADC în care este scris rezultatul conversiei (ADC).
ADC = V_in * 1024 / V_ref
sau
V_in = ADC * V_ref / 1024
unde V_in este tensiunea măsurată iar V_ref este tensiunea aleasă ca referință.
In functie de intervalul in care varieaza semnalul pe care il citim putem selecta alta tensiune de referinta. Acest lucru este util pentru a mari rezolutia citirii. ADC-ul de pe Atmega 328p ne ofera ca tensiune de referinta tensiunea de alimentare (AVCC), o tensiune interna de 1.1V sau un pin pe care putem conecta o referinta de tensiune externa (AREF)
ADC-ul nostru are nevoie de un semnal de ceas pentru a stii cat timp dureaza o conversie. Pentru ca semnalul de ceas al microcontrollerului este prea rapid avem nevoie de un prescaler. Cea mai mica valoare este 2 si cea mai mare este 128.
F_ADC = F_CPU / PRESCALER
Alegerea prescaler-ului depinde de frecventa de esentionare si de acuratetea dorita. Cu cat prescaler-ul este mai mare frecventa ADC va fi mai mica si acuratetea va fi mai mare. Mai multe informatii se pot gasi in capitolul 23.4 din datasheet.
Convertorul poate functiona in mai multe moduri. Cel mai comun mod si cel care este desponibil si in biblioteca arduino este Single Conversion Mode. In acest mod se va efectua o singura conversie si se incepe setand ADSC pe 1. Registrul va fi setat pe 0 automat la finalul conversiei.
Un alt mod de functionare este Free Running Mode in care convertorul va functiona in continuu, la finalul unei conversii se va incepe automat urmatoarea conversie. De fiecare data rezultatul precedent va fi suprascris. Pentru a incepe o conversie se va seta registrul ADSC pe 1 si acesta nu va fi pus pe 0 automat.
Setup:
ADMUX = 0; /* ADC1 - channel 1 */ ADMUX |= (1 << MUX0); /* AVCC with external capacitor at AREF pin */ ADMUX |= (1 << REFS0); ADCSRA = 0; /* set prescaler at 128 */ ADCSRA |= (7 << ADPS0); /* enable ADC */ ADCSRA |= (1 << ADEN);
Read:
/* start conversion */ ADCSRA |= (1 << ADSC); /* wait until conversion is complete */ while (!(ADCSRA & (1 << ADIF))); uint16_t result = ADC;
Biblioteca arduino ne pune la dispozitie o functie simpla pentru a folosi ADC-ul si anume analogRead().
void loop() { val = analogRead(A0); // read the input pin Serial.println(val); // debug value delay(100); }
Aceasta functie primeste ca parametru un pin si va bloca pana citirea valorii de pe acel pin se termina. Pentru aplicatii simple acest lucru este suficient, dar pentru aplicatii mai complexe in care ne dorim sa continuam procesarea in timp ce facem conversia va trebui sa folosim cod specific pentru microcontrollerul nostru.
Tensiunea de referinta folosita se poate seta cu functia analogReference()
Task 0 Folositi cod Arduino pentru a citi valoarea unui potentiometru si a unui senzor de temperatura si apoi trimiteti valorile pe seriala.
Task 1 Folosind cod specific AVR, cititi valoarea potentiometrului doar atunci cand se apasa un buton.
Task 2 Folosind cod specific AVR, cititi valoarea potentiometrului o data la 10ms. Pentru acest exercitiu trebuie sa folositi ADC-ul sa porneasca o conversie automat in functie de un timer.