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.rar
Schemat 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ń