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

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • 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.