logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Atmega128][c][WinAVR] Timer w trybie asynchronicznym

speecu 08 Lis 2009 16:49 2263 2
REKLAMA
  • #1 7232510
    speecu
    Poziom 11  
    Witam!

    Postanowiłem przetestować tryb asynchroniczny timera0 z podłączonym kwarcem 32768 Hz na płytce ZL9AVR i uC ZL7AVR.
    Napisałem programik
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    
    volatile int time=0;
    
    int main (void){
    	TCCR0|=(1<<WGM01)|(1<<CS02)|(1<<CS01)|(1<<CS00);	//--- Ustawienie Timer0 w tryb CTC i preskaler 1/1024
    	TIMSK|=(1<<OCIE0);	//--- Ustawienie przerwania Timer0 przy porównaniu
    	OCR0=32;	//--- Ustawienie licznika porównania Timer0
    	ASSR|=(1<<AS0);	//--- Ustawienie trybu asynchronicznego Timer0
    	sei();	//--- Włączenie obsługi przerwań
    
    	LCD_Init();	//--- Inicjalizacja i kasowanie LCD
    	LCD_Clear();
    	while(1){}
    	return 0;
    }
    
    ISR(TIMER0_COMP_vect){
    time++;	//--- Zwiększenie licznika
    LCD_GoTo(0,0);	//--- Ustawienie LCD
    //--- Wyswietlenie wartości time na LCD
    char bufor[6];
    LCD_WriteText(itoa(time,bufor,10));
    }


    Przy tych ustawieniach Timer0 powinien generować przerwanie co 1 sekundę i wyświetlić na LCD aktualną wartość zmiennej time.
    Niestety licznik opóźnia się o ok 2min/godz.
    Początkowo program był bardziej rozbudowany i myślałem, że to kwestia zbyt dużego obciążenia atmegi obliczeniami matematycznymi, które były wykonywane pomiędzy obsługą przerwań, ale 16M cykli pomiędzy nimi powinno starczyć na kilkukrotne podzielenie long przez int i wyświetlenie obliczonych wartości na LCD.
    Myślałem również, że przyczyną może być "gubienie" wywołania przerwania i brak inkrementacji zmiennej time, ale zmienna jest powiększana i wyświetlana prawidłowo, co sprawdziłem licząc kolejne zmiany przez ok 20 minut.
    W innych postach przeczytałem, że kwarc 32768 może mieć odchylenia od zadeklarowanej wartości, ale chyba nie aż takie.
    Czy źle zrozumiałem notę Atmegi (słaby angielski) i czegoś zapomniałem ustawić, czy też wina może leżeć po stronie hardware.

    Pozdrawiam
  • REKLAMA
  • Pomocny post
    #2 7233570
    ZbeeGin
    Poziom 39  
    Po co koledze ten CTC? Prescaler ustaw na 128 i wykorzystaj przerwanie przepełnienia licznika.

    Fint = Fosc / preskaler / 2^ilość_bitów_licznika = 32768Hz / 128 / 256 = 1Hz

    Przy CTC trzeba pamiętać, że występuje taki jeden mały szczegół jak 1+OCRn, gdyż licznik musi przynajmniej zliczyć jeden impuls. A ty go nie uwzględniłeś:

    Fint = Fosc / (preskaler * (1 + OCRn))

    Po podstawieniu wszystkich danych masz

    Fint = 32768/(1024*(1+32)) = 32768/33792 = 0,96Hz

    I tu kryją się te Twoje dwie minuty.


    I jeszcze jedno. Wyświetlanie na LCD w przerwaniu to nie jest doby pomysł.
  • #3 7234285
    speecu
    Poziom 11  
    Dzięki za szybką odpowiedź i wyjaśnienie problemu.
    Czyli braki w angielskim dają znać. Nie doczytałem o tym jednym dodatkowym takcie który faktycznie sporo zmienia.
    Cytat:
    I jeszcze jedno. Wyświetlanie na LCD w przerwaniu to nie jest doby pomysł.

    Wiem, wiem już kiedyś był poruszany ten temat, ale na moje usprawiedliwienie powiem tak: Wg mnie jest to najprostsza metoda do testowania zmiennych w przerwaniach, której to metody nie używam w docelowym programie.

    Jeszcze raz dziękuję.

    POMÓGŁ++
REKLAMA