Vyberte váš jazyk

Vaša IP adresa: 216.73.217.154
Počet návštev: 1651

Analógovo-digitálny prevodník (ADC) v mikrokontroléroch AVR

Väčšina fyzikálnych veličín reálneho sveta (ako teplota, tlak, mechanické namáhanie, intenzita svetla či biopotenciály tela) má spojitý – analógový charakter. Aby bolo možné tieto signály spracovať, analyzovať a vyhodnotiť pomocou digitálneho mikrokontroléra, je potrebné ich premeniť na postupnosť číselných (diskrétnych) hodnôt. Túto kľúčovú úlohu plní analógovo-digitálny prevodník (Analog-to-Digital Converter – ADC).

Mikrokontrolér ATmega328P obsahuje integrovaný 10-bitový AD prevodník pracujúci na princípe postupnej aproximácie (Successive Approximation Register – SAR). Prevodník je prepojený s analógovým multiplexorom (ADMUX), ktorý umožňuje privádzať signál z viacerých vonkajších analógových pinov (kanály ADC0ADC7 v závislosti od typu puzdra MCU), ako aj z interných zdrojov (napr. teplotný senzor čipu či interné napäťové referencie).

Základné princípy a parametre potrebné pre správne použitie AD prevodníka:

  • Rozlíšenie (Resolution): Prevodník je 10-bitový, čo znamená, že spojitý rozsah vstupného analógového napätia rozdeľuje na 210 = 1024 diskrétnych kvantovacích úrovní (hodnoty v rozsahu 0 až 1023). Výsledné 10-bitové číslo je uložené v registrovom páre ADCH:ADCL.
  • Referenčné napätie (VREF): Určuje maximálne merateľné vstupné napätie zodpovedajúce maximálnemu kódu prevodu (1023). Ako referenciu možno zvoliť napájacie napätie analógovej časti AVCC, externé napätie privedené na pin AREF, alebo internú stabilizovanú napäťovú referenciu 1,1 V. Kvantovací krok (napäťové rozlíšenie jedného LSB) je daný vzťahom: LSB = VREF/1024
  • Taktovacia frekvencia ADC: Prevodník vyžaduje vstupný hodinový signál v rozsahu 50 kHz až 200 kHz na dosiahnutie maximálneho 10-bitového rozlíšenia. Tento kmitočet sa odvodzuje zo systémového taktu MCU pomocou nastaviteľnej preddeličky (Prescaler) s delením 2, 4, 8, 16, 32, 64 alebo 128.
  • Režimy prevodu: AD prevodník podporuje režim jednorazového prevodu (Single Conversion), kedy sa každý prevod spúšťa manuálne softvérovým zápisom, a režim automatického spúšťania (Free Running alebo spúšťanie externou udalosťou/časovačom), kedy nový prevod začína automaticky po dokončení predchádzajúceho alebo po definovanej udalosti.

Dokončenie prevodu je hardvérovo signalizované nastavením príznaku v stavovom registri, pričom prevodník dokáže po ukončení digitalizácie vzorky vyvolať vyhradené prerušenie (ADC Conversion Complete Interrupt), čo umožňuje efektívny zber dát bez blokovania výpočtového výkonu hlavného programu.

Dôležité registre

V tejto časti sú opísané niektoré registre súvisiace s interným AD prevodníkom, ktoré sú využité v príkladoch nižšie.

ADMUX - Register slúžiaci na nastavenie referencie AD prevodníka a na výber analógového kanála, ktorý bude pripojený k AD prevodníku.

  • Bity REFS1 a REFS0 slúžia na nastavenie referencie AD prevodníka podľa tabuľky, ktorá je uvedená nižšie. Ak na testovanie používate vývojovú dosku Mega Development Board, tak použite konfiguráciu REFS1=0 a REFS0=1. V schéme pre Mega Development Board je pin AVCC pripojený na pin VCC = 5V. Referenčné napätie je teda AVCC = 5V.

  • Bit ADLAR ovplyvňuje reprezentáciu výsledku AD konverzie v 16-bit registri ADC (uvedený nižšie). Ak ADLAR=1, tak je výsledok zarovnaný vľavo, inak je výsledok zarovnaný vpravo.
  • Bity MUX3MUX0 slúžia na výber analógového kanála ADC0ADC8, ktorý bude pripojený na vstup AD prevodníka. Vývojová doska Mega Development Board má vyvedené na svorkovnicu kanály ADC0 a ADC1.

ADCSRA - Riadiaci a stavový register AD prevodníka.

  • Bit ADEN povoľuje/vypína AD prevodník. Ak ADEN=1, tak je AD prevodník povolený. Ak je AD prevodník vypnutý počas konverzie (ADEN=0), tak sa ukončí prevod.
  • Bit ADSC spúšťa AD prevod. Zápis ADSC=1 spúšťa každý jeden prevod. Po dokončení prevodu sa automaticky vynuluje (ASDSC=0). Zápis ADSC=0 nemá žiadny vplyv.
  • Bit ADIF sa nastaví (ADIF=1) vtedy, keď je dokončený AD prevod a je aktualizovaný dátový register. ADIF je nulovaný automaticky (hardvérovo) v prípade uskutočnenia prerušenia pri dokončení prevodu (ADC Conversion Complete Interrupt), alebo softvérovo zápisom logickej jednotky (ADIF=1).
  • Bit ADIE aktivuje prerušenie pri dokončení prevodu (ADC Conversion Complete Interrupt).
  • Bity ADPS2ADPS0 nastavujú vstupnú frekvenciu AD prevodníka pomocou predeličky (Division Factor) systémovej frekvencie MCU. Nastavenie je uvedené v nasledujúcej tabuľke. Vstupná frekvencia AD prevodníka musí byť v rozmedzí 50 kHz - 200 kHz v prípade 10-bit rozlíšenia. Nastavenie frekvencie AD prevodníka sa preto odvíja od systémovej frekvencie MCU (ATmega328P má interný kryštál 8 MHz).

ADC - Register (16-bit) obsahujúci výsledok prevodu. Register sa skladá z dvoch 8-bit registrov ADCH (High) a ADCL (Low).V závislosti od nastavenia bitu ADLAR v registri ADMUX je výsledok prevodu zarovnaný vpravo alebo vľavo.

Výsledok ADC prevodu (obsah registra ADC) v prípade 10-bit rozlíšenia je vypočítaný podľa vzťahu:


Príklad č. 1

Príklad opisuje použitie interného 10-bitového AD prevodníka na digitalizáciu analógového napäťového signálu, ktorý je privádzaný k vstupu AD prevodníka ADC0 (PORTC0). Referencia AD prevodníka je 5V. Po privedení napätia 0V na vstup ADC0 sa na displeji rozsvieti číslo 0 a po privedení 5V sa na displeji rozsvieti číslo 5. Napätiu 0V zodpovedá najmenšia digitálna hodnota 0 a napätiu 5V zodpovedá najvyššia digitálna hodnota 1023. Keďže môže byť vstup AD prevodníka mierne zarušený, tak na displeji sa vypíše číslo 0, keď je digitálna hodnota menšia ako 100. Hodnota 5 sa rozsvieti v prípade, ak je digitálna hodnota väčšia ako 950. Ak sa digitálna hodnota bude nachádzať mimo týchto intervalov, tak displej zostane zhasnutý.

#include <avr/io.h>

void ADC_Init()//inicializacia AD prevodnika
{
ADMUX|=(1<<REFS0);//referencia na AVCC pine
//v scheme su piny VCC a AVCC prepojene -> referencia AD prevodnika = 5V

//digitalizujeme kanal ADC0 - prednastavena hodnota v registri ADMUX
ADCSRA|=(1<<ADPS2)|(1<<ADPS1);//predelicka 64 -> 125kHz
ADCSRA|=(1<<ADEN);//povolenie AD prevodnika
}

uint16_t StartPrevodu()//funkcia s navratovou hodnotou typu uint16
{
ADCSRA|=(1<<ADSC);//start prevodu
while ((ADCSRA&(1<<ADIF))==0) ; //caka na dokoncenie prevodu
ADCSRA|=(1<<ADIF);//nulovanie dokoncenia prevodu zapisom log.1
return ADC;//vysledok prevodu je v registri ADC
}

void ZhasniDisplej()
{
PORTB=255;//zhasne displej (vsetky segmenty)
}

void RozsvietNulu()
{
PORTB=(1<<PORTB6);//zhasne segment G
}

void RozsvietPatku()
{
PORTB=(1<<PORTB1)|(1<<PORTB4);//zhasne segmenty B a E
}

int main(void)
{
DDRB=255;//PORTB ako vystupny (pripojeny displej)
ZhasniDisplej();
ADC_Init();//inicializacia AD prevodnika

while (1)
{
uint16_t hodnota=StartPrevodu();
if (hodnota<100)
RozsvietNulu();
else
{
if (hodnota>950)
RozsvietPatku();
else
ZhasniDisplej();
}
}
}


Príklad č. 2

V nasledujúcom príklade je digitalizovaný analógový signál privedený na vstup ADC0 so vzorkovacou frekvenciou fvz = 100 Hz (Tvz = 10 ms). Digitálne vzorky sú odosielané do PC cez rozhranie USART (Baude Rate = 19 200). Tento príklad je komplexný, pretože využíva časovač, prerušenie a rozhranie USART, ktoré boli predstavené v predchádzajúcich lekciách.

#include <avr/io.h>
#include <avr/interrupt.h>

#define RTS PIND2

void ADC_Init()//inicializacia AD prevodnika
{
ADMUX|=(1<<REFS0);//referencia na AVCC pine
//v scheme su piny VCC a AVCC prepojene -> referencia AD prevodnika = 5V

//digitalizujeme kanal ADC0 - prednastavena hodnota v registri ADMUX
ADCSRA|=(1<<ADPS2)|(1<<ADPS1);//predelicka 64 -> 125kHz
ADCSRA|=(1<<ADEN);//povolenie AD prevodnika
}

void Timer1_Init()//inicializacia 16-bit casovaca (TIMER1)
{
TCCR1B|=(1<<CS11);//zapnutie casovaca predelicka 8 -> fCPU=8MHz-> f_casovac=1MHz -> T_casovac=1us
OCR1A=10000;//10000x1us=10ms->fvz=100 Hz
TCCR1B|=(1<<WGM12); //automaticke nulovanie TCNT1 pri dosiahnuti hodnoty v OCR1A
TIMSK1=(1<<OCIE1A);//zapnutie prerusenia casovaca (TIMER1_COMPA_vect)
}

void USART_Init()
{
// Nastavenie USART-8 datovych bitov,jeden stop bit,ziadna parita
// - uvedene parametre su vychodiskove hodnoty registrov,
// preto nie je potrebne nastavovat
UBRR0=25; //nastavena rychlost 19200 Baud (z datasheetu) pri f_MCU=8MHz
UCSR0B|=(1<<TXEN0); //zapnutie vysielaca
}

void USART_send(unsigned char bajt)
{
while ( !( UCSR0A & (1<<UDRE0)) ) ; //pocka na vyprazdnenie buffera
UDR0 = bajt; //odoslanie bajtu cez USART
}

uint16_t StartPrevodu()//funkcia s navratovou hodnotou typu uint16
{
ADCSRA|=(1<<ADSC);//start prevodu
while ((ADCSRA&(1<<ADIF))==0) ; //caka na dokoncenie prevodu
ADCSRA|=(1<<ADIF);//nulovanie dokoncenia prevodu zapisom log.1
return ADC;//vysledok prevodu je v registri ADC
}

ISR(TIMER1_COMPA_vect) //obsluha prerusenia casovaca TIMER1
{
//prerusenie sa spusta kazdych 10ms
if (! (PIND&(1<<RTS)))//ak je linka RTS na log.0
{
uint16_t digi_hodnota=StartPrevodu();
//digi_hodnota = 16 bit = 2 bajty
USART_send(digi_hodnota);//odosle dolny bajt
USART_send(digi_hodnota>>8);//odosle horny bajt
}

}

int main(void)
{
DDRD&=~(1<<RTS);//pin RTS (PIND2) ako vstupny
ADC_Init();//inicializacia AD prevodnika
Timer1_Init();//inicializacia casovaca TIMER1 (16 bit)
USART_Init();//inicializacia USART

sei();//globalne povolenie preruseni

while (1)
{

}
}