Zaczynając naukę programowania zaczyna się od wyświetlenia na ekranie komputera napisu Hello Word. W przypadku nauki programowania mikrokontrolerów wyświetlenie jakiegokolwiek napisu na ekranie komputera na pierwszych zajęciach może się okazać problematyczne. Przyjmijmy, że nasz Hello Word będzie wyświetlony na diodach.
Kurs programowania mikrokotrolerów jest przeznaczony dla rodziny AVR AtMega i oparty o model AtMega644p. Do celów kursu wykorzystuje płytkę prototypową firmy AND-TECH EvB 5.1.
Zakładam, że osoby czytające ten wpis mają już jakąś wiedzę dotyczącą programowania, a nawet znają już język C przynajmniej w podstawowym stopniu. Dalszym założeniem jest iż takowe osoby wiedzą co nie co o elektronice i byle „dioda” ich nie wystraszy.
Programowanie mikrokontrolerów nie różni się zbytnio od programowania komputerów. Nasz program zaczniemy od dołączenia bibliotek z których będziemy korzystać wraz z podstawowymi definicjami.
/* Definicje */ #define F_CPU 16000000UL //Definicja czestotliwosci procesora #define LEDS PORTB /* Dolaczane biblioteki */ #include <avr/io.h> //Biblioteka wejsc/wyjsc #include <util/delay.h> //Biblioteka opoznien #include <stdint.h> //Biblioteka typow liczb
I tak biblioteka <avr/io.h> zapewnia nam informacje o obsłudze wejść i wyjść. <util/delay.h> pozwoli nam na wstawianie opóźnień czasowych, przydatnych jak byśmy chcieli jakieś zmiany pracy naszego układu zarejestrować „gołym okiem”. Następną biblioteką którą wykorzystamy jest <stdint.h> . W tej bibliotece przechowywane są informacje o typach liczb.
A po co te definicje? Pierwsza definicja jest potrzebna aby opóźnienia działały. Sam uC nie wie jakim zegarem jest taktowany, temu trzeba go o tym poinformować. Jeżeli wiemy z jaką częstotliwością jest taktowany nasz układ to możemy przeliczyć ile takich taktów musi odmierzyć aby minęła jedna sekunda. No dobra, a druga definicja? To już kwestia udogodnienia, abyśmy nie musieli pamiętać gdzie podpięliśmy swoje diody.
Okey, mamy już jakieś podstawy do dalszego programowania ale gdzie będzie umieszczony nasz główny program? Otóż trzeba zauważyć zasadniczą różnicę pomiędzy programowaniem komputerów, a mikrokontrolerów. Program na komputerze wywoływany jest raz i przestaje pracować gdy wykona swoje zadanie. Innego typu pracy chcemy od naszych mikrokontrolerów. One mają pracować nieprzerwanie, wykonując pewne operacje. Z tej przyczyny nasz program będzie już w założeniu wyglądał inaczej niż byśmy pisali go dla komputera.
/* Funckja main() */ int main() { /* Petla nieskonczona */ while(1) { ; } }
W funkcji main() mamy pętlę nieskończoną while(1) to ona zapewnia nam ciągłe wykonywanie się określonych zadań. W tym momencie pętla jest pusta, co daje nam efekt cyklicznego powtarzania polecenia „nic”. No dobra chcemy, żeby nasz procek wykonywał coś więcej. Baa najlepiej aby wykonywał dokładnie to co założyliśmy. I tu nasuwa się pytanie… co my założyliśmy…. A no tak, mieliśmy napisać Hello Word dla mikrokontrolera i zrealizować to na diodach LED. Proponuje to zrobić poprzez cykliczne (trzeba jakoś wykorzystać bibliotekę opóźnień) zaświecanie i gaszenie diod LED.
Aby to zrobić przypisujemy do zmiennej LEDS oznaczającej port który wcześniej zdefiniowaliśmy pewną wartość. Jako, że port w tej konkretnej AtMedze posiada 8 pinów, to zapalmy na początek cztery pierwsze diody. Osiem stanów wyjść portu jest reprezentowane poprzez kombinację od 0 do 255. Trudno przeliczyć która kombinacja za co będzie odpowiadać, ale jest na to rada. Możemy użyć zapisu binarnego i tak, tylko pierwsze cztery świecące diody LED możemy zapisać jako 0b11110000. No już jest fajniej, a czy w tym przypadku nie dało by się to jakoś skrócić? A można, wystarczy użyć zapisu hexadecymalnego. I tak cztery bity w stanie wysokim to F, czyli dla całego portu to będzie: 0xF0. Dobra następny stan będzie na odwrót, analogicznie przypiszemy wartość 0x0F. Ale ale Czy zdołamy to zobaczyć? Otóż nie koniecznie bo procesor wykonuje miliony operacji na sekundę (sami zdefiniowaliśmy F_CPU). To teraz trzeba dodać opóźnienie. 0.5 sekundy powinno starczyć, używamy do tego funkcji w bibliotece <until/delay.h> o nazwie _delay_ms() z parametrem ilości milisekund. A wszystko jest wewnątrz pętli nieskończonej.
/* Funckja main() */ int main() { /* Petla nieskonczona */ while(1) { LEDS = 0xf0; //Zapalenia pierwszej tetrady _delay_ms(500); //Opoznienie 0.5s LEDS = 0x0f; //Zapalenie drugiej tetrady _delay_ms(500); //Opoznienie 0.5s } }
Dobra czy napisaliśmy już pełny program? Nie! Zapomnieliśmy o konfiguracji naszego mikrokontrolera. Napiszmy sobie funkcję którą wywołamy na początku trwania programu o nazwie ConfIO().
/* Funckja main() */ int main() { /* Konfiguracja procesora */ ConfIO(); /* Petla nieskonczona */ while(1) { LEDS = 0xf0; //Zapalenia pierwszej tetrady _delay_ms(500); //Opoznienie 0.5s LEDS = 0x0f; //Zapalenie drugiej tetrady _delay_ms(500); //Opoznienie 0.5s } }
Funkcja ConfIO() będzie nam służyła do konfiguracji portu na wyjścia. Za konfigurację portu służy nam rejestr DDRx. Konfigurujemy port B więc używamy rejestru DDRB. Bity wysokie w tym rejestrze będą oznaczały tryb działania pinu jako wyjście, a niskie jako wejście.
void ConfIO(void) { /* DDRx rejestr ustawiajacy tryb pracy pinow, 1 - wyjscie, 0 - wejscie */ DDRB = 0xff; //Port diod LED /* PORTx rejestr ustawiajacy stany pinow */ PORTB = 0xff; //Ustawienie wartosci stanu wysokiego }
Teraz napisaliśmy swój pierwszy program, wystarczy połączyć wszystko w całość 🙂
W ten sposób napisaliśmy swój pierwszy program dla procesora AVR
/***************************************************************** * * R01_Diody * Diody_na_przemian * main.c * Plik : main.c * Mikrokontroler : Atmel AVR atmega644p * Kompilator : avr-gcc Toolchain * Autor : Mariusz Czajkowski * Źródło : http://uengineering.net/ * Data : 08.12.2012 * *****************************************************************/ /***************************************************************** * * PORTB podlaczony do diod LED * PORTC<0,1> podlaczony do przyciskow * *****************************************************************/ /* Definicje */ #define F_CPU 16000000UL //Definicja czestotliwosci procesora #define LEDS PORTB /* Dolaczane biblioteki */ #include <avr/io.h> //Biblioteka wejsc/wyjsc #include <util/delay.h> //Biblioteka opoznien #include <stdint.h> //Biblioteka typow liczb /* Funkcje wlasne */ void ConfIO(void) { /* DDRx rejestr ustawiajacy tryb pracy pinow, 1 - wyjscie, 0 - wejscie */ DDRB = 0xff; //Port diod LED /* PORTx rejestr ustawiajacy stany pinow */ PORTB = 0xff; //Ustawienie wartosci stanu wysokiego } /* Funckja main() */ int main() { /* Konfiguracja procesora */ ConfIO(); /* Petla nieskonczona */ while(1) { LEDS = 0xf0; //Zapalenia pierwszej tetrady _delay_ms(500); //Opoznienie 0.5s LEDS = 0x0f; //Zapalenie drugiej tetrady _delay_ms(500); //Opoznienie 0.5s } }
100 Comments
You must log in to post a comment.