Skocz do zawartości

[C] ATmega8 Timer1 16-bit nie startuje.


peter507

Pomocna odpowiedź

Witam !

Mam problem z uruchomieniem TIMERA1 w ATmega8. Chcę aby przerwanie przychodziło z częstotliwością 1Hz, Częstotliwość taktowania procesora to 8Mhz. Wklejam kod, który napisałem:

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

#define PRZERWANIE_OFF TCCR1B &= ~ ( (1<<CS12) | (1<<CS11) | (1<<CS10) ) //wyłaczenie preskalera
#define PRZERWANIE_ON TCCR1B  |= (1<<CS12) //ustawienie preskalera na 256

int main(void)
{

TCCR1B |= (1<<WGM12);									//CTC
PRZERWANIE_OFF;
TIMSK |= (1<<OCIE1A);									// przerwanie Compare Match A

OCR1A = 31250;											//wartość rejestru porówania równa wartości częstotliwości zliczania impulsów czyli 8MHz / 256 = 31250Hz

sei();	

while(1)
{

}

ISR(TIMER1_COMPA_vect)										//procedura przerwania TMIERA1 Compare Match A (przerwanie co 1sek.)
{
uint8_t licznik = 0;
licznik ++;											
if (licznik == 10)
{												
	licznik = 0;										
	PRZERWANIE_OFF;										
}
}
}


Jak widać, jest to tylko fragment programu, który odpowiada za obsługę przerwania. W skrócie, w pętli głównej, mamy włączanie przerwania, a po odliczeniu przez przerwanie 10 sekund, przerwanie ma się wyłączyć. Niestety, to nie działa, nie wiem za bardzo czemu.

Link do komentarza
Share on other sites

Zmienną licznik definiujesz w przerwaniu jako obiekt automatyczny (chyba tak to się nazywa) - czyli tylko istnieje w tym przerwaniu, po jego zakończeniu obiekt jest kasowany.

Spróbuj definicję zmiennej licznik umieścić na górze programu (po za funkcjami) i dodaj przydomek volatile. To sprawi, że "zabronisz" kompilatorowi optymalizować tej zmiennej. "On myśli", że przerwanie się nigdy nie wykona, bo nigdzie w programie nie wywołujesz tej funkcji, więc pewnie optymalizuje tą zmienną.

Ogólnie zasada jest taka, że wszystkie zmienne które się używa w przerwaniu, muszą być z przydomkiem volatile.

  • Lubię! 1
Link do komentarza
Share on other sites

Dzięki kolego, bartek1333. Przerwanie zaczęło działać. Tylko coś jest nie tak z czasem. Teoretycznie powinno być 10 sek, a za każdym razem ten czas jest inny. Macie może pomysł czym to może być spowodowane ?. Może definicja

#define PRZERWANIE_OFF TCCR1B &= ~ ( (1<<CS12) | (1<<CS11) | (1<<CS10) ) 

tylko zatrzymuje przerwanie, a nie resetuje jego licznika ?

Prawodopodobnie timer w ogóle się nie zatrzymuje, dlatego czas jest różny. Macie jakiś pewny sposób na zatrzymanie timera w dowolnym miejscu programu ?

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Napisałeś:

W skrócie, w pętli głównej, mamy włączanie przerwania,

A w programie masz:

TCCR1B |= (1<

PRZERWANIE_OFF;

TIMSK |= (1<

To w końcu włączasz w pętli głównej przerwanie, czy jak?

Link do komentarza
Share on other sites

w pętli głownej czytaj w while(1), w mainie przed while wyłączam, ponieważ ma być włączany na żądanie.

wygląda to mniej wiecej tak:

while(1)
{
   if (jakas_zmienna == 4)
   {
      PRZERWANIE_ON;
   }
}
Link do komentarza
Share on other sites

Zablokowanie zegara (wyzerowanie bitów CS1x) zatrzymuje timer ale go nie zeruje - dlaczego miałoby to robić? Przed puszczeniem kolejnego cyklu zliczania musisz timer "ręcznie" wyzerować, żeby pierwsza sekunda była prawidłowej długości. Co prawda błąd nie powinien być duży, bo z poprzedniego cyklu timer (po poprzednim zatrzymaniu w obsłudze przerwania) nie będzie miał dużego naddatku w szczególności gdy pracuje z prescalerem 1024 ale sztuka cierpi. Jak duże są różnice o których piszesz? W jaki sposób je mierzysz i co je sygnalizuje?

W jaki sposób reszta programu będzie dowiadywać się o zliczeniu zadanego czasu? Przez sprawdzanie czy timer wciąż liczy (bit CS12 ustawiony)?

Okres: do OCR1A musisz wpisać o 1 mniej, bo timer zeruje się po komparacji.

A na koniec o dokładności (nie myślę o powtarzalności): przy wykorzystaniu wewnętrznego generatora RC nie liczyłbym na lepszą niż kilka procent.

Spróbuj wrzucać kod naprawdę niedziałający a nie jakiś okrojony fragment, który ewidentnie działać nie może z przyczyn oczywistych (np. brak załączania przerwania w powyższym). Arbitralnie wycinając szczegóły wg własnego uznania pozbawiasz nas szansy wnikania w niuanse kodu a często tam siedzi problem.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.