Tak na szybko - jak te wszystkie rejestry poustawiac? Zegar 4MHz. Wykombinowalem tak: Prescaler 256, wiec zliczenia nastepuja co 0,000064s, czyli do zliczenia
1s potrzebuje zliczyc 15625 impulsow. Wiec timer1 16bit zlicza w gore od 0 ... OCRA ustawiony na 15625 Clear Timer on Compare Match (CTC) Mode WGM13:0 = 4 i wywoluje procedurke moja (ktora np zlicza sekundy, jak sekundy >60 to minuty++ itd) czy wywolanie procedurki bedzie w postaci ?: SIGNAL(TIMER1_COMPA_vect) { costam; } I jak do tego poustawiac TCCR1A,TCCR1B i co jeszcze zeby wlaczyc przerwanie (tylko) od tego przeladowania?
Dzieki Oczywiscie na dokladnosc nie licze, po prostu chce przerobic stare programy z basica na c, i przy okazji powyrzucac "wait 15" zamieniajac na dekrementacje licznika w przerwaniu, cos mniejwiecej zamiast: if cos then wlacz costam wait 15 wylacz costam zamienie na: volatine uint8_t timer_jakis if (cos) timer_jakis=15; if (timer_jakis>0) {wlacz costam;} else {wylacz costam;} endif a w przerwaniu co 1s od timer1 bedzie if (timer_jakis>0) timer_jakis--;
Dzieki temu program sie zrobi troche bardziej "wielozadaniowy" ;)
ale gdy licznik doliczy do tej wartosci wpisanej do rejestrow OCR1Ax pojdzie dalej od wartosci 15625 do 65535, przejdzie przez 0 i wywola przerwanie znow gdy osiagnie 15625. Dlatego ustaw dodatkowo licznik w tryb pracy "Clear Timer on Compare Match (Auto Reload)", a wartosc poczatkowa ustaw na 0. Tak mi sie wydaje, wiec doczytaj szczegoly w pdf-ie procesora
Wlasciwie zdublowalem info podane wczesniej przez BartkaK. On w przykladowym kodzie powyzej zrobil to o czym ja mowilem, a ze nie uzywalem do tej pory timerow w AVRze wiec podalem ogolnie jak ma dzialac timer aby osiagnac to o co Ci chodzi. CTC to wlasnie tryb "Clear Timer on Compare Match (Auto Reload)".
Uzywasz trybu CTC gdzie wartosc TOP jest brana z rejestru OCR1A, wtedy bit WGM12 musi byc ustawiony a reszta (WGM10, WGM11, WGM13) wyzerowana. Zatem kod podany przez BartkaK jest OK, jedynie wyczytalem w opisie rejestru Timer/Counter Interrupt Flag Register - TIFR że bit TOV1 jest ustawiany w trybie normalnym i CTC(!) timera, więc wektor przerwania to ma byc SIG_OVERFLOW1, a nie SIG_OUTPUT_COMPARE1A (jak to podal BartekK):
_BV( x ) to makro wykonujace operacje ( 1 << x ) gdy uzywasz srodowiska WinAVR.
Jakby cos Ci nie dzialalo to daj znac, moze znajde chwile aby poprobowac na jakiejs mojej plytce prototypowej. Oczywiscie skoro uzywasz kwarca zewnetrzego, ustawiles odpowiednie fuse bity aby nie byl wykorzystany oscylator wewnetrzny ~1MHz.
Wlasciwie zdublowalem info podane wczesniej przez Murmiego. On w przykladowym kodzie powyzej zrobil to o czym ja mowilem, a ze nie uzywalem do tej pory timerow w AVRze wiec podalem ogolnie jak ma dzialac timer aby osiagnac to o co Ci chodzi. CTC to wlasnie tryb "Clear Timer on Compare Match (Auto Reload)".
Uzywasz trybu CTC gdzie wartosc TOP jest brana z rejestru OCR1A, wtedy bit WGM12 musi byc ustawiony a reszta (WGM10, WGM11, WGM13) wyzerowana. Zatem kod podany przez Murmiego jest OK, jedynie wyczytalem w opisie rejestru Timer/Counter Interrupt Flag Register - TIFR że bit TOV1 jest ustawiany w trybie normalnym i CTC(!) timera, więc wektor przerwania to ma byc SIG_OVERFLOW1, a nie SIG_OUTPUT_COMPARE1A (jak to podal Murmie):
_BV( x ) to makro wykonujace operacje ( 1 << x ) gdy uzywasz srodowiska WinAVR.
Jakby cos Ci nie dzialalo to daj znac, moze znajde chwile aby poprobowac na jakiejs mojej plytce prototypowej. Oczywiscie skoro uzywasz kwarca zewnetrzego, ustawiles odpowiednie fuse bity aby nie byl wykorzystany oscylator wewnetrzny ~1MHz.
Odpowiadam sam sobie, ale juz z ciekawosci chcialem przecwiczyc ten timer w trybie CTC (kto wie moze w przyszlosci mi sie to przyda) i napisalem kod na swoja uklad testowy. Okazuje sie ze kod ktory przytoczylem powyzej jest zly, bo nie sa generowane przerwania. Wkurzylem sie i poczytalem dokladnie wszystko o Timerach, w opisie trybu CTC Timera0 jest "An interrupt can be generated each time the counter value reaches the TOP value by using the OCF0 Flag." (a nie ma podobnej informacji w opisie trybu CTC Timera1 dotyczacego bitu OCIE1A), zaś w opisie rejestru TIFR Timera1: "In Normal and CTC modes, the TOV1 Flag is set when the timer overflows.". Ta druga informacja mnie zmyliła. Zatem kolega Murmie podal faktycznie uzywany wektor przerwania w swoim kodzie przykladowym. Ponizej podaje sprawdzony, dzialajacy kod:
#include <avr/io.h>
#include <avr/interrupt.h>
int main( void ) { DDRA = 0xFF; // PORTA bedzie przelaczany miedzy 0x00 a 0xFF
return 0; // tylko aby uniknac warning kompilatora }
SIGNAL( SIG_OUTPUT_COMPARE1A ) { // funkcja wolana co 1 sekunde! PORTA = ~PORTA; // Neguj zawartosc bitow PORTA }
Teraz na porcieA co sekunde jego bity beda negowane.
Uwaga: na symulatorze AVRStudio widac, ze rejestry Timera nie sa automatycznie zerowane w momencie dojscia do wartosci takiej jak zapisana w OCR1 (16bit), tylko troszke pozniej -> tak samo jest na sprzecie, w funkcji obslugi przerwania jak odczytywalem wartosc TCNT1L i wpisywalem ja do portuA mial wartosc 0x00, ale max wartosc odczytywana w tej nieskonczonej petli jaka TCNT1L uzyskal byla rowna OCR1AL (przy czym OCR1AH byl ustawiony na 0x00).
Faktycznie, jest to w punkcie "Output Compare Units": "If TCNT equals OCRnx the comparator signals a match. A match will set the Output Compare Flag (OCFnx) at the next timer clock cycle."
Człowiek nie doczyta dwóch zdań a potem spędzi tydzien dociekając z jakiej przyczyny dostaje event nie co 1sekundę, ale co 999,936 milisekund!!!
Faktycznie, jest to w punkcie "Output Compare Units": "If TCNT equals OCRnx the comparator signals a match. A match will set the Output Compare Flag (OCFnx) at the next timer clock cycle."
Człowiek nie doczyta dwóch zdań a potem spędzi tydzien dociekając z jakiej przyczyny dostaje event nie co 1sekundę, ale co 1000,064 milisekund!!!
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.