KURS
Kurs Arduino (1)
Język programowania Rozpoczynamy naukę programowania Arduino. W pierwszej kolejności zajmiemy się specyficznym językiem Arduino, który dostępnymi bibliotekami oraz składnią niewiele różni się od języka C. Dlatego też preferowana jest podstawowa znajomość składni i komend języka C oraz ich użycia. W kolejnych częściach kursu zapoznamy się z zestawem Arduino UNO i jego uruchomieniem w środowisku Arduino IDE. W kolejnych częściach kursu zaprezentujemy sposób programowania w tym systemie na podstawie praktycznych przykładów. Jak wspomniano, język Arduino IDE jest zbliżony do języka C. Jego komendy umieszczono w tabeli 1. Składa się on ze struktur, zmiennych oraz funkcji. W strukturach Setup() oraz Loop(), wymaganych przez język Arduino, będzie się znajdował program. Pozostałe struktury kontrolne, arytmetyczne, bitowe czy logiczne pokazane w tab. 1 są identyczne, jak dla języka C. W programowaniu w każdym języku są wykorzystywane zmienne i związane z nimi typy danych oraz stałe. W języku Arduino, oprócz standardowych stałych dla języka C, są dostępne dodatkowe stałe LOW, HIGH, INPUT oraz OUTPUT związane z operacjami na liniach portów mikrokontrolera. Natomiast typy zmiennych są identyczne jak dla języka C. Nowością w języku Arduino są dostępne funkcje związane z mikrokontrolerem. Dostępne są funkcje wykonujące operacje na portach mikrokontrolera. Pierwsza z funkcji pinMode(pin, mode) umożliwia konfigurowanie poszczególnych wyprowadzeń portów mikrokontrolera, ustalanie czy dana nóżka ma być wejściem czy wyjściem. Pozostałe funkcje digitalWrite() oraz digitalRead() dotyczą zapisu lub odczytu wartości linii portu. Kolejnymi funkcjami są funkcje dotyczące obsługi analogowych linii portów mikrokontrolera. Składają się one z funkcji analogReference(), analogRead() i analogWrite() odpowiednio: ustalających napięcie odniesienia dla przetwornika A/C, funkcji odczytu zmierzonej wartości analogowej i zapisu wartości analogowej (sygnał PWM). Funkcje należące do grupy zaawansowanych służą odpowiednio do generowania tonu audio na dowolnej linii portu mikrokontrolera, generowania strumienia bitów oraz odczytu długości impulsu na linii mikrokontrolera. Prawdopodobnie często będą wykorzystywane funkcje służące do odmierzania czasu. Umożliwiają one wstawienie w programie opóźnień oraz wykonywanie
98
pomiaru czasu. Arduino IDE ma również funkcje matematyczne, trygonometryczne czy funkcje generatorów pseudolosowych. Z mikrokontrolerami związane są nieodzownie operacje na bajtach oraz bitach. Dlatego też Arduino udostępnia funkcje związane z bitami i bajtami. Umożliwiają one zapis bajtów, ich odczyt oraz ustawianie/kasowanie i odczyt dowolnych bitów zmiennych. Są to bardzo pomocne funkcje przydatne w operowania na portach mikrokontrolera. Kolejne funkcje są przeznaczone do obsługi przerwań. Umożliwiają one przerwanie pracy programu głównego i wykonanie bardziej priorytetowego zadania. Dostępne są funkcje obsługi przerwań zewnętrznych zgłaszanych od linii portów mikrokontrolera oraz wewnętrznych przerwań zgłaszanych przez peryferia mikrokontrolera jak czasomierzy czy interfejsów komunikacyjnych. Ostania z dostępnych funkcji języka Arduino jest funkcją obsługi transmisji szeregowej zgodnej z RS232. Będzie ona bardzo pomocna podczas komunikacji mikrokontrolera np. z komputerem lub innym urządzeniem zgodnym i wyposażonym w interfejs RS232. Mogą to być np. moduły Bluetooth, GPS czy GSM. Dostępne funkcje języka Arduino jak i inne instrukcje pokazane w tab. 1 będą dokładniej opisane i pokazane z użyciu podczas praktycznych przykładów ich wykorzystania.
Biblioteki Oprócz dostępnych instrukcji języka Arduino dostępne są liczne biblioteki funkcji umożliwiających obsługę różnych układów dołączanych do mikrokontrolera. Część z nich wymieniono w tabeli 2. Są dostępne dwie grupy bibliotek – biblioteki dostępne z systemem Arduino czyli biblioteki standardowe oraz pozostałe niestandardowe utworzone przez innych użytkowników systemu Arduino. Wśród stan-
dardowych bibliotek dostępne są biblioteki funkcji obsługi pamięci EEPROM, komunikacji z komputerem, obsługi wyświetlaczy LCD, transmisji sieciowej ETHERNET, obsługi kart pamięci SD, silników krokowych, programowej wersji interfejsu RS232 czy obsługi interfejsów SPI i I2C/TWI, w które został wyposażony w mikrokontroler. Do niektórych bibliotek standardowych wymagane będą elementy sprzętowe, jak choćby wyświetlacz LCD czy kontroler Ethernet. Jak wspomniano, dostępne są również biblioteki niestandardowe, które można ściągnąć z Internetu. Biblioteki niestandardowe można podzielić na kilka grup. W grupie bibliotek komunikacyjnych można znaleźć biblioteki umożliwiające obsługę wiadomości tekstowych, obsługi interfejsu 1Wire, klawiatury z interfejsem PS2, obsługi telefonu komórkowego czy serwera www. Dostępne są również biblioteki umożliwiające komunikacje zestawów Arduino ze sobą. W grupie bibliotek obsługujących czujniki są dostępne biblioteki obsługujące czujniki pojemnościowe oraz przyciski w jakie jest wyposażona większość urządzeń. Dostępna jest również grupa bibliotek obsługujących wyświetlacze graficzne oraz wyświetlacze wielosegmentowe LED również z wykorzystaniem kontrolerów firmy MAXIM. Biblioteki w grupie generatory umożliwiają generowanie sygnału na dowolnym pinie mikrokontrolera lub z wykorzystaniem scalonych generatorów PWM. Dostępna jest również grupa bibliotek dotyczących czasu. Można w niej znaleźć bibliotekę obsługującą zegar oraz kalendarz – bardzo przydatna biblioteka, gdy będzie wymagany zegar i kalendarz i związana z tym np. rejestracja danych ze znacznikiem czasu rejestracji. Pozostałe biblioteki związane są z odmierzaniem czasu. Ostatnia grupa dostępnych bibliotek dotyczy bibliotek do obsługi tekstów czyli łańcuchów znaków przydatnych podczas wyświetlania tekstowych komunikatów na wyświetlaczu LCD lub wysyłanych do komputera. Jak widać dostępna jest pokaźna liczba bibliotek, która cały czas jest rozwijana. W Internecie można znaleźć wiele innych niestandardowych bibliotek dla Arduino umożliwiających obsługę wielu układów dołączanych do mikrokontrolera. Biblioteki niestandardowe zawsze w pierwszej kolejności należy zainstalować. Składają się one z jednego pliku z przedrostkiem .h oraz jednego .cpp. W ramach kursu będą dokładniej opisywane tylko biblioteki wyELEKTRONIKA PRAKTYCZNA 4/2011
Kurs Arduino – Język programowania czytu sygnałów z czujników. W mikrokontrolerach ATmega jest możliwość programowego włączenia void setup() //struktura inicjalizująca { rezystora podciągającego, który doSerial.begin(9600); pinMode(buttonPin, INPUT); myślnie na linii wejściowej będzie } ustalał stanu wysoki. Rozwiązanie void loop() //nieskończona pętla programu z rezystorem podciągającym jest { // ... bardzo często wykorzystywane pod} czas odczytu stanu z przycisków. Jego naciśniecie, na linii wejściowej ustawi stan niski a domyślnie po jego puszkorzystywane w przykładowych projektach czeniu będzie panował stan wysoki wymui związanymi z dołączanymi do zestawu Arszany przez rezystor podciągający. Cyfrowe duino UNO modułami AVTDUINO. linie mogą również być wyjściami na któProgram główny w Arduino rych stan może się zmieniać na niski lub wyNieodzownymi elementami programu soki co odpowiada napięciu 0 V i +5 V. Wysą zmienne w których przechowuje się dane dajność prądowa wyjść mikrokontrolerów oraz funkcje od których zależy działanie proATmega umożliwia zasilanie dołączonych gramu. Program główny systemu Arduino do nich diod LED. W przypadku większych składa się z dwóch nieodzownych struktur obciążeń wymagane są dodatkowe wzmacsetup() oraz loop(). Wygląd szkicu programu niacze chociażby w postaci tranzystorów. Do obsługi cyfrowych linii w Arduino dostępne w Arduino pokazano na listingu. 1. są trzy funkcje pinMode(), digitalWrite() i diW pierwszej kolejności są inicjowane gitalRead(). Za pomocą funkcji pinMode(pin, zmienne. Następnie w strukturze setup() inimode) jest możliwość skonfigurowania typu cjowane są tryby pracy linii mikrokontrolera, linii cyfrowej – czy ma być wejściem czy jego peryferia, linie portów mikrokontrolera wyjściem. Pierwszy parametr określa numer oraz funkcje zależne od wykorzystywanych pinu mikrokontrolera zgodnie z opisem linii bibliotek. Struktura ta jest wykonywana na płytce zestawu Arduino UNO. Drugi patylko raz podczas włączania zasilania lub rametr mode może posiadać stałe parametry zerowania mikrokontrolera. Po strukturze INPUT lub OUTPUT co wskazuje czy linia ma inicjującej wymagana jest struktura loop(), być wejściem, czy wyjściem. która tworzy niekończoną pętle w której wyInstrukcja: konywany jest program sterujący pracą CPU. pinMode(13, HIGH) oznacza że linia Działanie instrukcji w pętli będzie zależeć 13 mikrokontrolera będzie linią wyjściood użytkownika i napływających informacji z otoczenia mikrokontrolera. Oczywiście wą. Funkcja digitalWrite(pin, value) służy jest możliwe wychodzenie z nieskończonej do ustawiania stanu linii mikrokontrolera. pętli do obsługiwanych funkcji z biblioPierwszy parametr pin określa numer pinu, tek lub własnych. Dla większej czytelnonatomiast drugi parametr określa jaki ma być ści programu i jego opisu działania, można jej stan (niski czy wysoki – stałe parametry LOW lub HIGH). Instrukcja: digitalWrite(13, wprowadzać komentarze które powinny być LOW) ustawia na linii 13 stan niski czyli naoddzielone od instrukcji znakami „//”. Jest pięcie 0V. Instrukcja digitalWrite() umożliwia możliwe również wprowadzenie komentarównież załączenie rezystora podciągającerza w znakach otwierających komentarz „/*” go na linii będącej wejściem. Aby do linii oraz zamykających komentarz „*/”. Wszystko wejściowej dołączyć wewnętrzny rezystor pomiędzy tymi znakami jest przez język Arpodciągający należy z wykorzystaniem funkduino ignorowane. Komentowanie działania cji digitalWrite() wpisać do linii wejściowej programu jest dobrą praktyką gdyż po pewwartość HIGH co pokazano na poniższym nym czasie umożliwia to szybsze zapoznanie przykładzie: się z działaniem programu. Każdy przygotopinMode(12, LOW); //Konfiguracja linii 12 wany program będzie musiał być poddany jako wejściowa kompilacji a mikrokontroler zaprogramowadigitalWrite(12, HIGH); //Włączenie rezystony utworzonym plikiem z programem. ra podciągającego do linii 12 Obsługa cyfrowych linii Powyższe dwie instrukcje powodują że mikrokontrolera linia 12 będzie linią wejściową z włączoCyfrowe linie portów mikrokontrolerów nym rezystorem podciągającym. Instrukcja digitalRead(pin) służy do odczytu stanu linii mogą być skonfigurowane jako wejścia lub będącej wejściem. Parametr pin określa nuwyjścia. Dotyczy to również linii analogomer pinu mikrokontrolera który jest odczywych. W zestawie Arduino z mikrokontrotywany. Funkcja zwraca stan odczytywanego lerem ATmega domyślnie linie portów są stanu pinu zgodnie z przykładem: val = diskonfigurowane jako wejścia z wyłączonym gitalRead(12); rezystorem podciągającym. Czyli domyślnie Do zmiennej val zostanie zapisany stan są to wejścia prawie nie pobierające prądu 12 linii portu mikrokontrolera. Liczba doi bardzo często są wykorzystywane do odListing. 1. Szkic programy w Arduino int buttonPin = 3;
//inicjacja zmiennej
ELEKTRONIKA PRAKTYCZNA 4/2011
stępnych portów będzie zależeć od zastosowanego mikrokontrolera, choć jest również możliwość ich zwiększenia poprzez dołączenie do niego odpowiednich ekspanderów. Na płytce Arduino UNO dostępne są cyfrowe linie portów oznaczone numerami od 0 do 13. Dlatego tez dla ułatwienia właśnie tymi aliasami można się posługiwać podczas konfigurowania portów I/O.
Obsługa analogowych linii mikrokontrolera W Arduino dostępnych jest kilka linii analogowych z wykorzystaniem których można mierzyć analogowe sygnały np. z czujników (temperatury, ciśnienia) w przedziale napięcia od 0 V do +5 V i z rozdzielczością 10 bitów. 10-bitowa rozdzielczość oznacza, że mierzone napięcie od 0 V do 5 V będzie odczytywane wartościami od 0 do 1023. Dla 5 V daje to rozdzielczość (5 V/1024) 0,0049 V (4,9 mV). Zakres rozdzielczości przetwornika można zmienić za pomocą funkcji analogReference(). Pomiar wartości analogowej trwa około 100 mikrosekund. Analogowe linie mikrokontrolera oznaczone w Arduino UNO są jako A0 do A5 i mogą być wykorzystane również jako linie cyfrowe. Konfiguruje się je identycznie za pomocą funkcji pinMode(), digitalWrite() i digitalRead() z tym że parametr pin jest oznaczany za pomocą aliasów A0 do A5. Na przykład aby skonfigurować linie analogowa A0 jako wyjście wystarczy komenda pinMode (A0, OUTPUT);. Analogowe linie również posiadają cyfrowo załączane rezystory podciągające które można włączyć z wykorzystaniem funkcji digitalWrite(). Aby działało wejście analogowe mikrokontrolera musi ono być wcześniej ustawione jako wejście z wykorzystaniem funkcji pinMode(). Należy również wyłączyć rezystor podciągający. Do odczytu napięcia z linii analogowej mikrokontrolera służy funkcja analogRead(pin). Parametrem pin jest linia analogowa. Na przykład komenda val = analogRead(A2); //odczyt wartości sygnału z linii A2 powoduje odczyt wartości analogowej z linii A2 i zapis jej do zmiennej val. Dostępna jest również funkcja analogReference(type) za pomocą której można zmienić parametry pracy przetwornika analogowo-cyfrowego mikrokontrolera. Parametr type określa napięcie odniesienia dla przetwornika. Dostępne są następujące opcje: – DEFAULT: napięcie odniesienia dla przetwornika jest napięciem zasilającym mikrokontroler czyli 5 V lub 3,3 V. – INTERNAL: wbudowane napięcie odniesienia równie 1,1 V dla ATmega168, – INTERNAL1V1: wbudowane napięcie odniesienia równie 1,1 V dla Arduino Mega, -– INTERNAL2V56: wbudowane napięcie odniesienia równie 2,56 V dla Arduino Mega,
99
KURS – EXTERNAL: zewnętrzne napięcie odniesienia dołączone do linii AREF mieszczące się w przedziale od 0 V do 5 V. Możliwość zmiany napięcia odniesienia dla przetwornika A/C mikrokontrolera daje możliwość dostosowania się do wartości mierzonego sygnału analogowego z wymaganą rozdzielczością pomiaru.
Obsługa generatora PWM Sygnał PWM jest to sygnał prostokątny o modyfikowanym wypełnieniu. Z wykorzystaniem sygnału PWM i jego późniejszym uśrednieniu z wykorzystaniem prostego filtra składającego się z rezystora i kondensatora można uzyskać prosty przetwornik cyfrowo-analogowy na wyjściu którego wartość analogowa (napięcie) będzie zależne od wypełnienia generowanego sygnału PWM. Częstotliwość sygnału PWM w Arduino jest około 500 Hz. Do generowania sygnału PWM dostępna jest funkcja analogWrite-
(pin, value) gdzie pierwszym parametrem jest numer linii cyfrowej PWM a value wartością wypełnienia generowanego sygnału PWM w zakresie od 0 do 255. Wartość 255 daje stałe napięcie 5 V, wartość 127 da wypełnienie 50%, czyli napięcie wyjściowe po uśrednieniu 2,5 V, natomiast wartość 0 da wypełnienie 0% i napięcie 0 V. Z wykorzystaniem sygnału PWM można modyfikować np. jasność dołączonej diody LED czy prędkości silnika. Sygnał PWM dla mikrokontrolera ATmega168, który zamontowany jest w Arduino UNO może być generowany na pinach 3, 5, 6, 9, 10 i 11. Na przykład funkcja analogWrite(5, 127); //Sygnał PWM o wypełnienia 127 generuje sygnał PWM na pinie 5 o wypełnieniu 50 %. Nie trzeba również ustawiać linii PWM jako wyjścia przez wywołaniem funkcji analogWrite() ale dla czytelności programu zalecane jest ustawienie linii PWM jako wyjście z wykorzystaniem funkcji pinMode().
Tabela 1. Typy struktur, zmienne, funkcje języka Arduino Struktury setup() loop() Struktury kontrolne if if...else for switch case while do... while break continue return goto Składnia języka ; {} // /* */ #define #include Operacje arytmetyczne = (assignment operator) + (addition) - (subtraction) * (multiplication) / (division) % (modulo) Operatory porównania == (equal to) != (not equal to) < (less than) > (greater than) = (greater than or equal to) Operatory logiczne && (and) || (or) ! (not) Operacje na wskaźnikach * dereference operator & reference operator Operatory bitowe & (bitwise and) | (bitwise or) ^ (bitwise xor) ~ (bitwise not) > (bitshift right) Pozostałe operatory ++ (increment) -- (decrement) += (compound addition) -= (compound subtraction) *= (compound multiplication) /= (compound division) &= (compound bitwise and) |= (compound bitwise or) Zmienne Stałe HIGH | LOW INPUT | OUTPUT true | false integer constants floating point constants Typy zmiennych void boolean char unsigned char byte int unsigned int word long unsigned long float double string - char array String - object array Konwersje char() byte() int() word() long() float() Zmienne zakresowe variable scope static volatile const Narzędzia sizeof() Funkcje
Cyfrowe I/O pinMode() digitalWrite() digitalRead() Analogowe I/O analogReference() analogRead() analogWrite() - PWM Zaawansowane I/O tone() noTone() shiftOut() pulseIn() Czasu millis() micros() delay() delayMicroseconds() Matematyczne min() max() abs() constrain() map() pow() sqrt() Trygonometryczne sin() cos() tan() Losowe randomSeed() random() Bitów i Bajtów lowByte() highByte() bitRead() bitWrite() bitSet() bitClear() bit() Przerwania zewnętrzne attachInterrupt() detachInterrupt() interrupts() noInterrupts() Komunikacja Serial
Typy pamięci W mikrokontrolerach programowanych przez Arduino czyli ATmega istnieją trzy rodzaje pamięci: – pamięć FLASH (przestrzeń programu), przechowywany jest w niej program napisany w Arduino. Dane zapisane w tej pamięci nie są tracone po wyłączeniu zasilania, – pamięć SRAM (Static Random Access Memory), pamięć na zmienne czyli dane z obliczeń przeprowadzanych przez mikrokontroler. Dane w tej pamięci są tracone po wyłączeniu zasilania, – pamięć EEPROM jest pamięć do stałego przechowywania danych. Zapisane dane nie są wymazywane po wyłączeniu zasilania. Można jej używać do przechowywania długoterminowego informacji. Dla przykładu mikrokontroler ATmega168 ma następujące rodzaje pamięci: – FLASH – 16 kB (z czego 2 kB jest używane dla bootloadera), – SRAM – 1024 bajtów, – EEPROM – 512 bajtów. Ten mikrokontroler stosunkowo małą pamięć SRAM. Już zapisanie do niej przykładowego tekstu: char tekst[] = „Arduino – Elektronika Praktyczna”; zajmuje ponad 32 bajtów. To może nie wydawać się dużo, ale wystarczy kilka takich tekstów, aby zapełnić 1024 bajty pamięci. Zwłaszcza, gdy jest duża ilość tekstu do wysłania do wyświetlacza czy przez port RS232. Jest wiele sposobów na poradzenie sobie ze zbyt małą ilością pamięci. Część danych można zapisać w pamięci EEPROM. Można również ciągi tekstów przechowywać w pamięci Flash mikrokontrolera co można zrobić z wykorzystaniem funkcji PROGMEM: prog_char tekst[] PROGMEM = {„ Arduino – Elektronika Praktyczna „};. Wykorzystanie pamięci EEPROM – sposobu zapisu i odczytu danych zostanie pokazane w dalszej części kursu w przykładach praktycznych. Do obsługi pamięci EEPROM mikrokontrolera przewidziane są funkcje znajdujące się w dodatkowej bibliotece EEPROM.
Definiowanie zmiennych Zmienna jest zarezerwowanym miejscem do przechowywania danych. Składa się ona z nazwy, typu oraz wartości. Na przykład instrukcja Int PinLED = 13; tworzy zmienną nazwaną PinLED typu int i wartości początkowej 13, która może być używana do wskazywania pinu 13, do którego dołączono diodę LED. Za każdym odwołaniem się do nazwy PinLED będzie wskazywana wartość 13, która w tym przypadku jest numerem pinu portu mikrokontrolera. Zdefiniowana zmienną można szybko użyć w dowolnych funkcjach np. pinMode (PinLED, OUTPUT); Za pomocą tej funkcji linia PinLED o wartości 13 (13 linia mikrokontrolera) zostaje ELEKTRONIKA PRAKTYCZNA 4/2011
Kurs Arduino – Język programowania skonfigurowana jako wyjcie. Zaletą zmiennej w tym przypadku jest to, że wystarczy określić wartość pinu raz a używać wiele razy. Więc jeśli później zdecydujemy się na zmianę z pinu 13 na pin 12, wystarczy zmienić numer pinu w jednym miejscu w kodzie programu. Zmienna ma inne zalety w postaci możliwości przechowywania wartości liczbowej. Co najważniejsze, można zmienić wartości zmiennej za pomocą prostej komendy (wskazane przez znak równości). Na przykład komenda PinLED = 12; zmienia wartość zmiennej na wartość 12. Zauważyć można że nie jest już potrzebne określenie typu zmiennej. Wystarczy tylko raz wskazać jej typ. Oznacza to, że nazwa zmiennej jest na stałe związane z rodzajem, tylko jego wartość się zmienia. Przed przypisaniem wartości do zmiennej zawsze w pierwszej kolejności należy ją zdefiniować. W definiowaniu zmiennych ważna jest deklaracja odpowiedniego jej typu. W tabeli 3 wymieniono typy zmiennych oraz zakresy ich wartości. Ich zastosowanie będzie zależne od typu obliczeń jakie będą przeprowadzane w programie. Zmienne domyślnie są przechowywane w pamięci SRAM mikrokontrolera. Jak w języku C, zmienne mogą być inicjowane: Char znak; Int wartosc = 33; Pierwsza deklaracja deklaruje zmienną bez wartości początkowej, natomiast drugiej
zmiennej wartosc jest nadawana wartość początkowa 33. W zmiennych ważny jest również zakres jej działania. Zależy on od miejsca deklaracji zmiennej. Zmienne definiowane przed strukturami setup() oraz loop() będą zmiennymi globalnymi i ich zakres działania będzie w całym przygotowanym programie. Zmienne definiowane w funkcjach lub w strukturach setup() czy loop() będą działały tylko w nich: void setup () { Int PinLED = 13; pinMode (pin, OUTPUT); digitalWrite (pin, HIGH); } W tym przypadku wartość PinLED zmieniać się może tylko wewnątrz struktury setup(). Jeśli zmienna jest globalna, jej wartość można zmienić w dowolnym miejscu w kodzie programu, co oznacza, że trzeba zrozumieć cały program aby wiedzieć co się stanie. Jeśli zmienna ma ograniczony zakres, działanie programu jest łatwiej zrozumieć.
Tworzenie funkcji Funkcje czyli swego rodzaju procedury pozwalają programiście na dzielenie programu na moduły dzięki czemu jest bardziej zrozumiały oraz dane moduły (funkcje) mogą być wykonywane wielokrotnie bez po-
trzeby powtarzania kodu programu. Funkcje mogą wykonywać określone zadanie wielokrotnie np. funkcja opóźnienia która może być wykorzystana w programie wielokrotnie. Wywołanie funkcji powoduje wykonanie zawartego w niej programu i powrót po jego wykonaniu do programu głównego. Funkcje mogą posiadać parametry wejściowe jak np. w przypadku funkcji opóźnienia może to być czas opóźnienia. Mogą również one zwracać wynik obliczeń. Jak wspomniano zalety funkcji uwidaczniają się gdy trzeba coś w programie wielokrotnie powtórzyć. W programie bardzo często będą wykorzystywane funkcje czy to własne czy z wykorzystywanych bibliotek. Funkcja ma swoją nazwę oraz w nawiasie mogą się znajdować jej argumenty. Funkcje należy w pierwszej kolejności zdefiniować. W tym celu podaje się jej argumenty (identyczne jak typy zmiennych) oraz typ wartości zwracanej przez funkcje. W przypadku, gdy funkcja nie będzie zwracała żadnych wartości lub nie będzie miała żadnych wartości wejściowych wykorzystuje się do tego zaznaczenia słowo void: void Delay_100ms(void);. Funkcja ta będzie powodować opóźnienie programu o 100 ms. Niżej umieszczono przykładową funkcję do mnożenia dwóch liczb: Int Mnozenie(int x, int y){ Int wynik;
REKLAMA
ELEKTRONIKA PRAKTYCZNA 4/2011
101
KURS Wynik = x * y; Return wynik; } W powyższym przypadku deklarowana jest funkcja mnożenia o nazwie Mnozenie która ma dwa argumenty typu int. Funkcja zwraca wartość typu int (iloczyn). Rezultat działania funkcji jest zapisywany do zmiennej lokalnej wynik. Komenda return umożliwia zwrócenie wartości obliczeń przez funkcję. Użycie funkcji może być następujące: void loop{ int i = 2; int j = 3; int k; k = Mnozenie(i, j); // wynik mnożenia to 6 } W przykładzie zadeklarowano dwie zmienne i i j o wartość 2 i 3 oraz zmienną na k na ich iloczyn. Wywołanie funkcji mnożenie z parametrami i i j spowoduje wykonanie funkcji i wykonanie mnożenia dwóch wartości zapisanych do zmiennych i i j co da wynik 6 i jego zapis do zmiennej k. Dzięki przykładowej funkcji w każdej chwili w programie gdy będzie potrzebne mnożenie dwóch liczb wystarczy wywołać funkcje mnożenie podając jako jej parametry mnożone liczby.
Przykładowy program W ramach podsumowania części teoretycznej na listingu 2 pokazano prosty program powodujący pulsowanie diody LED. W strukturze setup() jest konfigurowana linia 13 mikrokontrolera jako wyjście. Do tego wyjścia dołączona jest dioda LED. W strukturze loop() wykonywane są w nieskończonej pętli instrukcje z których pierwsza powoduje ustawienie linii 13 w stan wysoki (wyłączenie diody LED). Kolejna funkcja delay z parametrom 1000 powoduje opóźnienie działania programu o 1 sekundę (1000 ms). Po opóźnieniu wykonywana jest instrukcja ustawiająca stan niski na linii 13 po czym następuje wykonanie kolejnej funkcji opóźnienia o 1 sekundę. Po tej instrukcji działanie programu rozpoczyna się od początku co powoduje miganie diody dołączonej do pinu 13 mikrokontrolera. Z praktycznym działaniem tego programu będzie się można zapoznać w kolejnej części kursu.
Podsumowanie W pierwszej części kursu Arduino opisano podstawowe funkcje i składnię języka Arduino. Są to informacje niezbędne do podjęcia programowania z tym systemie. W następnych częściach kursu zostanie pokazane środowisko programistyczne Arduino IDE wraz z instalacją zestawu Arduino UNO i jego uruchomieniem.
Marcin Wiązania
[email protected]
102
Tabela 2. Biblioteki w Arduino EEPROM Ethernet Firmata LiquidCrystal SD Servo SPI SoftwareSerial Stepper Wirebi Messenger NewSoftSerial OneWire PS2Keyboard Simple Message System SSerial2Mobile Webduino X10 XBee SerialControl Capacitive Sensing Debounce Improved LCD library GLCD LedControl LedDisplay Tone TLC5940 DateTime Metro MsTimer2 Tekstowe: TextString PString Streaming
Biblioteki standardowe odczyt zapis do pamięci EEPROM biblioteka funkcji sieciowych ETHERNET z wykorzystaniem modułu Arduino Ethernet Shield biblioteka komunikacji z komputerem z wykorzystaniem RS232 biblioteka obsługi wyświetlaczy LCD biblioteka obsługi kart pamięci SD biblioteka obsługi napędów servo biblioteka obsługi interfejsu SPI (Serial Peripheral Interface) biblioteka obsługi programowej interfejsu komunikacyjnego RS232 biblioteka obsługi silników krokowych biblioteka obsługi interfejsu TWI/I2C (Two Wire Interface) Biblioteki komunikacyjne: biblioteka do przetwarzania wiadomości tekstowych z komputera ulepszona biblioteka do obsługi programowej transmisji RS232 biblioteka obsługi interfejsu 1Wire biblioteka obsługi klawiatury z interfejsem PS2 biblioteka umożliwia wysyłanie wiadomości pomiędzy komputerem a Arduino umożliwia wysyłanie wiadomości tekstowych lub mail za pomocą telefonu komórkowego (za pomocą poleceń AT) biblioteka serwera WWW z wykorzystaniem Arduino Ethernet Shield biblioteka umożliwia transmisje po liniach zasilających umożliwia komunikacje z API XBee umożliwia zdalną kontrolę innych Arduino za pomocą interfejsu RS232 Biblioteki do obsługi czujników: biblioteka dla czujników pojemnościowych biblioteka do obsługi przycisków Obsługa wyświetlaczy i matryc LED: biblioteka obsługi wyświetlaczy LCD biblioteka obsługi graficznych LCD z kontrolerem KS0108 biblioteka sterująca 7-segmentowymi wyświetlaczami LED oraz LED’ami z kontrolerami MAX7221 lub MAX7219 biblioteka obsługi wyświetlaczy z kontrolerem HCMS-29xx Generatory: biblioteka umożliwia generowanie dźwięku na dowolnym pinie mikrokontrolera Umożliwia obsługę 16 kanałowego i 12 bitowego kontrolera PWM Data i godzina: biblioteka realizująca zegar i kalendarz biblioteka umożliwiające odmierzanie stałych odcinków czasu biblioteka generująca przerwanie co czas odmierzony w milisekundach biblioteka obsługi tekstów biblioteka zapisu tekstu do bufora uproszona biblioteka funkcji print()
Listing 2. Przykładowy program napisany dla Arduino void setup() { pinMode(13, OUTPUT); }
//konfiguracja linii 13 jako wyjście
void loop() { digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); delay(1000); }
// // // //
wyłączenie diody LED opóźnienie 1 sekundy włączenie diody LED opóźnienie 1 sekundy
Tabela 3. Zakresy typów zmiennych Typ boolean char unsigned char byte int unsigned int word long unsigned long float double string
Zakres True, False -128 do 127 0 do 255 0 do 255 -32768 do 32767 0 do 65,535 0 do 65535 -2147483648 do 2147483647 0 do 4294967295 3,4028235E+38 do -3,4028235E+38 (wartość 4-bajtowa) ciąg znaków ELEKTRONIKA PRAKTYCZNA 4/2011
KURS
Kurs Arduino (2)
Oprogramowanie Arduino IDE W EP 4/2011 rozpoczęliśmy kurs programowania Arduino. Omówiliśmy wtedy elementy języka. W tym artykule zajmiemy się Arduino IDE oraz utworzymy pierwszy program, który jeszcze nie będzie użyteczny, ale będzie takim arduinowym „Hello World”. Do programowania w systemie Arduino jest przeznaczone oprogramowanie Arduino IDE, które jest dostępne jest na stronach http://arduino.cc/en/Main/Software. Może ono pracować pod kontrolą systemów operacyjnych Windows, Linux oraz MAC OS X. Po zainstalowaniu oprogramowanie Arduino uruchamia się za pomocą skrótu lub przez dwukrotne kliknięcie na plik „Arduino. exe”. Wygląd głównego okna pokazano na rysunku 1. Okno programu można podzielić na kilka części. Dostępny jest górny pasek narzędzi, okno na przygotowywany program oraz obszar na dole, w którym będą wyświetlane komunikaty związane z działaniem programu Arduino IDE: o pracy kompilatora, o błędach i programowaniu mikrokontrolera. Pliki z przygotowanym programem dla mikrokontrolera są w Arduino zapisywane z rozszerzeniem .pde. Pasek narzędzi składa się z 7 przycisków. Dostępny jest jeden przycisk (ze strzałką w prawo) przy wyborze kartotek, którego użycie umożliwia dostęp do poleceń zarządzania kartotekami z plikami programu. Dostępne jest również menu podzielone na grupy File, Edit, Sketch, Tools oraz Help. Dodatkowe przyciski (pokazane na rysunku 2 i opisane w tabeli 1) umożliwiają szybki dostęp do najczęściej używanych poleceń (zapis pliku na dysku, programowanie itp.). Po wybraniu ikony Verify/Compile kompilator sprawdza składnię programu, a na-
Rysunek 2. stępnie jest on poddawany kompilacji. Po jej prawidłowym zakończeniu program jest gotowy do wysłania do mikrokontrolera. W przypadku nieprawidłowości w kodzie zostaną w dolnej części okienka systemu Arduino wyświetlone znalezione błędy. Ikona przycisku Stop zatrzymuje działanie Serial Monitor (monitor komunikacji szeregowej). Jest to pomocne, gdy przesyłane informacje przez interfejs szeregowy RS232 pojawiają się szybciej, niż można je zaobserwować. Przycisk New umożliwia utworzenie nowego, pustego pliku dla programu. Należy podać nazwę nowego pliku i jego lokalizację na dysku. Przycisk Open umożliwia otwarcie pliku z programem z dostępnej listy plików w wybranym katalogu. Przycisk Save umożliwia zapisanie przygotowanego programu do pliku o podanej nazwie i w wybranym ka-
Rysunek 3.
Rysunek 4. talogu. Przycisk Upload umożliwia przesłanie programu do mikrokontrolera a dokładnie do zestawu Arduino. Wcześniej należy przygotowany program poddać weryfikacji i kompilacji. Przed wysłaniem programu do mikrokontrolera należy skonfigurować typ zestawu Arduino oraz numer portu w komputerze, do którego jest dołączony zestaw Arduino. Przycisk Serial Monitor uruchamia okno monitora komunikacji (rysunek 3) przez interfejs RS232. W jego oknie pojawiają się informacje wysyłane przez interfejs RS232 mikrokontrolera (zestaw Arduino). Za jego pomocą jest również możliwość wysyłania danych do mikrokontrolera. W oknie monitora są dostępne opcje automatycznego przewijania otrzymanych znaków, możliwość wyboru prędkości transmisji czy opcji związanych ze znakami końca linii. Monitor będzie po-
Tabela 1. Pasek przycisków Verify/Compile Stop New Open Save Upload Rysunek 1.
106
Serial Monitor
Sprawdza i poddaje kompilacji napisany kod programu Zatrzymuje działanie monitora interfejsu RS232 Tworzy nową pustą zakładkę na programu Otwiera plik z programem Zapisuje plik z programem Umożliwia wysłanie programu do mikrokontrolera z wykorzystaniem szeregowego interfejsu RS232 Wyświetla okno monitora interfejsu RS232 ELEKTRONIKA PRAKTYCZNA 5/2011
Kurs Arduino
Oferta dla prenumeratorów Elektroniki Praktycznej Avtduino specjalnie z myślą o elektronikach-praktykach! Od numeru EP 04/2011 rozpoczęliśmy kurs programowania mikrokontrolerów AVR z użyciem bezpłatnego środowiska programistycznego Arduino. Kurs będzie się opierał na przykładach przygotowanych dla płytek rozszerzających do bazy (kompatybilnej z systemem modułów Arduino) wyposażonej m.in. w mikrokontroler ATmega, opisanej w EP1/2011 (odpowiednik Arduino Duemilanove, AVT-5272). Dla prenumeratorów Elektroniki Praktycznej przygotowaliśmy niespodziankę: wszystkim prenumeratorom papierowej wersji miesięcznika w grudniu 2011 zaoferujemy za darmo jedną, wybraną płytkę drukowaną modułu rozszerzenia dla zestawu Avtduino (zgodne z Arduino), dla których przykłady aplikacji przedstawimy w ramach kursu publikowanego na łamach czasopisma. Pierwsze artykuły kursowe o Arduino opublikowaliśmy w EP 4/2011 na stronach: 96 i 98. Opis pierwszego modułu rozszerzającego do płyty bazowej Avtduino opublikowaliśmy w Elektronice Praktycznej 4/2011 na stronie 47 (AVT-1615), kolejnego w bieżącym numerze na stronie 55 (AVT-1616).
Płytka bazowa systemu Avtduino będąca bazowym rozwiązaniem dla uczestników kursu
Rysunek 6.
Rysunek 5. mocny podczas sprawdzania pracy programu i wyszukiwania w nim błędów. Przycisk
Send umożliwia wysłanie danych do mikrokontrolera w zestawie Arduino. Działanie monitora transmisji szeregowej można zatrzymać przyciskiem Stop. Aby ponownie uruchomić monitor wystarczy przycisnąć przycisk Serial Monitor. Korzystanie z monitora szeregowej transmisji będzie pokazane podczas praktycznych przykładów odczytu
Rysunek 7. danych z czujników, gdy do zestawu nie będzie dołączony wyświetlacz. U góry okna Arduino IDE znajduje się menu składające się z przycisków File, Edit, Sketch, Tools oraz Help. W menu File, które pokazano na rysunku 4 umieszczono funk-
REKLAMA
ELEKTRONIKA PRAKTYCZNA 5/2011
107
KURS Listing 1. Program powodujący miganie diody LED
Rysunek 8.
void setup() { pinMode(13, OUTPUT); }
//konfiguracja linii 13 jako wyjście
void loop() { digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); delay(1000); }
// // // //
wyłączenie diody LED opóźnienie 1 sekundy włączenie diody LED opóźnienie 1 sekundy
Rysunek 12. Rysunek 9.
Rysunek 10. cje tworzenia nowego programu, jego zapisu oraz zamknięcia. W opcji Example znajdują się przykładowe programy dla Arduino. Można w nich znaleźć dużo przykładów podzielonych na grupy. Są to programy do obsługi silników, wyświetlaczy czy czujników. Dostępnych jest kilkadziesiąt przykładowych programów. Opcja Upload to I/O Board wysyła program do mikrokontrolera. Opcja Page Setup umożliwia ustawienie opcji
Rysunek 11.
108
strony, natomiast w opcji Preferences jest możliwość zmiany opcji konfiguracyjnych Arduino IDE. Oczywiście dostępna jest również opcja drukowania. W menu Edit pokazanym na rysunek 5 dostępne są opcje cofania zmian w programie, kopiowania, wklejania oraz wycinania. Są również opcje wstawiania komentarzy do programu, zaznaczania oraz opcje wyszukiwania Find i Find Next. W menu Sketch (rysunek 6) znajdują się ważne opcje związane z weryfikacją i kompilacją programu (Verify/Compile). Ponadto dostępna jest opcja Stop zatrzymująca monitor komunikacji szeregowej. Opcja Show Sketch Folder pokazuje folder z programem, natomiast opcja Import Library umożliwia import biblioteki z której będzie korzystał przygotowywany program (do programu wstawiany jest odnośnik do wybranej biblioteki). Program wyświetla biblioteki znajdujące się folderze libraries oprogramowania Arduino IDE. Domyślnie dostępnych jest kilkanaście bibliotek do których można również dołączyć biblioteki dostępne w Internecie. Opcja Add File umożliwia dodanie kolejnego pliku do przygotowywanego programu. W menu Tools pokazanym na rysunku 7 znajdują się narzędzia dzięki którym będzie możliwa komunikacja z zestawami Arduino. Opcja Auto Format umożliwia z formatowanie napisanego programu (wprowadza wcięcia sprawiające że program będzie bardziej czytelny). Opcja Archive Sketch umożliwia archiwizację przygotowanego oprogramowania do formatu ZIP. Dostępna jest również opcja Serial Monitor włączająca monitor komunikacji szeregowej. W opcji Board jest możliwość wyboru zestawu Arduino z którym będzie się komunikowało oprogramowanie Arduino IDE. Natomiast w opcji Serial Port wybiera się numer portu szeregowego z którym będzie odbywała się komunikacja z zestawem Arduino. W opcji
Rysunek 13. Burn Bootloader znajdują się obsługiwane przez Arduino programatory zewnętrzne za pomocą których jest możliwość przesłania do mikrokontrolera tak zwanego programu Bootloadera za pomocą którego będzie możliwe programowanie mikrokontrolera bez potrzeby wykorzystywania dodatkowego zewnętrznego programatora. W menu Help (rysunek 8) znajdują się opcje związane z odnośnikami do stron internetowych o Arduino, jego obsługi, sposobu programowania czy dostępnych instrukcji.
Podstawowe elementy zestawu Arduino IDE Odpowiednik zestawu Arduino UNO (Avtduino) z mikrokontrolerem ATmega168, który będzie używany podczas kursu, był opisywany w styczniowej Elektronice Praktycznej. Na rysunku 9 pokazano elementy płytki zestawu Arduino UNO. Zestaw ma gniazdo USB, za pomocą którego będzie się odbywać komunikacja komputera PC z mikrokontrolerem zestawu. Jest ona przeprowadzana z użyciem konwertera USB-RS232. Zestaw może być zasilany z interfejsu USB lub z wykorzystaniem zewnętrznego zasilania. W zestawie dostępne są linie DIGITAL (cyfrowe) mikrokontrolera oznaczone 0...13 przy czym linie 0 i 1 są liniami interfejsu RS232. Dostępna jest również linia AREF, do której można dołączyć zewnętrzne napięcie odniesienia dla przetwornika A/C mikrokontrolera. Do gniazda ANALOG IN (analogowe) dołączone zostały linie analogowe mikrokontrolera A0...A5, które również mogą pracować jako linie cyfrowe. Do gniazda Power ELEKTRONIKA PRAKTYCZNA 5/2011
Kurs Arduino doprowadzono linie masy, napięcia zasilające 5 V i 3,3 V oraz linię zerującą RESET. Dostępne jest również gniazdo ICSP, do którego można dołączyć zewnętrzny programator. Umożliwia on załadowania do pamięci mikrokontrolera programu Bootloadera lub zaprogramowania go dowolnym innym programem. Ponadto zestaw wyposażono w diodę sygnalizującą zasilanie, diody sygnalizujące transmisję z wykorzystaniem interfejsu RS232 oraz diodę „L” sygnalizującą stan linii 13 mikrokontrolera. Do dostępnych gniazd z liniami portów i zasilających będzie możliwość dołączania własnych lub dostępnych modułów Avtduino. Więcej informacji o zestawie Arduino UNO można znaleźć z Elektronice Praktycznej 01/2011.
Uruchomienie zestawu Zestaw może być zasilany z użyciem zewnętrznego zasilacza lub z interfejsu USB. Po połączeniu zestawu Arduino UNO z komputerem za pomocą przewodu USB należy w pierwszej kolejności zainstalować sterowniki USB wirtualnego portu COM. Sterowniki te znajdują się w pakiecie Arduino w katalogu Drivers. Po prawidłowym zainstalowaniu w menedżerze urządzeń powinny się pojawić dwa urządzenia zaznaczone na rysunku 10. W przykładzie został zainstalowany wirtualny port COM5, za pomocą któ-
rego będzie się odbywała komunikacja z zestawem Arduino UNO. Należy jeszcze odpowiednio skonfigurować oprogramowanie Arduino IDE. W menu Tools->Board należy wybrać zestaw pokazany na rysunku 11. Następnie ustawić numer portu, po którym będzie się odbywała komunikacja. Prawidłową konfigurację dla zainstalowanego portu (w tym przypadku port COM5) pokazano na rysunku 12. Po wykonaniu opisanych nastaw oprogramowanie Arduino IDE może się już komunikować z zestawem Arduino UNO, który został już wyposażony z odpowiedni Bootloader. Prawidłowa komunikacja będzie sygnalizowana za pomocą diod TX oraz RX. Aby przesłać do zestawu przygotowany program, po jego weryfikacji i kompilacji wystarczy przycisnąć przycisk Upload. Jeśli będą problemy z komunikacją może to być wina sprzętu lub nieprawidłowej konfiguracji portu komunikacyjnego. Zainstalowany numer portu powinien być zgodny z wybranym portem w oprogramowaniu Ardiuino IDE.
Przykładowy program Aby sprawdzić prawidłową współpracę oprogramowania Arduino IDE z zestawem Arduino UNO należy przepisać program z listingu 1. Powoduje on miganie diody „L” dołączonej do wyprowadzenia 13 mikrokon-
trolera. Dioda miga w jednosekundowych odstępach. Po przepisaniu przykładowego programu (rysunek 13) należy w pierwszej kolejności wykonać weryfikację oraz kompilację klikając na ikonie Verify/Complile. Po bezbłędnej kompilacji (gdy jest brak komunikatów o znalezionych błędach) program można przesłać do mikrokontrolera naciskając przycisk Upload. Po przesłaniu programu do mikrokontrolera powinna zacząć migać dioda oznaczona jako „L”. Można zmienić wartości opóźnień w instrukcji Delay i zobaczyć jak zacznie się zachowywać dioda LED L
Podsumowanie W ramach tej części kursu pokazano funkcje oprogramowania Arduino IDE oraz pokazano sposób konfigurowania i komunikację z zestawem Arduino UNO wraz z przykładowym programem testowym. W następnych częściach kursu będą przedstawiane przykłady obsługi różnych peryferiów mikrokontrolera i dołączonych do niego modułów wraz ze szczegółowym opisem ich działania. Przykłady będą pomocne podczas przygotowywania własnych programów, będzie je można szybko zmodyfikować i dostosować do własnych potrzeb.
Marcin Wiązania
[email protected]
REKLAMA
ELEKTRONIKA PRAKTYCZNA 5/2011
109
KURS
Kurs Arduino (3)
Obsługa modułu LCD W EP 4/2011 opublikowaliśmy opis modułu LCD z przyciskami (AVT1615) współpracującego z płytką Arduino oraz kompatybilną – AVTduino. W tym artykule pokażemy sposób obsługi programowej tego modułu oraz komponentów interfejsu użytkownika, które on zawiera: przycisków, potencjometru, generatora piezzo, diod LED oraz czujnika temperatury LM35. Zacznijmy od przykładów praktycznych rozwiązań, których będzie można użyć w samodzielnie opracowywanych aplikacjach. Na listingu 1 zamieszczono przykładowy program dla modułu AVT1615. Program ten wyświetla komunikat na wyświetlaczu LCD, mierzy napięcie na suwaku potencjometru, odczytuje temperaturę, wyświetla umowny numer naciśniętego przycisku oraz zaświeca umieszczoną koło niego diodę LED. Dodatkowo, naciśnięcie przycisku jest sygnalizowane dźwiękiem brzęczyka piezzo. W Arduino do obsługi modułów wyświetlaczy z kontrolerem HD44780 jest przeznaczona biblioteka LiquidCrystal (LCD) która umożliwia sterowanie modułem wyświetlacza za pomocą interfejsu z 4- lub 8-bitową szyną danych. W tabeli 1 zamieszczono komendy dostępne w tej bibliotece. Niektóre z komend wymienionych w tabeli 1 zastosowano w przykładowym programie z listingu 1. Jak można zauważyć, w programie w pierwszej kolejności dołączono bibliotekę obsługi LCD – LiquidCrystal.h. Następnie zadeklarowano stałe definiujące wyprowadzenia, do których dołączono diody LED, klawisze i brzęczyk piezzo. Dla lepszej czytelności programu nadano im łatwe do zapamiętania nazwy. Numery wyprowadzeń są zgodnie z opisem na płytkach Arduino Uno i Avtduino LCD. Dalej, za pomocą komendy LiquidCrystal(rs, enable, d4, d5, d6, d7) zgodnie ze schematem ideowym przypisano wyprowadzenia, do których został dołączony LCD. W dalszej części programu utworzono zmienne wykorzystywane do obliczenia wartości zmierzonego napięcia z suwaka potencjometru dołączonego do nóżki A0 oraz do obliczenia temperatury zmierzonej
86
przez termometr LM35 dołączony do nóżki A1. Dzięki 8-bajtowej tablicy byte st[8]={…} zdefiniowano symbol stopnia, który jest używany jako jednostka temperatury. W funkcji setup() za pomocą komendy lcd.begin(16, 2) zdefiniowano rozdzielczość zastosowanego wyświetlacza LCD. Pierwszy parametr określa liczbę znaków w wierszu (kolumn) a drugi liczbę wierszy. Jak łatwo domyślić się, w przykładzie zastosowano wyświetlacz 2×16 znaków. Do utworzenia znaku stopnia służy komenda lcd.create-
Dodatkowe materiały na CD/FTP: ftp://ep.com.pl, user: 10925, pass: 87thc181 • poprzednie części kursu
Char(0, st), której argumentami są numer znaku (kod) oraz bajty definicji (w naszym wypadku jest to tablica st[]). Komenda analogReference(DEFAULT) ustala napięcie odniesienia dla wewnętrznego przetwornika A/C mikrokontrolera na napięcie zasilające (w tym wypadku 5 V). Przetwornik mikrokontrolera będzie mierzył sygnały analogowe
Tabela 1. Komendy obsługi wyświetlacza LCD LiquidCrystal() begin() clear() home() setCursor() write() print() cursor() noCursor() blink() noBlink() display() noDisplay() scrollDisplayLeft() scrollDisplayRight() autoscroll() noAutoscroll() leftToRight() rightToLeft() createChar()
Definiuje piny do których został dołączony LCD Definiuje rozdzielczość zastosowanego LCD Czyści ekran LCD Ustawia kursor na początku ekranu LCD Ustawia kursor w zadanym miejscu LCD Zapisuje znak do LCD Zapisuje znak lub znaki do LCD Włącza kursor Wyłącza kursor Włącza miganie kursora Wyłącza miganie kursor Włącza ekran LCD Wyłącza ekran LCD Przesuwa zawartość LCD w lewo Przesuwa zawartość LCD w prawo Automatyczne przesuwanie zawartości na LCD Wyłączenie automatycznego przesuwania zawartości na LCD Ustawia kierunek zapisu tekstu od prawej do lewej Ustawia kierunek zapisu tekstu od lewej do prawej Umożliwia zdefiniowanie własnego znaku ELEKTRONIKA PRAKTYCZNA 6/2011
Kurs Arduino Listing 1. Przykładowy program dla modułu AVT11615 /* Przykład programu do obsługi modułu AVT1615 z: - wyświetlaczem LCD 2x16 znaków - 4 diodami LED - 4 przyciskami - brzęczykiem piezzo - czujnikiem temperatury LM35 */ #include
//biblioteka obsługi LCD
const const const const const const const const const
//przypisanie aliasów do pinów portów
int int int int int int int int int
Led1 = Led2 = Led3 = Led4 = SW1 = SW2 = SW3 = SW4 = Buzzer
13; 12; 11; 10; 3; 2; 1; 0; = A5;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); dołączony LCD int wart_pot; int wart_czuj; float wart_nap; float temperatura;
//konfigurowanie linii do których został
byte st[8] = { B00100, B01010, B00100, B00000, B00000, B00000, B00000, };
//zmienna na wartość zmierzona z potencjometru //zmienna na wartość zmierzonej z czujnika temperatury //zmienna na wartość zmierzonego napięcia //zmienna na wartość zmierzonej temperatury //tablica znaku stopnia dla wyświetlacza LCD
void setup() { //funkcja inicjalizacji lcd.begin(16, 2); //konfigurowanie rozdzielczości LCD lcd.createChar(0, st); //funkcja utworzenia własnego znaku z tablicy st o kodzie 0 analogReference(DEFAULT); //konfigurowanie napięcia odniesienia //dla przetwornika A/C - domyślnie 5V pinMode(Led1, OUTPUT); //konfigurowanie I/O, do których są //dołączone diody LED pinMode(Led2, OUTPUT); pinMode(Led3, OUTPUT); pinMode(Led4, OUTPUT); pinMode(Buzzer, OUTPUT); //konfigurowanie I/O, do której jest //dołączony brzęczyk piezzo pinMode(SW1, INPUT); //konfigurowanie I/O, do których są //dołączone przyciski pinMode(SW2, INPUT); pinMode(SW3, INPUT); pinMode(SW4, INPUT); digitalWrite(SW1, HIGH); //dołączenie wewnętrznych rezystorów //zasilających digitalWrite(SW2, HIGH); digitalWrite(SW3, HIGH); digitalWrite(SW4, HIGH); digitalWrite(Led1, HIGH); //wyłączenie diod LED digitalWrite(Led2, HIGH); digitalWrite(Led3, HIGH); digitalWrite(Led4, HIGH); digitalWrite(Buzzer, HIGH); //wyłączenie brzęczyka piezzo } void loop() { lcd.clear(); lcd.setCursor(4, 0);
//pętla główna programu //czyszczenie LCD //ustawienie kursora w 5 kolumnie //pierwszego wiersza lcd.print(„Arduino”); //wyświetlenie na LCD napisu Arduino //pomiar napięcia z potencjometru i dodanie wyniku do wart_pot for (int i = 0; i < 20; i++) { //pętla wykonywana 20 razy wart_pot = wart_pot + analogRead(A0); } //obliczenie średniej arytmetycznej z 20 pomiarów wart_pot = wart_pot / 20; //przeliczenie odczytanej wartości na napięcie wart_nap=(5.0*wart_pot)/1024.0; //ustawienie kursora w pierwszej pozycji drugiego wiersza LCD lcd.setCursor(0, 1); lcd.print(„U=”); //wyświetlenie napisu U= lcd.print(wart_nap); //wyświetlenie napięcia lcd.print(„V”); //wyświetlenie znaku V for (int i = 0; i < 20; i++) { //pętla wykonywana 20 //pomiar napięcia z czujnika temperatury i dodawanie wart_czuj wart_czuj = wart_czuj + analogRead(A1); } //obliczenie średniej arytmetycznej z 20 pomiarów wart_czuj = wart_czuj / 20; //przeliczenie wartości na stopnie Celsjusza temperatura=(5.0*wart_czuj*100)/1024.0; //ustawienie kursora na pozycji 9 drugiego wiersza LCD lcd.setCursor(9, 1); lcd.print(„T=”); //wyświetlenie napisu T= lcd.print((long)temperatura); //wyświetlenie wartości temperatury zaokrąglonej do pełnych stopni lcd.write(0); //wyświetlenie znaku stopnia
ELEKTRONIKA PRAKTYCZNA 6/2011
o napięciu od 0 V do 5 V z rozdzielczością 10-bitow. Komendy pinMode() definiują sposób pracy portów I/O mikrokontrolera. Linie, które sterują diodami LED oraz generatorem piezzo skonfigurowano jako wyjścia, a linie, do których dołączono przyciski jako wejścia. Za pomocą funkcji digitalWrite() dołączono rezystory zasilające pull-up, które polaryzują wejścia. Przyciśnięcie przycisku zmienia poziom dołączonego wejścia na niski. W funkcji loop() znajduje się program główny. W pierwszej kolejności za pomocą komendy lcd.clear() jest czyszczony ekran LCD. Następnie, za pomocą komendy lcd.setCursor(4, 0) kursor jest ustawiany w pierwszym wierszu i 5 kolumnie LCD (współrzędne numerowane są od 0). Komenda lcd. print(„Arduino”) wyświetla od ustawionej pozycji kursora komunikat Arduino. Jako parametr funkcji lcd.print() można użyć stałych w cudzysłowie lub zmiennych typu: char, byte, int, long, string. Funkcja ta ma również drugi opcjonalny parametr, który umożliwia formatowanie wyświetlanych liczb. Dozwolone są następujące ich formaty: DEC (dziesiętny), BIN (binarny), OCT (ósemkowy) i HEX (szesnastkowy). Następnie, w programie przykładowym za pomocą komendy analogRead(A0) jest odczytywane napięcie zmierzone przez przetwornik A/C na wejściu A0. Jak pamiętamy, jest to napięcie z suwaka potencjometru. Dla uniknięcia błędów pomiar jest wykonywany 20 razy w pętli FOR, jego wynik jest sumowany w zmiennej wart_ pot, a następnie jest obliczana średnia arytmetyczna z wyników pomiarów. Za pomocą wyrażenia wart_nap=(5.0*wart_pot)/1024.0 wartość obliczonej średniej jest zamieniana na napięcie. Stała „5.0” to napięcie odniesienia dla przetwornika, natomiast „1024” to jego rozdzielczość. Tak przeliczona wartość zmiennej zostaje wyświetlona w drugiej linii wyświetlacza LCD. Podobnie w dalszej części programu jest wykonywany pomiar temperatury za pomocą pomiaru napięcia na wyjściu czujnika LM35. Zmiana temperatury o 1ºC powoduje wzrost napięcia na wyjściu czujnika temperatury o 10 mV. Łatwo wywnioskować, że zmiana temperatury o 10ºC będzie odpowiadała zmianie napięcia wyjściowego czujnika o 100 mV. Temperatura jest odczytywana za pomocą funkcji analogRead(A1) mierzącej równoważne jej napięcie z czujnika LM35 na wejściu A1. Również w tym wypadku jest wykonywane 20 pomiarów, z których jest obliczana średnia arytmetyczna. Następnie za pomocą wyrażenia temperatura=(5.0*wart_ czuj*100)/1024.0 liczba odczytana z rejestru przetwornika A/C jest zamieniana na temperaturę. Wartość temperatury jest wyświetlana na wyświetlaczu w pozycji wskazywanej przez komendę lcd.setCursor(9, 1). Komenda lcd.write(0) powoduje wyświetlenie po wartości temperatury symbolu stopnia.
87
KURS W dalszej części programu umieszczono cztery bloki podobnych instrukcji obsługujących przyciski S1...S4 z diodami oraz brzęczyk piezzo. Ich działanie omówimy na przykładzie instrukcji odczytujących stan przycisku S1, ponieważ pozostałe działają w ten sam sposób. Za pomocą funkcji digitalRead(SW1) jest odczytywany stan wejścia, do którego dołączono przycisk S1. Następnie program sprawdza, czy odczytano poziom niski. Jeśli tak, to naciśnięto przycisk i zostają wykonane instrukcje zawarte w warunku IF. Jako pierwsza jest zaświecana dioda LED1 za pomocą komendy digitalWrite(Led1, LOW). Kolejna instrukcja – digitalWrite(Buzzer, LOW) – powoduje załączenie brzęczyka piezzo. Następnie jest czyszczony ekran LCD, pozycjonowany kursor oraz wyświetlany komunikat informujący o numerze wciśniętego przycisku. W pętli while(digitalRead(SW1) == LOW) następuje oczekiwanie na zwolnienie przycisku. Po jej zakończeniu są wykonane instrukcje digitalWrite(Led1, HIGH), digitalWrite(Buzzer, HIGH) wyłączające diodę LED oraz brzęczyk piezzo. Kolejne bloki programowe w taki sam sposób obsługują pozostałe przyciski i diody LED. Analogicznie, naciśnięcie przycisku S2 spowoduje zaświecenie się LED2, S3 zapali LED3 itd. Na ekranie LCD będą wyświetlane odpowiednie komunikaty, a naciśnięcie każdego przycisku będzie sygnalizowane przez brzęczyk piezzo. Program kończy się instrukcją delay(300), która powoduje zwłokę o czasie trwania 300 ms. Więcej informacji na temat komend obsługujących wyświetlacz LCD można znaleźć na stronach internetowych Arduino w informacjach dotyczących zastosowania biblioteki LiquidCrystal.
Podsumowanie Moduł LCD zapewne będzie jednym z najczęściej stosowanych we własnych aplikacjach. Uniwersalny, umożliwiający wyświetlanie liczb, komunikatów tekstowych, prostych ikon i pasków postępu na pewno będzie chętnie używany do różnych zadań.
Listing 1. c.d.
lcd.print(„C”);
//wyświetlenie znaku C
//sprawdzenie czy naciśnięto przycisk S1 if (digitalRead(SW1) == LOW) { digitalWrite(Led1, LOW); //zaświecenie LED1 digitalWrite(Buzzer, LOW); //włączenie brzęczyka lcd.clear(); //czyszczenie LCD //ustawienie kursora w pierwszym rzędzie i drugiej kolumnie lcd. setCursor(2, 0); lcd.print(„Przycisk S1”); //wyświetlenie nazwy przycisku //oczekiwanie na zwolnienie przycisku S1 while(digitalRead(SW1) == LOW); } else { //w przeciwnym razie digitalWrite(Led1, HIGH); //wyłączenie diody LED1 digitalWrite(Buzzer, HIGH); //wyłączenie brzęczyka } if (digitalRead(SW2) == LOW) { //sprawdzenie czy naciśnięto S2 digitalWrite(Led2, LOW); digitalWrite(Buzzer, LOW); lcd.clear(); lcd.setCursor(2, 0); lcd.print(„Przycisk S2”); while(digitalRead(SW2) == LOW); } else { digitalWrite(Led2, HIGH); digitalWrite(Buzzer, HIGH); } if (digitalRead(SW3) == LOW) { //sprawdzenie czy naciśnięto S3 digitalWrite(Led3, LOW); digitalWrite(Buzzer, LOW); lcd.clear(); lcd.setCursor(2, 0); lcd.print(„Przycisk S3”); while(digitalRead(SW3) == LOW); } else { digitalWrite(Led3, HIGH); digitalWrite(Buzzer, HIGH); } if (digitalRead(SW4) == LOW) { //sprawdzenie czy naciśnięto S4 digitalWrite(Led4, LOW); digitalWrite(Buzzer, LOW); lcd.clear(); lcd.setCursor(2, 0); lcd.print(„Przycisk S4”); while(digitalRead(SW4) == LOW); } else { digitalWrite(Led4, HIGH); digitalWrite(Buzzer, HIGH); } }
delay(300);
//opóźnienie o 300ms //koniec pętli głównej
Przyciski, w które jest wyposażony zestaw AVT1615 umożliwiają realizację interfejsu użytkownika umożliwiającego na przykład wprowadzanie nastaw. Niewątpliwym atutem są również diody LED i brzęczyk, których można użyć do sygnalizowania stanu budowanego przez siebie urządzenia, sygnalizowania alarmów itp. Mam nadzieję, że zaprezentowane przykłady obsługi wyjaśniają jak można użyć tych elementów we własnym projekcie.
W kolejnym odcinku kursu omówimy podobny moduł, jednak wyposażony w wyświetlacze LED. Umożliwia on na przykład zbudowanie miernika panelowego, zegara i innych urządzeń. Jednymi z najważniejszych cech Arduino są bowiem prostota użycia i niesamowita wręcz elastyczność platformy umożliwiająca różnorodne jej zastosowanie.
Marcin Wiązania
[email protected]
Oferta dla prenumeratorów Elektroniki Praktycznej Avtduino specjalnie z myślą o elektronikach-praktykach! Od numeru EP 04/2011 rozpoczęliśmy kurs programowania mikrokontrolerów AVR z użyciem bezpłatnego środowiska programistycznego Arduino. Kurs będzie się opierał na przykładach przygotowanych dla płytek rozszerzających do bazy (kompatybilnej z systemem modułów Arduino) wyposażonej m.in. w mikrokontroler ATmega, opisanej w EP1/2011 (odpowiednik Arduino Duemilanove, AVT-5272). Dla prenumeratorów Elektroniki Praktycznej przygotowaliśmy niespodziankę: wszystkim prenumeratorom papierowej wersji miesięcznika w grudniu 2011 zaoferujemy
88
za darmo jedną, wybraną płytkę drukowaną modułu rozszerzenia dla zestawu Avtduino (zgodne z Arduino), dla których przykłady aplikacji przedstawimy w ramach kursu publikowanego na łamach czasopisma. Pierwsze artykuły kursowe o Arduino opublikowaliśmy w EP 4/2011 na stronach: 96 i 98. Opis pierwszego modułu rozszerzającego do płyty bazowej Avtduino opublikowaliśmy w Elektronice Praktycznej 4/2011 na stronie 47 (AVT-1615), kolejnego w bieżącym numerze na stronie 55 (AVT-1616).
Płytka bazowa systemu Avtduino będąca bazowym rozwiązaniem dla uczestników kursu ELEKTRONIKA PRAKTYCZNA 6/2011
KURS
Kurs Arduino (4)
Obsługa modułu LED W „Elektronice Praktycznej” 5/2011 opisaliśmy moduł LED dla popularnego zestawu Arduino. W tym artykule pokażemy sposoby wyświetlania znaków oraz obsługi elementów, z których składa się ten moduł: dwóch przycisków, zegara RTC PCF8583, generatora piezo, czujnika temperatury DS18B20 oraz fotorezystorowego czujnika światła. Środowisko programistyczne Arduino zawiera gotowe funkcje obsługi zegara PCF8583 oraz termometru DS18B20, co po zaimplementowaniu obsługi wyświetlacza LED pozwala na szybkie, samodzielne zbudowanie funkcjonalnego zegara z termometrem lub obu tych przyrządów niezależnie. Na listingu 1 pokazano przykładowy program testowy dla modułu AVTduino LED. Po krótkiej demonstracji tj. wyświetleniu znaków „0”–„9” jest wyświetlany czas odczytany z zegara RTC i migocze kropka dziesiętna, sygnalizując w ten sposób pracę zegara. Po naciśnięciu przycisku S1 jest wyświetlana temperatura otoczenia zmierzona za pomocą czujnika DS18B20 z interfejsem 1-Wire. Po naciśnięciu przycisku S2 jest wyświetlana data odczytana z wewnętrznego kalendarza układu RTC. Po zaciemnieniu fotorezystora jest włączany generator piezo. Nie jest to być może użyteczna funkcja, ale służy ona jedynie do demonstracji sposobu odczytu napięcia z czujnika światła. Do obsługi programowej układów i komunikacji za pomocą I2C (zegar RTC) oraz 1-Wire (termometr) zastosowano funkcje dostępne w bibliotekach. Środowisko widzi je po skopiowaniu do podkatalogu Library oprogramowania Arduino IDE. Są to OneWire i PCF8583 (dostępne na stronie domowej Arduino oraz w materiałach dodatkowych). Do obsługi wyświetlacza modułu AVTduino LED brak gotowej biblioteki – tę należy wykonać samodzielnie lub wykorzystać opisane dalej rozwiązanie. Wyświetlacz jest multipleksowany. Jego obsługa odbywa się w przerwaniu generowanym przez Timer1 co 100 ms. Do generowania samych przerwań zastosowano bibliotekę Timerone (dostępna w materiałach dodatkowych). Na początku programu głównego instrukcja OneWire ustala linię komunikacyjną
90
Dodatkowe materiały na CD/FTP: ftp://ep.com.pl, user: 16732, pass: 630v2nfb
Listing 1. Przykład programu obsługującego moduł AVTduino LED #include #include #include #include
„TimerOne.h” //biblioteka obslugi timera //biblioteka i2c //biblioteka RTC //biblioteka 1Wire
OneWire ds(A3); // konfigurowanie 1Wire byte present = 0; byte data[12]; byte addr[8]; int wart_analog; int HighByte, LowByte, SignBit, temp, Fract, TReading, Tc_100; PCF8583 p (0xA0); //konfigurowanie RTC const int Buzzer = 13; //aliasy const int DP = 12; const int SW1 = A1; const int SW2 = A2; const int sens_sw = A0; int groundPins[8] = {0, 1, 2, 3, 4, 5, 6, 7}; //wiersze LED int digitPins[4] = { 8, 9, 10, 11}; //kolumny LED int wys=0; int digit[4]; //tablica znakow dla wyswietlacza LED int kr[4]; //tablica przechowujaca znak kropki byte temp_sec; byte wsk_sek=1; int number[13][7] = { //tablica znakow dla LED {0,0,0,0,0,0,1}, //zero {1,0,0,1,1,1,1}, //jeden {0,0,1,0,0,1,0}, //dwa {0,0,0,0,1,1,0}, //trzy {1,0,0,1,1,0,0}, //cztery {0,1,0,0,1,0,0}, //piec {0,1,0,0,0,0,0}, //szesc {0,0,0,1,1,1,1}, //siedem {0,0,0,0,0,0,0}, //osiem {0,0,0,0,1,0,0}, //dziewiec {1,1,1,1,1,1,1}, //wylaczenie LED {0,0,1,1,1,0,0}, //znak stopnia {0,1,1,0,0,0,1} //znak C }; void setup() //procedura konfigurujaca { Timer1.initialize(100); //inicjalizacja timera 1 Timer1.attachInterrupt(int_wys); //uruchomienie przerwania for(int i=0; i < 8; i++) //wyjscia obslugi wierszy LED { pinMode(groundPins[i], OUTPUT); digitalWrite(groundPins[i], HIGH); } pinMode(Buzzer, OUTPUT); //konfigurowanie linii piezo digitalWrite(Buzzer, HIGH); pinMode(DP, OUTPUT); //konfigurowanie dwukropka digitalWrite(DP, HIGH);
ELEKTRONIKA PRAKTYCZNA 7/2011
Kurs Arduino Listing 1. Przykład programu obsługującego moduł AVTduino LED for(int i=0; i < 4; i++) //konfigurowanie kolumn LED { pinMode(digitPins[i], OUTPUT); digitalWrite(digitPins[i], HIGH); } p.hour = 14; //inicjalizacja RTC p.minute = 30; p.second = 0; p.year = 2011; p.month = 4; p.day = 1; p.set_time(); pinMode(SW1, INPUT); //linie przyciskow pinMode(SW2, INPUT); digitalWrite(SW1, HIGH); //zalaczenie pull-up digitalWrite(SW2, HIGH); analogReference(DEFAULT); //nastawy A/C
} //funkcja przerwania, w ktorej jest obslugiwany LED void int_wys() { for(int i=0; i < 4; i++) { digitalWrite(digitPins[i], HIGH); //wylaczenie LED } for(int g=0; g < 7; g++) //LED=znak z digit { digitalWrite(groundPins[g], number[digit[wys]][g]); }; digitalWrite(groundPins[7], !(kr[wys])); //kropka digitalWrite(digitPins[wys], LOW); //wlaczenie wyswietlacza wys++; //zwiekszenie wartosci wys if (wys>4) wys=0; //jesli był obslugiwany 4 wyswietlacz //to przejscie do 1 }; void loop() //petla glowna programu { digitalWrite(DP, LOW); //wlaczenie LED kr[0]=HIGH; kr[1]=HIGH; kr[2]=HIGH; kr[3]=HIGH; for(int k=0; k < 10; k++) //wyswietlenie „0” do „9” { digit[0] = k; digit[1] = k; digit[2] = k; digit[3] = k; delay(200); //opoznienie 200ms }; digitalWrite(DP, HIGH); //wylaczenie LED kr[0]=LOW; kr[1]=LOW; kr[2]=LOW; kr[3]=LOW; digit[0] = 10; digit[1] = 10; digit[2] = 10; digit[3] = 10; delay(2000); while(1) //petla programu { p.get_time(); //odczyt RTC digit[3]= p.minute%10; //wyswietlenie minut digit[2] = p.minute / 10; digit[1]= p.hour%10; //wyswietlenie godzin digit[0] = p.hour / 10; if (temp_sec!=p.second) //miganie dwukropka 1s { temp_sec=p.second; //zapisanie wartosci sekund //wlaczenie lub wylaczenie dwukropka if (wsk_sek==1) digitalWrite(DP, HIGH); else digitalWrite(DP, LOW); wsk_sek = !wsk_sek; //zmiana stanu zmiennej } if (digitalRead(SW1) == LOW) { //Wcisniety S1? digit[0] = 10; //wylaczenie LED digit[1] = 10; digit[2] = 10; digit[3] = 10; digitalWrite(DP, HIGH); while(digitalRead(SW1) == LOW) { getTemp(); //odczyt temperatury digit[1]= temp%10; //wyswietlenie temperatury digit[0] = temp / 10; digit[2] = 11; //wyswietlenie ° digit[3] = 12; //wyswietlenie C delay(500); //opoznienie 500 ms } } if (digitalRead(SW2) == LOW) { //czy nacisniety S2? digit[0] = 10; //wylaczenie LED digit[1] = 10; digit[2] = 10; digit[3] = 10;
ELEKTRONIKA PRAKTYCZNA 7/2011
interfejsu 1-Wire, którą w tym przypadku jest linia A3. Instrukcja PCF8583 pcf(0xA0) z biblioteki PCF8583 umożliwia zapisanie adresu układu RTC, który ma wartość 0xA0. Tablica groundPins[8] zawiera linie wierszy wyświetlacza, natomiast tablica digitPins[4] linie kolumn wyświetlacza LED. Do tablicy digit[] będą zapisywane wartości wyświetlane na wyświetlaczu LED w taki sposób, że każdemu wyświetlaczowi odpowiada pojedynczy element tablicy digit[]. Tablica kr[] jest używana do obsługi kropek wybranego wyświetlacza LED. Zapis do tej tablicy wartości „1” powoduje zapalenie się kropki danego wyświetlacza, a „0” jej zgaszenie. W tablicy numer[] zapisano wyświetlane na LED znaki, czyli cyfry od „0” do „9”. Zapisanie liczby „10” powoduje wyłączenie wyświetlacza, „11” wyświetlenie znaku stopnia, natomiast „12” powoduje wyświetlenie litery „C”. Tablice znaków można dowolnie rozbudować o własne znaki. W procedurze setup instrukcja Timer1. initialize(100) konfiguruje Timer1 w taki sposób, aby zgłaszał przerwanie co 100 ms. Natomiast instrukcja Timer1.attachInterrupt(int_wys) konfiguruje nazwę wywoływanej procedury podczas przerwania. Co 100 ms będzie wykonywana procedura int_wys obsługująca wyświetlacz LED. Procedura obsługi przerwania w pierwszej kolejności wyłącza wyświetlacz na danej pozycji, wystawia na port mikrokontrolera wartość odczytaną z tablicy digit[], a następnie załącza ten wyświetlacz. Przy kolejnym wywołaniu przerwania jest obsługiwany kolejny wyświetlacz LED. W procedurze przerwania jest także włączana kropka wyświetlacza w zależności od wartości zapisanych w tablicy kr[]. Na pozycję aktualnie obsługiwanego wyświetlacza wskazuje zawartość zmiennej wys. Po obsłudze ostatniego jest ona zerowana i następuje obsługa pierwszego wyświetlacza. Obsługa wyświetlaczy LED jest wykonywana tak szybko, że dla obserwatora będzie widoczne jednoczesne świecenie wszystkich cyfr LED. Instrukcje p.hour = 14, p.minute = 30, p.second = 0, p.year = 2011, p.month = 4 oraz p.day = 1 ustawiają domyślne wartości czasu w układzie zegara RTC. Ich zapis do układu RTC powoduje instrukcja p.set_ time(), natomiast odczyt następuje z użyciem instrukcji p.get_time(). Opis komend obsługi zegara RTC można znaleźć w dokumentacji biblioteki PCF8583. W dalszej części procedury nastaw są konfigurowane te linie mikrokontrolera, do których dołączono przyciski. Są one ustalane jako wejściowe z włączonymi rezystorami podciągającymi. W pętli głównej programu loop jest włączany za pomocą instrukcji digitalWrite(DP, LOW) dwukropek DP dołączony do linii 12 systemu Arduino (wartość LOW
91
KURS włącza dwukropek, a HIGH wyłącza). Kolejne instrukcje włączają kropki wyświetlaczy. W tym przypadku wpisanie wartości HIGH włącza kropkę, a LOW ją wyłącza. W pętli FOR co 200 ms zapisywane są do wszystkich wyświetlaczy cyfry od „0” do „9” (wartość zmiennej k). Po zakończeniu się pętli FOR wyświetlacz jest wyłączany (wyłączane są kropki, znak DP oraz dzięki zapisaniu liczby 10 do tablicy digit[] wszystkie wyświetlacze) na 2 s. Następnie w nieskończonej pętli while za pomocą instrukcji p.get_ time() jest pobierana z układu RTC godzina oraz data, które są zapisywane do zmiennych p.hour, p.minute, p.second, p.year, p.month oraz p.day. Za pomocą instrukcji digit[3]= p.minute%10 oraz digit[2] = p.minute / 10 do dwóch ostatnich wyświetlaczy są zapisywane wartości minut (dziesiątki oraz jednostki), natomiast za pomocą instrukcji digit[1]= p.hour%10 oraz digit[0] = p.hour / 10 do dwóch pierwszych wyświetlaczy zapisywana jest godzina. W warunku if (temp_sec!=p. second) jest obsługiwany dwukropek wyświetlacza. Odczytana wartość sekund jest porównywana z poprzednią wartością zapisaną w zmiennej temp_sec. Jeśli jest różna, to jest zmieniany stan dwukropka. Zmiana jest uzależniona od stanu zmiennej wsk_sek, której wartość zmienia się co 1 s. Jeśli zmienna ma wartość „0”, to na „1”, jeśli „1”, to „0”. Tak sterowany dwukropek wyświetlacza będzie migał z częstotliwością 1 Hz. Za pomocą instrukcji if (digitalRead(SW1) == LOW) jest sprawdzany stan przycisku S1. Jeśli został on naciśniety (o czym świadczy poziom niski), wykonywane są instrukcje wyłączające wyświetlacz LED. Następnie instrukcja while(digitalRead(SW1) == LOW) sprawdza, czy nadal jest naciśniety przycisk S1. Jeśli tak, to jest wykonywana procedura getTemp(), w której następuje odczyt temperatury z czujnika DS18B20 (za pomocą funkcji dostępnych w bibliotece OneWire). Jako pierwsze procedura getTemp() wykonuje zerowanie magistrali 1-Wire za pomocą instrukcji ds.reset(). W dalszej kolejności, zgodnie ze specyfikacją układu DS18B20, są wykonywane instrukcje s.write(0xCC,1) oraz ds.write(0x44,1) inicjujące pomiar temperatury. Kompletna procedura odczytu temperatury wygląda następująco: ds.reset() ds.write(0xCC,1); ds.write(0xBE); for ( i = 0; i < 9; i++) { data[i] = ds.read(); }
92
Listing 1. Przykład programu obsługującego moduł AVTduino LED digitalWrite(DP, HIGH); while(digitalRead(SW2) == LOW) { digit[3]= p.day%10; digit[2] = p.day / 10; digit[1]= p.month%10; digit[0] = p.month / 10; kr[1]=HIGH; delay(500); } kr[1]=LOW;
//jesli S2 nacisniety //wyswietlenie dnia miesiaca //wyswietlenie miesiaca //wlaczenie kropki 2. LED //opoznienie 500 ms
} //wlaczenie lub wylaczenie buzzera if ((wart_analog = analogRead(A0))