czwartek, 29 września 2016

[3] Atmega328 - Timer 2/Timer 1

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.

  1. #include <avr/io.h>
  2. #include <avr/interrupt.h>
  3. int main(void)
  4. {
  5.     OCR2A = 0x3E;
  6.     TCCR2A |= (1 << WGM21); //Wlaczenie trybu CTC (Clear on compare match)
  7.     TIMSK2 |= (1 << OCIE2A); //Wystapienie przerwania gdy zliczy do podanej wartosci
  8.     TCCR2B |= (1 << CS21); //Ustawienie dzielnika na 8, po czym start
  9.     sei(); //Wlaczenie przerwan
  10.     while (1) { }
  11. }
  12. ISR (TIMER2_COMPA_vect) { //Obsluga przerwania
  13. }

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.

  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.

  1. 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.

  1. TCCR1A |= (1<<COM1A1)|(1<<COM1B1)|(1<<COM1B0);

Dalej ustawiana jest wartość w rejestrze ICR1, czyli Input Capture Register.

  1. IRC1 = 0x00FF;

Teraz w drugim rejestrze kontrolnym TCCR1B wartości maksymalnej do jakiej będzie zliczał oraz wygląd przebiegów.

  1. TCCR1B |= (1<<WGM13);

Ustawienie wartości porównawczych.

  1. OCR1A=0x0064;
  2. 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.

  1. 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.

  1. #include <avr/io.h>
  2. #include <avr/interrupt.h>
  3. int main(void)
  4. {
  5.     ICR1H = 0x30;
  6.     ICR1L = 0xD3;
  7.     TCCR1B |= (1 << WGM12); //Ustawienie CTC
  8.     TIMSK1 |= (1 << ICIE1); //Wlaczenie przerwania na porowanie (compare)
  9.     TCCR1B |= (1 << CS12); //Dzielnik na 256
  10.     sei();
  11.     while (1){ }
  12. }
  13. ISR (TIMER1_COMPA_vect){
  14. //Obsluga przerwania
  15. }

Bibliografia


[1] Atmega328 - Datasheet