Zobacz także:
- Mikrokontrolery AVR część 1 – wprowadzenie
- Mikrokontrolery AVR część 2 – podstawy
- Mikrokontrolery AVR część 3 – wokół kontrolera
- Mikrokontrolery AVR część 4 – Porty we/wy
- Mikrokontrolery AVR część 5 – przerwania
- Mikrokontrolery AVR część 6 – timer0
- Mikrokontrolery AVR część 7 – tmier1
- Mikrokontrolery AVR część 8 – timer2
- Mikrokontrolery AVR część 9 – Komparator analogowy
- Mikrokontrolery AVR część 10 – transmisja szeregowa UART
W poprzednim artykule zajmowaliśmy się timerem 0, który był stosunkowo prostym układem, w tej część będzie zawierała opis timera 1. Rysunek poniżej pomoże bardzo w zrozumieniu działania licznika, jednak co do szczegółów odsyłam do noty katalogowej, bo to zagadnienie jest z byt szerokie jak na ten artykuł. Postaram się jednak opisać podstawowe tryby pracy tego licznika.
Jest to o wiele bardziej rozbudowany układ, mogący pracować w kilku (15) trybach. Mamy takie tryby jak PWM, CTC, oraz tryb normalny. Tryby PWM i CTC mają jeszcze po kilka odmian, ale to tym za chwile.
Tryb normalny, to taki prosty licznik, jak licznik0, czyli zlicza aż się przepełni o wtedy daje sygnał przerwania. Łatwe i proste.
Tryb PWM zajmuje się generacją przebiegu prostokątnego o regulowanym współczynniku wypełnienia. Mamy takie tryby PWM:
- szybki PWM
- PWM z poprawną fazą
- PWM z poprawną fazą i częstotliwością
Tryb szybki PWM (fast PWM)
Jego zadaniem jest generowanie sygnału o zmodulowanym współczynniku wypełnienia na wyjściach OC1A i OC1B. Zlicza od zera, aż do momentu porównania z rejestrem OCR1A lub OCR1B, chyba, że wcześniej osiągnie wartość określoną jako TOP. Kiedy zostanie osiągnięta odpowiednia wartość, stan na liniach OC1A i OC1B zmienia swój stan w sposób określony poprzez bity COM1A1:0. Tryb ten charakteryzuje się wysoką częstotliwością generowanego sygnału. A o tej częstotliwości mówi ustawienie preskalera, i obliczamy ją ze wzoru:
Działa to tak, licznik zlicza zawsze w górę, kiedy osiąga wartość równą zawartości rejestru OCR1x stan na wyjściu OC1x zostanie ustawiony na stan logiczny 0, a gdy licznik się przepełnia i zaczyna zliczać od nowa, to wtedy na wyjściu OC1x ustawia się logiczna 1. Świetnie to obrazuje wykres zaczerpnięty z noty katalogowej.
Radzę go bardzo dokładnie przestudiować, gdyż zrozumienie tego wykresu stanowi klucz do programowania timera1 w kontrolerach AVR.
Pojawia się na tym wykresie zanegowanie linii OCnx, jest możliwe osiągnięcie takiego efektu poprzez odpowiednie bity rejestru TCCR1A. Te bity to COM1A0, COM1B0, COM1A1 oraz COM1B1. Poprzez odpowiednią konfiguracje tych bitów możemy ustawić tak zmiany stanów logicznych na wyjściach licznika.
PWM z poprawną fazą
Różnica pomiędzy tym trybem a poprzednim jest taka, że zlicza on najpierw w górę, a następnie w dół. Co zapewnia poprawną fazę generowanego sygnału. Częstotliwość sygnału, który zostanie wygenerowany w tym trybie można obliczyć z tego samego wzory, co przy trybie szybkiego PWM.Ten powyższy schemat pokazuję jak działa licznik w tym trybie. Ze względu na to że licznik zlicza w dwie strony jest on zalecany do sterowania silnikami.
Tryb CTC
W tym trybie licznik zlicza w górę, aż do momentu porównania z rejestrem OCR1A lub ICR1. W chwili gdy zachodzi zrównanie się zawartości licznika z rejestrem OCR1A bądź ICR1 (zależnie od trybu) stan licznika zostaje wyzerowany, a stan na linii OC1A ulega zmianie na przeciwny.
Ten tryb umożliwia generowanie przebiegu prostokątnego o określonej częstotliwości, która jest zależna od zawartości rejestru OCR1A lub ICR1. A policzenie tej częstotliwości umożliwia wzór:
Gdzie N to wartość prescalera.
Wybór trybu
Do wyboru trybu służą bity WGM10, WGM11 z rejestru TCCR1A oraz bity WGM12, WGM13 z rejestru TCCR1B. Konfigurację trybów opisuje tabla poniżej.
Trybów jest oczywiści o wiele więcej niż te co opisywałem, jednak nie ma miejsca w tym artykule na tak szeroki opis. Zachęcam do studiowania noty katalogowej kontrolerów AVR, tam jest wszystko zawarte.
Mode | WGM13 | WGM12 | WGM11 | WGM10 | Timer/Counter Mode | TOP | Update of OCR1x | TOV1 Flag Set on |
0 | 0 | 0 | 0 | 0 | Normal | 0xFFFF | Immediate | MAX |
1 | 0 | 0 | 0 | 1 | PWM, Phase Correct, 8-bit | 0x00FF | TOP | BOTTOM |
2 | 0 | 0 | 1 | 0 | PWM, Phase Correct, 9-bit | 0x01FF | TOP | BOTTOM |
3 | 0 | 0 | 1 | 1 | PWM, Phase Correct, 10-bit | 0x03FF | TOP | BOTTOM |
4 | 0 | 1 | 0 | 0 | CTC | OCR1A | Immediate | MAX |
5 | 0 | 1 | 0 | 1 | Fast PWM, 8-bit | 0x00FF | BOTTOM | TOP |
6 | 0 | 1 | 1 | 0 | Fast PWM, 9-bit | 0x01FF | BOTTOM | TOP |
7 | 0 | 1 | 1 | 1 | Fast PWM, 10-bit | 0x03FF | BOTTOM | TOP |
8 | 1 | 0 | 0 | 0 | PWM, Phase and Frequency Correct | ICR1 | BOTTOM | BOTTOM |
9 | 1 | 0 | 0 | 1 | PWM, Phase and Frequency Correct | OCR1A | BOTTOM | BOTTOM |
10 | 1 | 0 | 1 | 0 | PWM, Phase Correct | ICR1 | TOP | BOTTOM |
11 | 1 | 0 | 1 | 1 | PWM, Phase Correct | OCR1A | TOP | BOTTOM |
12 | 1 | 1 | 0 | 0 | CTC | ICR1 | Immediate | MAX |
13 | 1 | 1 | 0 | 1 | (Reserved) | – | – | – |
14 | 1 | 1 | 1 | 0 | Fast PWM | ICR1 | BOTTOM | TOP |
15 | 1 | 1 | 1 | 1 | Fast PWM | OCR1A | BOTTOM | TOP |
Przykłady
Dla tych co nic nie zrozumieli z tego artykułu (może ich być sporo) teraz kilka przykładów, które mam nadzieje rozwieją nie domówienia.
Przykład 1
Ten przykład będzie pokazywał działanie licznika w trybie CTC. Jego zadaniem będzie wygenerować przebieg prostokątny o o określonej częstotliwości. Będziemy korzystać z trybu numer 4.
#define F_CPU 1000000 //ustawienie oscylatora na 1MHz #include <avr/io.h> //dołączenie podstawowej biblioteki int main() { TCCR1B |= (1<<WGM12); //włączenie trybu CTC TCCR1B |= (1<<CS10) | (1<<CS11); //ustawienie preskalera na 64 OCR1A = 1000; //wartość do której zlicza licznik while(1) //pusta pętla { } }
Ten program będzie powodował generowanie przebiegu prostokątnego o częstotliwości około 7,8Hz. Czyli jak by podłączyć diodę LED do wyjścia OC1A to będzie jeszcze widać jak miga. Oczywiście diodą podpinamy poprzez rezystor ograniczający.
Przykład 2
Teraz zajmiemy się trybem PWM. Najczęściej spotkany jest tryb szybki, więc i taki przykład przedstawię. Będziemy mieli 10 bitową rozdzielczość, czyli tryb 7.
#define F_CPU 1000000 //ustawienie oscylatora na 1MHz #include <avr/io.h> //dołączenie podstawowej biblioteki int main() { TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10)|(1<<WGM11); //konfiguracja trybu TCCR1B = (1<<CS10)|(1<<WGM12); //konfiguracja trybu i prescalera OCR1A = 500; //wartość określająca współczynnik wypełnienia while(1) //pusta pętla { } }
Ten program generuje sygnał PWM o wypełnieniu niecałe 50%. Wartość dla OCR1A może wynosić od 0 (wypełnienie 0%) do 1023 (wypełnienie 100%).
Przykłady przedstawione w artykule nie były w żaden sposób sprawdzane, więc nie mogę zagwarantować bezproblemowego ich działania. Jednak w założeniach teoretycznych są prawidłowe.
Na tym przykładzie zakończę ten opis timera 1 w mikrokontrolerach AVR. Jest to tylko mała cześć możliwości tego licznika. Zachęcam to przestudiowania go głębiej, bo jest bardzo przydatnym narzędziem.
W następnej części przedstawię ostatni z liczników czyli licznik/czasomierz 2.
Witam,
w pierwszym kodzie po
OCR1A = 1000 powinien być średnik
i w while wartość np. 1
PS. bardzo porządne artykuły, dobra robota
Pozdrawiam
No może tam brakować średnika zaraz to poprawię. Z tą jedynką, to też mój błąd, dzięki za zauważenie.
Ciesze się, ze artykuł się podoba.
Przykład 2, żeby działała dioda trzeba jeszcze dodać:
DDRB = _BV(PB1);
Trochę mi zeszło żeby dowiedzieć się czemu nie działa
W 1, TCCR1A=(1<<COM1A0);
czy wykorzystując PWM da się ustawić jego wyjście na OC1B, lub włączyć jednocześnie dwa niezależne PWN – jedno z wyjściem na OC1A, drugie na OC1B?
Tak można wykorzystać wyjścia OC1A i OC1B jako dwa niezależne wyjścia PWM.
Proszę sprawdzić poprawność wzoru na wyliczenie częstotliwości dla licznika ustawionego w tryb fast PWM.
Nie nie powinien on wyglądać w ten sposób: focnxpwm = fclk_io/N*(1+TOP).
Dziękuje za informacje, faktycznie był błąd, to był wzór na częstotliwość w trybie ctc. Już wszystko poprawione.
Generuje chyba nie sinusoidę, tylko przebieg prostokątny.
Dzięki za uwagę, już poprawione.