Kursy • Poradniki • Inspirujące DIY • Forum
Gdy zaczynałem przygodę z programowaniem, w Internecie, można było znaleźć dużo przykładów w Bascomie oraz całkowitą pustkę jeśli chodzi o język C. Dodatkowo, sytuacji nie ułatwiał mi brak znajomości języka angielskiego. Próby szukania czegokolwiek w dokumentacji były porażkami.
Dlatego pamiętając o takich niby błahych – choć myślę, że częstych i utrudniających szybkie „wejście” w robotykę - problemach początkujących, chciałbym wytłumaczyć, jak sobie z nimi radzić. W tym artykule wskażę jakich rozdziałów i tabel szukać w dokumentacji, aby odpowiednio ustawić timery oraz jak to później wykorzystać w przykładowym kodzie robota.
Inicjalizacja PWM
W przykładzie posłużę się wykorzystaniem licznika (timera) 16-bitowego ustawionego w tryb Fast PWM. Posiada on dwa kanały, więc może służyć np.: do sterowania dwóch silników.
Tryb Fast PWM 8-bit oznacza, że wypełnienie sygnału będziemy mogli regulować w zakresie od 0 do 255, gdzie 0 będzie oznaczało ciągły stan niski, a 255 ciągły stan wysoki. Oto czynności, które należy wykonać w celu inicjalizacji PWM:
Szukamy w nocie katalogowej (datasheet) rozdziału dotyczącego np.: Timera 1 (jest to Timer 16-bitowy). W nim odszukujemy tabelkę Waveform Generation Mode Bit Description. Przykładowo dla mikrokontrolera ATMEGA8A (nota w załączniku) jest to tabela 16-5, która znajduje się na str. 101:
Widzimy z niej, że musimy ustawić na 1 bity WGM12 i WGM10, aby Timer pracował w wybranym przez nas trybie. W naszym przypadku (ATMEGA8A, 16-bitowy Timer1) bity te znajdują się w dwóch różnych rejestrach (TCCR1A oraz TCCR1B).
Widać to w dokumentacji (rejestry są rozpisane na poszczególne bity, w naszym przypadku TCCR1A znajduje się na str. 99, TCCR1B na str. 101). W przypadku liczników 8 bitowych mamy tylko jeden rejestr TCCRx (gdzie x jest numerem licznika), a do wyboru mamy zazwyczaj tylko cztery tryby pracy.
Kolejnym krokiem jest podłączenie Timera do odpowiedniego pinu mikrokontrolera oraz określenie sposobu sterowania tymże wyjściem. W tym celu szukamy tabelki Compare Output Mode, Fast PWM. W naszym przypadku jest to tabelka 16-3 na str. 100:
Interesują nas w zasadzie tylko dwie ostatnie opcje. Wybieramy: Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM, (non-inverting mode) – oznacza to, że na starcie mamy stan wysoki, a podczas przerwania (gdy wartość licznika będzie taka sama, jak wpisana przez nas do OCRx) wyjście jest ustawiane w stan niski.
„Na chłopski rozum” mówiąc – im większą wartość wpiszemy do OCRx, tym dłużej na wyjściu będzie panował stan wysoki (wyższe „średnie” napięcie). Po wpisaniu maksymalnej wartości (w naszym przypadku 255, ponieważ wybraliśmy tryb 8-bit) na wyjściu będzie ciągle ustawiony stan wysoki, a po wpisaniu 0, na wyjściu będzie ciągle panował stan niski. Kolejne ustawienie działa w odwrotny sposób. Musimy więc ustawić w TCCR1A bity COM1A1 i COM1B1.
Uwaga!
Jeśli chcemy mieć dwa kanały (A oraz B), to musimy ustawić bit COM1A1 oraz COM1B1!
Wybór prescalera
Ostatnią czynnością jest wybranie prescalera. Od niego będzie zależała częstotliwość, z jaką będzie pracował nasz PWM. Generalnie, co do odpowiedniej częstotliwości zdania są mocno podzielone, tutaj możemy przeczytać dyskusję która była prowadzona na naszym forum na ten temat, ale ostrzegam, jest bardzo długa!
Za wartość prescalera odpowiadają bity CSxy. Aby dowiedzieć się, jakie mamy możliwości wyboru szukamy tabelki Clock Select Bit Description. W naszym przypadku jest to tabelka 16-6 na str. 102. W naszym przykładzie wybierzemy prescaler o wartości 64. Jak widać w tabelce, musimy w tym celu ustawić bity CS11 oraz CS10 w TCCR1B.
Jak więc obliczyć częstotliwość (f) naszego PWM? Załóżmy, że taktujemy nasz mikrokontroler częstotliwością 16MHz. Musimy więc podzielić ją przez prescaler oraz przez pojemność naszego licznika. Częstotliwość naszego PWM będzie wynosiła więc około 976Hz (16 000 000Hz / 64 / 256).
Inicjalizacja PWM powinna więc wyglądać tak:
TCCR1A |= (1<<WGM10);//Tryb: Fast PWM 8bit
TCCR1B |= (1<<WGM12);
TCCR1A |= (1<<COM1A1)|(1<<COM1B1);//Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM
TCCR1B |= (1<<CS10)|(1<<CS11);//Preksaler = 64, fpwm = 976,5Hz
//Sterowanie prędkością silników
OCR1A = 0; //Kanał A = 0
OCR1B = 0; //Kanał B = 0
Implementacja w programie robota
Teraz możemy przejść do wykorzystania PWM w programie (np.: robota). Po pierwsze musimy odpowiednie piny ustawić jako wyjścia. W przypadku omawianego mikrokontrolera (ATmega8A) są to PB1 oraz PB2. Nie można również pominąć pozostałych pinów, którymi sterowany będzie mostek H. Jednak to zależy już od konkretnej konstrukcji.
Następnie, w programie, musi nastąpić odpowiednie ustawienie PWM, czyli dokładnie, to czym zajmowaliśmy się poprzednio. Dalej można już pisać właściwy program. W celu zmiany wypełnienia sygnału PWM wystarczy wpisywać odpowiednie wartości do rejestrów OCR1A oraz OCR1B.
Przykładowy szkielet widoczny jest poniżej:
#include <avr/io.h>
#define PWM_A (1<<PB1)
#define PWM_B (1<<PB2)
//inne nasze definicje i deklaracje
/* FUNKCJA GŁÓWNA */
int main(void)
{
/* USTAWIANIE WYJŚĆ */
DDRB |= (PWM_A|PWM_B); //wyjścia pwm
/* INICJALIZACJA PWM - TIMER1 */
TCCR1A |= (1<<WGM10); // Fast PWM 8bit
TCCR1B |= (1<<WGM12);
TCCR1A |= (1<<COM1A1)|(1<<COM1B1) ; //Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM
TCCR1B |= (1<<CS10)|(1<<CS11); // Preksaler = 64 fpwm = 976,5Hz
OCR1A = 0; //kanał A = 0
OCR1B = 0; //kanał B = 0
/* PĘTLA GŁÓWNA */
while(1)
{
//główny program - odczyt czujników, odpowiednie obliczenia, sterowanie silnikami itd.
}
}
Podsumowanie
Mam nadzieje, że ten krótki artykuł udowodnił, że korzystanie z dokumentacji nie jest takie trudne. Wystarczy wiedzieć czego szukać, a najważniejsze informacje znaleźć można bez problemu w stosunkowo prostych tabelach. W razie problemów zachęcam do pytania w komentarzach.
Pierwsza publikacja: Grabki, 04-07-2012
Edycja i przeniesienie na blog: Treker, 26-05-2015, grafika tytułowa: Hudyvolt
Załączniki
To nie koniec, sprawdź również
Przeczytaj powiązane artykuły oraz aktualnie popularne wpisy lub losuj inny artykuł »
C, częstotliwość, inicjalizacja, konfiguracja, prescaler, programowanie, PWM
Trwa ładowanie komentarzy...