Ten post chciałbym poświęcić na opisanie programowanie 16 bitowego timera na mikrokontrolerze Atmega328 poprzez płytkę Arduino oraz 8 bitowego timera 8 bitowego. Timer 0 zostawię na inną okazję.
Mikrokontroler Atmega328 zawiera jeden timer 16 bitowy. Jest on w dokumentacji opisany jako Timer/Counter1 (TC1).
Timer 1 posiada następujące rejestry:
- TCNT1 - podzielony na część starszą TCNT1H, oraz młodszą TCNT1L. Pozostałe rejestry są podzielone w ten sam sposób.
- OCR1A - rejestr wyjściowy komparatora
- OCR1B - rejestr wyjściowy komparatora
- ICR1 - rejestr wejściowy komparatora
W związku z tym, że jest to układ 8 bitowy należy dane do rejestru 16 bitowego wpisać w paczkach po 8 bitów. Najpierw 4 starsze bity, potem 4 młodsze.
Drugi z opisanych tu timerów to 8 bitowy układ timera 2. Nadaje się do krótkich opóźniej. Spowodowane jest to bardzo wysokim dzielnikiem. Może działać w trybie normalnym bądź CTC. Jego obsługa sprowadza się głównie do rejestrów TCCR2A, TCCR2B, TIMSK2, TIFR2, TCNT2 oraz OCR2.
Poniżej przykład dla timera 2:
Przedstawię krótki program pozwalający na obsługę timera 2 na przerwaniach, które będzie wyzwalane co 250us.
Każda z linijek została opisana bezpośrednio w programie.
- #include <avr/io.h>
- #include <avr/interrupt.h>
- int main(void)
- {
- OCR2A = 0x3E;
- TCCR2A |= (1 << WGM21); //Wlaczenie trybu CTC (Clear on compare match)
- TIMSK2 |= (1 << OCIE2A); //Wystapienie przerwania gdy zliczy do podanej wartosci
- TCCR2B |= (1 << CS21); //Ustawienie dzielnika na 8, po czym start
- sei(); //Wlaczenie przerwan
- while (1) { }
- }
- ISR (TIMER2_COMPA_vect) { //Obsluga przerwania
- }
Poniżej przykład dla timera 1:
Poniżej program włączający w tym korekcję fazy oraz częstotliwości sygnału PWM. Poniżej przedstawię linijka po linijce w jaki sposób wykonać jego włączenia. Na samym początku należy zdefiniować odpowiednie porty jako wyjścia na pinach B1 oraz B2. Ponieważ posiadają one wyjścia PWM Set Comper dla Timera 1.
- DDRB |= _BV(DDB1) | _BV(DDB2);
Następnie należy ustawić wartość początkową dla Timera za pomocą rejstru TCNT1. Tej modyfikacji najlepiej dokonywać na początku przed włączeniem timera, ponieważ może to grozić niepoprawnym działaniem układu.
- TCNT1 = 0x00;
Kolejnym krokiem jest ustawienie odpowiedniej wartości w rejestrze kontrolnym TCCR1A. Pozwala on na ustawienie parametrów sygnału PWM. Sygnał na PB1 będzie nie odwrócony, natomiast na PB2 będzie odwrócony.
- TCCR1A |= (1<<COM1A1)|(1<<COM1B1)|(1<<COM1B0);
Dalej ustawiana jest wartość w rejestrze ICR1, czyli Input Capture Register.
- IRC1 = 0x00FF;
Teraz w drugim rejestrze kontrolnym TCCR1B wartości maksymalnej do jakiej będzie zliczał oraz wygląd przebiegów.
- TCCR1B |= (1<<WGM13);
Ustawienie wartości porównawczych.
- OCR1A=0x0064;
- OCR1B=0x0096;
Na samym końcu jest włączenie timera z dzielnikiem. Do tego celu służy rejestr TCCR1B w których zdefiniowane są bity CS12, CS11 oraz CS10. Można wybrać następujące wartości 1, 8, 64, 256 oraz 1024.
- TCCR1B|=(1<<CS11)|(1<<CS10);
Poniżej jeszcze krótki przygład dotyczący obsługi przerwania od od timera 1 z wyzwalaniem co 200ms.
- #include <avr/io.h>
- #include <avr/interrupt.h>
- int main(void)
- {
- ICR1H = 0x30;
- ICR1L = 0xD3;
- TCCR1B |= (1 << WGM12); //Ustawienie CTC
- TIMSK1 |= (1 << ICIE1); //Wlaczenie przerwania na porowanie (compare)
- TCCR1B |= (1 << CS12); //Dzielnik na 256
- sei();
- while (1){ }
- }
- ISR (TIMER1_COMPA_vect){
- //Obsluga przerwania
- }
Bibliografia
[1] Atmega328 - Datasheet