Redakcja: dondu
Drzaśkowy pamiętnik: Spis treści
Warto przeczytać także ten artykuł: ADC - Ile da się wycisnąć? - czyli eksperymenty z ADC
Preskalery ADC może być jak widać z tabeli potęgą liczby 2:
Dla tych co nie wiedzą, co to jest preskaler: Prescaler, postscaler - Co to takiego?
Poprzez wybranie preskalera ustawić można częstotliwość taktowania przetwornika, a nie sama częstotliwość próbkowania. Aby obliczyć częstotliwość próbkowania trzeba uwzględnić także czas konwersji (patrz artykuł z linku powyżej). W efekcie częstotliwości próbkowania są dość niewygodne.
Zacząłem się więc zastanawiać jak uzyskać dokładnie interesującą mnie częstotliwość próbkowania.
Do głowy przyszły mi dwa pomysły:
- dobrać odpowiednio taktowanie procesora, np. z zewnętrznego generatora,
 - wykorzystać Timer.
 
Uruchomiłem ADC w trybie FREE RUN, bez zgłaszania przerwań po zakończonej konwersji. Ustawiłem Timer tak, aby zgłaszał przerwanie z interesującą mnie częstotliwością. W procedurze obsługi przerwania od Timera przepisywałem wartość pomiaru ADC do zmiennej.
Przykład pomiaru z częstotliwością 20 kHz (20 kSPS):
//kod5
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>   
#include "HD44780.h"
//definicja napiecia referencyjnego
#define VREF 5.0
//definicja ADCIN (wejście ADC)
#define ADCIN PC5 
volatile uint8_t adc;//zmienna do pomiaru ADC
 
void main(void)
{
 char wynik[]="    ";//bufor tekstowy, wyczyszczenie bufora
    
 LCD_Initalize();   //inicjalizacja LCD
 LCD_GoTo(1, 0);      //Ustawienie kursora w pozycji (0,0)
 LCD_WriteText("76,9 kHz 8 bit");
 //Inicjalizacja ADC
 ADCSRA = (1<<ADEN)      // ADC Enable (uruchomienie przetwornika)
          |(1<<ADFR)      //tryb Free run
          |(1<<ADSC)      //rozpoczęcie konwersji
          |(1<<ADPS2);   //ADPS2: (ustawienie preskalera) preskaler= 16
 ADMUX  = (1<<ADLAR)     //Wyrównanie wyniku do lewej
          |(1<<REFS0)            //VCC jako napięcie referencyjne
          |(1<<MUX2) | (1<<MUX0);   //Wybór wejścia (ADC5 - Pin 5 )
 //Inicjalizacja Timera
 TIMSK |= (1<<TOIE0) | (1<<TOIE1); //Przerwanie overflow przepełnienie timera
 TCCR0 |= (1<<CS01); // źródłem CLK, preskaler 8 (2000000 Hz)
 TCNT0 = 155; //Początkowa wartość licznika 
 DDRC &=~ (1<<ADCIN);               //Ustawienie pinu wejściowego ADC
 sei();//Globalne uruchomienie przerwań 
 for(;;)//główna pętla programu
 {
    LCD_GoTo(5, 1);         //Ustawienie kursora w pozycji (5,1)
    LCD_WriteText("    ");  //Czyszczenie poprzednij wartości
    itoa(adc,wynik,10);     //konwersja wyniku do tablicy char
    LCD_GoTo(5, 1);         //Ustawienie kursora w pozycji (5,1)
    LCD_WriteText(wynik);   //Wyświetlenie wyniku
    _delay_ms(100);         //opóźnienie
 }
}
ISR(TIMER0_OVF_vect)
{
    adc=ADCH;             //odczytaj tylko starszy bajt pomiaru
    TCNT0 = 155;          //Początkowa wartość licznika
}
Pobierz program: prog5.rarSchemat układu testowego znajdziesz tutaj: ADC - Ile da się wycisnąć? - czyli eksperymenty z ADC
Przeczytaj także:







Witam. Mam problem z napisaniem kodu. Potrzebuje plynnie sterowac predkoscia silnika za pomoca potencjometru. w Atmega32. W jaki spodob by to mozna bylo zrobic?
OdpowiedzUsuńadc<->fast pwm
Usuńadc<->fast pwm
Usuńjak chcesz kod i układ to napisz
Witaj, najprościej przeszukać forum Elektroda.pl, później spróbować coś samemu napisać, a dalej już tak: Fora dyskusyjne są bardzo pomocne
OdpowiedzUsuńTo naprawdę najlepsza droga :-)
Powodzenia!
Problem z tym kodem jest taki, że ADC w trybie Free run będzie obliczał wykonywał konwersję asynchronicznie do przerwań zegara a więc wartość pobrana w przerwaniu "ISR(TIMER0_OVF_vect)" może być niekompletna albo niewłaściwa (itp.).
OdpowiedzUsuńKod będzie prawidłowy jeśli ustawimy ADIF oraz w przerwaniu TIMER0_COMP_vect skopiujemy wartość wygenerowaną przez ADC do zmiennej globalnej - tu:adc. Po takim działaniu mamy zapewnione, że wartość pomiaru będzie prawidłowa (zapewni nam to sposób w jaki są obsługiwane przerwania).
W programie Drzasiek nie odczytuje stanu całego rejestru ADC, a jedynie ADCH. Poza tym, choć nie wynika to bezpośrednio z dokumentacji, to rejestr ADCH w trakcie trwania pomiaru pamięta poprzednią wartość. Można więc odczytywać ADCH w dowolnym momencie.
UsuńPomysł "ręcznego" ustawiania flagi ADIF jest bardzo dziwny :-)
Powyższy program można oczywiście napisać inaczej bez trybu Free Running:
1. Timer ustawiony na przerwania z częstotliwością 20kHz,
2. przerwanie timera rozpoczyna konwersję ADC,
3. przerwanie z ADC obrabia wynik pomiaru,
4. pętla główna wyświetla dane na LCD.
Istnieje jeszcze inne rozwiązanie - ADC może być wyzwalany zdarzeniem przepełnienia lub compare match timera. Nowsze ATMegi tak potrafią (np. ATMega88). Wtedy próbkowanie określa precyzyjnie timer np. w trybie CTC. Warto też pomyśleć np. o XMEGA, gdzie ADC może być wyzwalany przez event system, w efekcie próbkowanie może być wyzwalane przez cokolwiek tylko chcemy.
UsuńCzym tutaj jest tak na prawdę wyświetlany wynik i jak go zinterpretować żeby otrzymać częstotliwość z jaką pracuje nasz przetwornik? Wynik wyświetla mi się nawet gdy nie mam niczego na wejściu przetwornika wtedy jest to wynik około 110.
OdpowiedzUsuń