wtorek, 29 marca 2011

Komparator analogowy

Autor: drzasiek
Redakcja: dondu

Drzaśkowy pamiętnik: Spis treści


Mikrokontroler jest z gruntu układem cyfrowym, ale budując urządzenie często zachodzi potrzeba pomiaru wielkości zewnętrznych, czyli analogowych.

Opisałem już obsługę i uruchomienie przetwornika ADC, który jest bez wątpienia jednym z najbardziej atrakcyjnych urządzeń peryferyjnych wbudowanych w mikrokontroler Atmega8.

Nie zawsze jednak zachodzi potrzeba dokładnego zmierzenia napięcia. Czasami wystarczy jedynie porównanie dwóch napięć. Do tego celu służy komparator analogowy, który również jest na wbudowany w mikrokontroler Atmega8.



Już ze schematy blokowego w dokumentacji mikrokontrolera można z grubsza poznać, jakie możliwości daje układ komparatora analogowego w danym mikroprocesorze.

Jak widać komparator posiada 2 wejścia analogowe:
  • AIN0 (wejście dodatnie) 
  • AIN1(wejście ujemne).

Zgodnie ze schematem wejście dodatnie (AIN0) komparatora może być wejściem napięcia analogowego z pinu AIN0 mikrokontrolera lub może być wewnętrznie podłączone do wbudowanego napięcia referencyjnego.

Napięcie to zależy od napięcia zasilania i od temperatury:


W temperaturze pokojowej, przy zasilaniu mikrokontrolera napięciem 5V jak widać napięcie to wynosi około 1,2V.

Wejście ujemne (AIN1) komparatora może być również wejściem napięcia analogowego z pinu AIN1 lub może być podłączone do tego samego multipleksera, który używany jest przy ADC, pod warunkiem, że zostanie ustawiony („1”) Bit 3 – ACME: Analog Comparator Multiplexer Enable w rejestrze SFIOR oraz jeśli ADC jest wyłączony, czyli jest skasowany („0”) Bit 7 – ADEN: ADC Enable rejestru ADCSRA.

Jak widać na schemacie wynik porównania dwóch napięć jest równy:
  • 1 - gdy napięcie na wejściu dodatnim jest większe od napięcia na wejściu ujemnym,
  • 0 - gdy jest przeciwnie lub napięcia są równe.

Wynik odczytać można z bitu ACO w rejestrze ACSR – Analog Comparator Control and Status Register lub może zostać wygenerowane przerwanie przy jakiejkolwiek zmianie stanu na wyjściu komparatora lub przy jednej, określonej zmianie.

Tylko teraz gdzie co podłączyć i jak skonfigurować?

Najpierw zlokalizowałem możliwe wejścia na schemacie obudowy DIP mikrokontrolera Atmega8.

Rys. Atmega8, obudowa DIP.

Ponieważ komparator to urządzenie analogowe, bardzo istotne jest dbanie o eliminowanie wszelkich możliwych zakłóceń. Sugeruję więc byś zapoznał się z działem: Zasilanie i zakłócenia



Eksperyment 1 - podstawowe działanie

Na początku postanowiłem spróbować prostego eksperymentu. Podłączam dwa napięcia analogowe do wejść AIN0 oraz AIN1, i  w zależności od tego, czy napięcie na wejściu AIN0 jest większe od napięcia na wejściu AIN1, to zapala się dioda LED, a jeśli jest mniejsze to dioda gaśnie.

We wszystkich eksperymentach Atmega pracuje na wewnętrznym oscylatorze RC 1MHz.

Schemat układu:


Pobierz schemat: eagle1.rar

I napisałem prosty program:
#include <avr/io.h>

void main(void)
{
   DDRD=0x01;                //wyjście LED

   for(;;)                   //pętla główna
   {
      if( ACSR & (1<<ACO) )  //jeśli AIN0>AIN1
       PORTD |= 0x01;        //zapal diodę LED
      else                   //w przeciwnym wypadku
       PORTD &= ~0x01;       //zgaś diodę LED
   }
}
Pobierz program: ac1.rar

Jako, że komparator jest domyślnie włączony, nie musiałem go konfigurować dla takiej aplikacji.



Eksperyment 2 - multiplekser z ADC

Następnie spróbowałem wykorzystać inne wejście jako wejście ujemne komparatora, dzięki zastosowaniu multipleksera z ADC.


Pobierz schemat: eagle2.rar


I program:
#include <avr/io.h>

void main(void)
{
   DDRD=0x01;                //wyjście LED

   //Konfiguracja multipleksera
   SFIOR |= (1<<ACME);       //włącza multiplekser
   ADMUX |= (1<<MUX1);       //ADC2 jako wejście ujemne

   for(;;)                   //pętla główna
   {
      if( ACSR & (1<<ACO))   //jeśli AIN0>ADC2
       PORTD |= 0x01;        //zapal diodę LED
      else                   //w przeciwnym wypadku
       PORTD &= ~0x01;       //zgaś diodę LED
   }
}
Pobierz program: ac2.rar



Eksperyment 3 - Bandgap voltage

Kolejną rzeczą jaką wypróbowałem było wykorzystanie wbudowanego w mikrokontroler napięcia referencyjnego (bandgap voltage) jako wejście dodatnie mikrokontrolera.


Pobierz schemat: eagle3.rar

Program:
#include <avr/io.h>

void main(void)
{
   DDRD=0x01;                //wyjście LED

   //Konfiguracja multipleksera
   SFIOR |= (1<<ACME);       //włącza multiplekser
   ACSR |= (1<<ACBG);        //wybór bandgab voltage jako AIN0
   ADMUX |= (1<<MUX1);       //ADC2 jako wejście ujemne

   for(;;)
   {
      if( ACSR & (1<<ACO))   //jeśli Napięcie wewnętrzne (2.56V)>ADC2
       PORTD |= 0x01;        //zapal diodę LED
      else                   //w przeciwnym wypadku
       PORTD &= ~0x01;       //zgaś diodę LED
   }
}
Pobierz program: ac3.rar



Eksperyment 4 - przerwanie

Sprawdzanie w pętli wyjścia komparatora (bitu ACO w rejestrze ACSR) może stać się kłopotliwe, gdy program wykonuje skomplikowane i czasochłonne operacje a my chcemy wykonać natychmiastową reakcję gdy nastąpi zmiana wyjścia komparatora.

Z pomocą przychodzi tutaj możliwość generowania przerwań przez komparator w zależności od zmiany stanu na wyjściu komparatora. Odpowiadają za to bity ACIS1 oraz ACIS0 w rejestrze ACSR.

Do wyboru w tym mikrokontrolerze jest:

Tab. Atmega8

Czyli przerwanie przy jakiejkolwiek zmianie stanu na wyjściu komparatora, przerwanie przy zmianie 0-1 lub przerwanie przy zmianie 1-0.

Do tego celu użyłem układu ze schematu w eksperymencie pierwszym:


Pobierz schemat: eagle1.rar

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


void main(void)
{
   DDRD=0x01;                //wyjście LED

   //uruchomienie obsługi przerwań
   ACSR    |= (1<<ACIE);     //ACIS0 i ACIS1 = 0 więc przerwanie przy
                             //jakiejkolwiek zmianie ACO

   sei();                    //włączenie obsługi przerwań

   for(;;);
}

ISR(ANA_COMP_vect)           //obsługa przerwania
{
   if( ACSR & (1<<ACO))      //jeśli AIN0>AIN1
    PORTD |= 0x01;           //zapal diodę LED
   else                      //w przeciwnym wypadku
    PORTD &= ~0x01;          //zgaś diodę LED
}
Pobierz program: ac4.rar



Podsumowanie

Atmega8 posiada tylko jeden komparator analogowy, który nie jest zbyt rozbudowany. Nowsze mikrokontrolery posiadają większą ilość bardziej funkcjonalnych komparatorów.

Jednak nawet w tym małym i dość prostym mikrokontrolerze, łącząc odpowiednio część sprzętową z oprogramowaniem można przy pomocy komparatora mierzyć i poniekąd przetwarzać na postać cyfrową wiele wielkości analogowych.

3 komentarze:

  1. "W temperaturze pokojowej, przy zasilaniu mikrokontrolera napięciem 5V jak widać napięcie to wynosi około 1,2V."
    A więc Vref~1,2V
    Natomiast w Eksperymencie 3 zostało użyte na wejście nieodwracające napięcie Vref, a do wejścia odwracającego zostało dołączone wejście z ADC.
    Przy linijce 14 czytamy:
    "if( ACSR & (1<ADC2 "

    Jest tutaj napięcie wewnętrzne opisane w komentarzu jako 2.56V co jest napięciem referencyjnym ADC, a nie komparatora.
    Możliwe, że jest tutaj błąd, albo ja coś nie rozumiem.
    Mam też pytania: jak wykorzystuje się Vref do wejścia odwracającego, to można niezależnie od tego używać pinu AIN0 jak wyjście, bo przecież ten pin nie służy nam w tym wypadku jako wejście?
    Jest jakaś różnica przy wykorzystywaniu wejść z multipleksera ADC, a normalnego AIN1? Bo rozumie, że przy wykorzystywaniu ADC możemy programowo zmieniać, które wejście ADC chcemy użyć, ale dla jednego pomiaru wystarczy AIN1?
    Możliwe, że DS jest trochę mylny jak się czyta: It is possible to select any of the ADC7:0 pins to replace the negative input to the Analog Comparator. Co można zrozumieć jako "jeśli nie ma się napięcia ujemnego", ale komparator jako WO może mieć podane napięcie dodatnie na wejście odwracające. Być może to też mój toporny angielski. :)
    Przepraszam za zamieszanie i dziękuję za prowadzenie tego bloga, który jest pomocny przy nauce.

    OdpowiedzUsuń
  2. Witam. Postanowiłem że podzielę się z Wami jednym ważnym spostrzeżeniem bo może komuś zaoszczędzę pracy w przyszłości. Otóż wówczas gdy korzystamy z multipleksera (za pomocą którego możemy ustalić pin źródłowy wejścia odwracającego komparatora) to wówczas nie możemy oczywiście stosować instrukcji: PRR|=(1<<PRADC); czyli nie możemy stosować instrukcji wyłączającej taktowanie modułu przetwornika ponieważ ten cały multiplekser jest wewnętrzną składową właśnie tegoż przetwornika. Nie chce mi się dowodzić skąd i czy w ogóle procek bierze jakieś napięcie na wejście odwracające jeśli ktoś tą instrukcję wykona w takim układzie natomiast wiem jedno, może natrafić na zonka także uwaga taka tylko. Pozdrawiam dociekliwych : AdamZad.

    OdpowiedzUsuń
  3. A czy można w głównej pętli while odczytywać z dwóch wejść adc jako ujemne ?? z moich prób się nie udało.

    OdpowiedzUsuń