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

Timer/Counter0 ATMEGA8. Timer0 jako wyjście. Odliczanie odstępów czasu.

Kubbaz 05 Paź 2006 18:59 3694 16
REKLAMA
  • #1 3088164
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Witam

    Właśnie przeczytałem rozdział manuala M8 dot. pracy T/C0 i rejestrów odpowiadających za timer, tylko nie wiem jak zrobić, aby timer odmierzał wartość 1 sekundy .... ;|

    Otóż policzyłem, że wg tego co mam to:

    F-CPU = 8MHz
    Prescaler = 64
    MAX_VAL = 256 (bo 8-mio bitowy)

    więc:

    TOV ck = (F_CPU/Prescaler)/MAX_VAL = 488

    czyli wynika że w ciągu jednej sekundy timer zrobi 488 przepełnień lub inaczej: że jedno przepełnienia trwać będzie 2.049ms.

    Ok, świetnie....nic sie nie trzyma kupy ;|.
    Ktoś mógłby mi jasno napisać jak w języku C i przy pomocy tych kilku rejestrów obsługujących Timer0 uruchomić go jako WYJŚCIE i żeby odmierzał jakiekolwiek odstępy czasu ??
  • REKLAMA
  • #2 3088570
    Tdv
    Poziom 34  
    Posty: 2237
    Pomógł: 150
    Ocena: 53
    TCCR0=0x04;
    TCNT0=0x05;

    I w przerwaniu na początku musisz mieć:
    TCNT0=0x05;
    I zliczać równo 125 przerwań - odliczysz doładnie 1s.

    Tak przy okazji, nie prościej to zrobić na tajmerze 1, który jest 16 bitowy i nieco inaczej pracuje?

    Zresztą już w jednym Twoim wątku wstawiłem program kalkulatora do obliczania zawartości rejestrów do tajmerów i UARTa.
  • #3 3088585
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Kubbaz napisał:
    Witam

    Właśnie przeczytałem rozdział manuala M8 dot. pracy T/C0 i rejestrów odpowiadających za timer, tylko nie wiem jak zrobić, aby timer odmierzał wartość 1 sekundy .... ;|

    To chyba nie bardzo zrozumiałeś to , co przeczytałeś :(
    Timery nie potrafią odmierzać czasu , ale za to doskonale potrafią zliczać impulsy , których źródłem może być przeskaler lub źródło zewnętrzne.
    Jednakże to do piszącego program należy zinterpretowanie(wyliczenie) , ile czasu zajęło Timerowi zliczenie N impulsów taktujących , występujących co X sekund(y).
    Kubbaz napisał:

    Otóż policzyłem, że wg tego co mam to:

    F-CPU = 8MHz
    Prescaler = 64
    MAX_VAL = 256 (bo 8-mio bitowy)

    więc:

    TOV ck = (F_CPU/Prescaler)/MAX_VAL = 488

    ...

    I bardzo dobrze to policzyłeś , tylko pominąłeś część ułamkową przy liczbie 488.Korzystając z Twoich danych dotyczących F_CPU i prescalera , można napisać program , który z dość dużą dokładnością , co/po 1 sekundę coś tam wykona.A więc:
    W procedurze przerwania od przepełnienia T0 , zmniejszasz/zwiększasz jakąś zmienną 488 razy , a po zliczeniu 488 przepełnień , ustawiasz licznik na taką wartość , by przepełnienie nastąpiło po 72 impulsach z preskalera i to 489 przepełnienie nastąpi po 1 sekundzie , ponieważ:
    488*preskaler*pojemność licznika+(preskaler*72)=F_CPU , czyli
    488*64*256+(64*72)=8000000.Nie wiem czy taka dokładność Ci wystarczy , bo nie byłeś łaskaw o tym wspomnieć :(

    Piotrek

    PS
    Lub zrób tak , jak sugeruje Tdv
  • REKLAMA
  • #5 3089222
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Tdv napisał:
    TCCR0=0x04;
    TCNT0=0x05;

    I w przerwaniu na początku musisz mieć:
    TCNT0=0x05;
    I zliczać równo 125 przerwań - odliczysz doładnie 1s.


    ok ....tylko jak np. chcę żeby po tych 125 przerwaniach nastąpiła zniana stanu portu ?? to jak to ując w pętli głównej ??
  • #6 3089856
    GienekS
    Poziom 32  
    Posty: 1971
    Pomógł: 139
    Ocena: 15
    Możesz to zrobić na dwa sposoby.
    1. W przerwaniu zmienisz stan tego portu.
    2. Przerwanie ustawia ci pewną flagę że nastąpiło odmierzenie 1 sekundy a w pętli głównej programu testujesz tą flagę i jak wystąpi to zmienisz ten port a flagę kasujesz

    I cała filozofia. Czy to jest jasne ?
  • REKLAMA
  • #7 3090788
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    GienekS napisał:
    Czy to jest jasne ?

    Niestety nie ...:(

    ale spłodziłem taką mizernotę:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    int main ()
    {	
    	DDRD = 0xFF;
    
    	TCCR0=0x04;
    	TCNT0=0x05; 
    	
    	delayus (100);
    	sei ();
    
    	for (;;) 
    	{	
                    // I CO TU MA BYć W PęTLI GłóWNEJ ??
    	} 
        return (0);             
    }
    


    i pytane brzmi: jak skonstruowac kod w pętli głównej tak, aby na porcie TO (no bo od TIMERa) pojawiały się cyklicznie zmiany stanów logicznych (takia migająca dioda LED) ??
  • #8 3090811
    Tdv
    Poziom 34  
    Posty: 2237
    Pomógł: 150
    Ocena: 53
    Sory, że tak wprost zapytam: gdzie masz procedurę obsługi prpzerwania tego tajmera?
    I po co używasz delay do opóźnień jak chcesz mieć tajmer?
  • #9 3090824
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    Tdv napisał:
    Sory, że tak wprost zapytam: gdzie masz procedurę obsługi prpzerwania tego tajmera?
    I po co używasz delay do opóźnień jak chcesz mieć tajmer?


    I bardzo dobrze że o to zapytałeś - nie wiem jak to ma wyglądać i jak to napisać, a jasnowidzem nie jestem ;), żebym z sufitu odrazu napisał poprawny kod.....stąd proszę o pomoc w napisaniu krótkiego kwawałku dziłającego kodu .....uffff
  • #10 3091367
    Tdv
    Poziom 34  
    Posty: 2237
    Pomógł: 150
    Ocena: 53
    Pisane na żywca, nie wiem czy się skompiluje od strzału:
    
    #include <avr/io.h>
    #include <avr/signal.h>
    
    #define LED PORTC.0
    uint8_t liczba;
    
    SIGNAL (SIG_OVERFLOW0)
    {
      TCNT0=0x05;
      if(liczba++==250)
        {
         PORTC=~PORTC;
    	 liczba=0;
    	}
    }
    
    int main( void )
    { 
      DDRC=0x0FF;
      PORTC=0;
      TCCR0=0x04;
      TCNT0=0x05;
      TIMSK=0x01;
      sei();
      for (;;){}
      return(0);
    }
    


    Fragment który się zaczyna od SIGNAL to właśnie procedura obsługi przerwania.
  • #11 3091371
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    właśnie o taki przykład mi chodziło ... wielkie dzięki - zaraz spróbuje uruchomić kod ;)

    Dodano po 4 [godziny] 7 [minuty]:

    dzięki za kod - działa...
    tylko jedno pytanie:
    if(liczba++==250)


    mam kwarc 8MHz, i jak widać wg powyśzego kodu Tdv presckaler ustawiony jest na 256 oraz T0 jest 8-mio botowy, to czy aby "odmierzyć" 1 sekunde (zapalać diode na 1 s i ją gasić na 1s) nbie powienno być :

    if(liczba++==118)

    bo:

    TOVck = (8000000/256)/256 = 118 ?? czy sie myle ?
    aczkolwiek wydaje mi sie że troche sie spieszy :) ....mozna ustawić to jakoś dokładniej ?? a może na T1 ??;|
  • #12 3092946
    Tdv
    Poziom 34  
    Posty: 2237
    Pomógł: 150
    Ocena: 53
    W tym kodzie masz ładowanie do licznika wartości początkowej, więc licznik zlicza Ci do 250, a nie do 256. MOżesz zrobić sobie 118 ale twedy z procedury obsługi przerwania wywal ładowanie do TCNT0 wartości początkowej.
  • #13 3093144
    GienekS
    Poziom 32  
    Posty: 1971
    Pomógł: 139
    Ocena: 15
    Kubbaz napisał:
    if(liczba++==118)[/code]
    bo:

    TOVck = (8000000/256)/256 = 118 ?? czy sie myle ?
    aczkolwiek wydaje mi sie że troche sie spieszy :) ....mozna ustawić to jakoś dokładniej ?? a może na T1 ??;|
    bo wynik dzielenia nie jest przeciz bez reszty dlatego nie jest to dokladne. Powinno byc:
    8000000/256/250/125 = 1 sek oczywiscie dzielenie jak leci i tu nie ma reszty co powinno dac ci dokladnie 1 sekunde.
  • REKLAMA
  • #14 3093947
    Kubbaz
    Poziom 26  
    Posty: 1237
    Pomógł: 9
    Ocena: 30
    GienekS napisał:
    bo wynik dzielenia nie jest przeciz bez reszty

    to prawda ....
    GienekS napisał:
    Powinno byc:
    8000000/256/250/125 = 1 sek

    no faktycznie...bez reszty...tylko jak to uzyskać.....bo widzę, że robisz tu 3 dzielenia, a jak dotąd to zawsze dzieliłem 2 razy: raz przez prescaler i drugi raz przez wartośc maksytmalną timera0
  • #15 3093980
    Tdv
    Poziom 34  
    Posty: 2237
    Pomógł: 150
    Ocena: 53
    Kubbaz napisał:

    no faktycznie...bez reszty...tylko jak to uzyskać.....bo widzę, że robisz tu 3 dzielenia, a jak dotąd to zawsze dzieliłem 2 razy: raz przez prescaler i drugi raz przez wartośc maksytmalną timera0

    Czasmi wydaje mi się, że pisanie na forum to marnowanie czasu...
    Człowieku, poświeć 5 minut i przeczytaj moje posty, łącznie z tym, gdzie masz ten kod źródłowy bo ten kod działa właśnie według sposobu napisanego przez GieniekS.
    Wbrew temu co mówi i pokazuje władza Najjaśniejszej IV naszej, myślenie nie boli!
  • #16 3094063
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Tdv napisał:
    Czasmi wydaje mi się, że pisanie na forum to marnowanie czasu...
    ... a szczególnie w przypadkach , gdy ktoś prosi o wytłumaczenia działań na potęgach , a w trakcie okazuje się , że ów nie radzi sobie z dodawaniem czy odejmowaniem :(
    Taka przenośnia z algebry ;)

    Piotrek

Podsumowanie tematu

✨ Dyskusja dotyczy konfiguracji i wykorzystania 8-bitowego Timer/Counter0 w mikrokontrolerze ATmega8 do odmierzania odstępów czasu, w szczególności 1 sekundy. Omówiono obliczenia związane z częstotliwością taktowania (F_CPU = 8 MHz), prescalerem (np. 64 lub 256) oraz maksymalną wartością licznika (256). Wyjaśniono, że timer sam nie mierzy czasu, lecz zlicza impulsy, a interpretacja czasu wymaga odpowiedniego programowego zliczania przepełnień. Zaproponowano implementację przerwania przepełnienia timera, w którym liczona jest liczba przerwań (np. 125 lub 250) odpowiadająca 1 sekundzie. Przedstawiono przykładowy kod w języku C z obsługą przerwania (SIGNAL(SIG_OVERFLOW0)), inicjalizacją rejestrów TCCR0, TCNT0, TIMSK oraz konfiguracją portu wyjściowego do migania diodą LED. Omówiono różnice w ustawieniach prescalera i wartości początkowej licznika, które wpływają na dokładność odmierzania czasu. Zasugerowano również rozważenie użycia 16-bitowego Timera1 dla większej precyzji. Temat zakończono potwierdzeniem działania kodu i rozwiązaniem problemu.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA