Dużo wody upłynęło w Wiśle, odkąd napisałem na HR ostatni wpis. Najbliższe wpisy będą dedykowane początkującym robotykom/elektronikom, bo właśnie oni zadają najwięcej pytań za pośrednictwem mojego formularza. Zacznę od sprawy, która regularnie zapełnia mi skrzynkę mailową, czyli „kosmicznych” wręcz problemów początkujących z zaprogramowaniem pierwszego mikrokontrolera z rodziny AVR.
Tak, programowanie mikrokontrolerów po raz kolejny 🙂 Postaram się tym razem rozwiać wszelkie niejasności, w razie potrzeby uzupełnię później treść tego wpisu. Z góry zachęcam do nie wstydzenia się i zadawania pytań w komentarzach.
Jak to właściwie działa?
Cały proces programowania mikrokontrolera przedstawię podzielony na kilka kluczowych etapów.
Etap I
Piszemy program. Do wykorzystania mamy kilka języków, największą popularnością cieszą się język C, język Basic oraz język Assembler. Język Basic uznawany jest za najprostszy w opanowaniu i generalnie został stworzony z myślą o początkujących. Język C jest trudniejszy pod tym względem, że wymaga już pewnej znajomości działania mikrokontrolera, ale za to możemy z niego skorzystać do oprogramowania wielu różnych rodzin układów, nie tylko AVR. Bardzo ważne narzędzie, jeśli nie planujemy zakończyć przygody na AVR’ach. Assembler to język najbardziej zbliżony do maszynowego, a przez to najtrudniejszy w opanowaniu. Oczywiście, jest to tylko moja subiektywna opinia. Miałem do czynienia z każdym z tych języków i na „zielony” początek polecam Basic. Chodzi o to, żeby nie zniechęcić się zbyt dużą ilością wiedzy potrzebnej do przyswojenia na starcie.
Po wybraniu języka, przystępujemy do wybrania środowiska programistycznego. Jest to aplikacja, którą uruchamiamy na naszym komputerze, a która na ogół wyposażona jest w edytor tekstu kolorujący składnię (czyli zaznacza nam na kolorowo różne wyrazy kluczowe, podświetla nawiasy, żeby o żadnym nie zapomnieć, dba o wcięcia tekstu – generalnie chodzi o poprawienie czytelności pisanego kodu źródłowego oraz uniknięcie błędów) i kompilator. Zadaniem ostatniego jest „przetłumaczenie” programu z języka zrozumiałego dla człowieka na instrukcje zrozumiałe dla mikrokontrolera. Każdy mikrokontroler ma nieco inną budowę, inną architekturę, dlatego przed rozpoczęciem pisania programu zawsze musimy wybrać, jaki konkretnie układ chcemy zaprogramować, żeby kompilator od razu wiedział jak „wytłumaczyć” układowi, co każemy mu robić. Na chwilę obecną istnieje kilka popularnych środowisk programistycznych – zarówno dla systemu Windows, różnych dystrybucji Linux, jak i MacOS. Z Windowsowych rozwiązań polecam zwłaszcza dwa:
- Atmel Studio – następca AVR Studio, darmowy „kombajn” umożliwiający zaprogramowanie wszystkich układów z rodziny AVR, Xmega, a nawet 32-bitowych układów ARM firmy Atmel. Programuje się w nim w języku C lub Assembler. Do pobrania tutaj.
- BASCOM-AVR – częściowo darmowe środowisko, mam tu na myśli kilka ograniczeń darmowej wersji. Na początku ograniczenia te nie powinny jednak sprawiać kłopotu. Programuje się w języku Basic. Do pobrania tutaj (wersja Demo).
Po napisaniu programu, przystępujemy do kompilacji. Jest to na ogół ikonka opisana jako „Run” albo „Build” – niekiedy istnieje możliwość wgrania od razu skompilowanego kodu do mikrokontrolera, ale na ogół wymagane są do tego specjalne, droższe programatory. Dla przejrzystości opisu – pominę taką ewentualność.
Celem kompilacji jest nic innego, jak utworzenie pliku o rozszerzeniu .hex lub/i .bin. Ten plik to nasz „skarb” – to właśnie go będziemy wgrywać wprost do pamięci mikrokontrolera.
Etap II
Wybór programatora – sprawa prawdopodobnie najbardziej kosztowna. O programatorach napisałem już jakiś czas temu, ale na potrzeby tego artykułu, podsumuję moje obecne doświadczenia następująco: jeśli zaczynacie swoją przygodę z AVR, to nie marnujcie czasu na nieudane próby skonfigurowania całości. STK200 może i jest najtańszy, ale też sprawia problemy początkującym, jako że nie każdy ma port LPT, nie każda przejściówka USB-LPT zadziała, nie każdy umie taki port odpowiednio skonfigurować w BIOSie i nie każdy jest w stanie prawidłowo polutować sam programator i bezpiecznie podłączyć do niego mikrokontroler, przez co istnieje ryzyko uszkodzenia płyty głównej komputera. Moja propozycja to STK500v2, powszechnie dostępny np. na Allegro od 40zł z przesyłką. Jego zaletą w porównaniu do popularnego USBasp jest to, że od samego początku istnienia projektu, dobrze działał z 64-bitowymi systemami operacyjnymi Windows 7 – mamy gwarancję, że każda zakupiona wersja zadziała. Przeglądając oferty warto zwrócić uwagę na dwie rzeczy – zworkę HID, która sprawi, że programator zacznie działać niemal natychmiast po podłączeni do komputera oraz zabezpieczenie przeciwzwarciowe, czyli najzwyklejszy bezpiecznik (na ogół polimerowy). Po zakupie programatora należy z uwagą przeczytać załączoną instrukcję obsługi. Warto dowiedzieć się, w jaki sposób uruchomić go w trybie HID – najwięcej problemów początkujących wynika ze źle dobranych lub nieprawidłowo zainstalowanych sterowników. HID zrobi to za nas i do tego zrobi to dobrze.
Etap III
W tym momencie warto zadbać o prawidłowe podłączenie mikrokontrolera do programatora, a programatora do komputera PC. Wymagana jest (niestety) pewna podstawowa wiedza z zakresu elektroniki, przydatna może się okazać umiejętność lutowania. Zakładam, że dysponujecie już mikrokontrolerem, który może wyglądać np.tak:
… oraz programatorem, który może wyglądać np. tak:
Musimy te dwie rzeczy „jakoś” połączyć. W tym momencie warto zwrócić uwagę na złącza dostępne w naszym programatorze. Z jednej strony będzie to zapewne złącze USB – obojętnie, czy w formie gniazda mini-USB, przewodu zakończonego klasyczną wtyczką, czy też samą wtyczką wlutowaną w płytkę – tę stronę programatora podłączamy bezpośrednio do naszego komputera. Ale na razie się z tym wstrzymamy.
Istotniejsze jest to, co znajduje się „z drugiej strony”. Producenci wymyślili kilka standardów złącz służących do programowania mikrokontrolerów. W zależności od zakupionego sprzętu, będzie to najpewniej złącze składające się z dwóch wierszy zawierających po 5 pinów (łącznie 10, tzw. złącze KANDA) lub dwóch wierszy po 3 piny (czyli łącznie 6). W droższych programatorach, wyposażonych w interfejs JTAG pinów może być znacznie więcej, ale dla uproszenia pominę taką ewentualność. Na poniższym rysunku widać złącza, o których przed chwilą napisałem:
W Polsce zdecydowanie królują złącza z drugiego zdjęcia (10-pinowe), ale tutaj należy wspomnieć o jednej rzeczy. Niektóre sprzedawane np. na Allegro programatory posiadają dwa komplety takich złącz. Nie oznacza to, że możemy programować 2 mikrokontrolery równocześnie! Jedno z tych złącz służy do aktualizacji oprogramowania mikrokontrolera sterującego samym programatorem! Które? O tym przeczytacie w instrukcji.
Jakiego gniazda byście nie mieli w swoim programatorze, powinna być do niego dołączona specjalna taśma połaczeniowa – tzw. „taśma ISP”. Warto się o nią upomnieć u sprzedawcy, bo bez niej może być ciężko cokolwiek zdziałać. Na tym etapie warto zapamiętać/przerysować/wydrukować poniższy rysunek. Na pewno przyda się Wam wiele razy!
O co tutaj chodzi? Żeby to zrozumieć, musimy chwilowo przeskoczyć do nieco innego tematu.
Jak zapewne zauważyliście, mikrokontrolery mają wiele „nóżek”. Chociaż wyglądają one tak samo, wiele z nich może pełnić różne funckje, ale niektóre są wyjątkowe i bardzo specyficzne. Do unikalnych nóżek układów można zaliczyć m.in. pin RESET (w skrócie RST, RES), pin MISO, pin MOSI oraz pin SCK. Każdy AVR ma te piny nieco inaczej rozmieszczone, po szczegóły odsyłam do noty katalogowej mikrokontrolera (wpiszcie w google „nazwa_układu datasheet”, czyli np. „ATmega88 datasheet” i przewertujcie kilka pierwszych stron). Przykładowo, dla ATmega88 wygląda to następująco:
Na niebiesko zaznaczyłem wspomniane wcześniej porty. Dodatkowo, na czerwono, zaznaczyłem piny odpowiedzialne za zasilanie układu. GND, czyli tzw. masa (albo na ogół „minus” w bateriach), VCC (bywa zaznaczany na schematach jako VTG, czyli Voltage Target, czyli napięcie zasilania odbiornika, czasami po prostu od razu podaje się wartość tego napięcia, czyli np. „+5V” – jest to na ogół „plus” w bateriach i akumulatorach).
Wymienione piny są niezbędne do zaprogramowania układu. To właśnie je należy połączyć z naszym programatorem. W jaki sposób? Za pomocą złącza ISP! ISP, czyli In-System Programming. Dobrze by było, żeby przewody od programatora nie były przylutowane na stałe, tylko żeby istniała możliwość podłączania i odłączania programatora wedle naszego uznania. Dla naszej wygody powinniśmy wymyślić dedykowane złącze, w którym „specyficzne piny” będą zawsze rozmieszczone tak samo – w ten sposób jedna wtyczka programatora będzie pasować do wszystkich naszych układów. Dobry pomysł? Dobry 🙂 Sęk w tym, że producenci programatorów już dawno nas w tym pomyśle ubiegli i stworzyli własny standard. To właśnie rysunek, który radziłem Wam zapamiętać. Przywołajmy go raz jeszcze:
Wygląda znajomo? To właśnie rysunki złącz ISP pasujących do najpopularniejszych programatorów. Nowe oznaczenie „NC” w złączu po prawej to nic innego, jak „not connected”, czyli do tego pinu niczego nie podłączamy. Wyciągamy więc płytkę uniwersalną/płytkę prototypową albo lutujemy przewody bezpośrednio do pinów mikrokontrolera i do złącza (nawiasem mówiąc – typowe złącze o nazwie IDC-10 widoczne na rysunku poniżej, możemy dostać np. w sklepie TME; w ostateczności możemy też wykorzystać odcinek zwykłej, łatwodostępnej, dwurzędowej listwy tzw. goldpinów). Oto sposób, w jaki należy to wszystko „spiąć do kupy”:
Jedna uwaga – jest podłączenie dla programatora, który posiada opcję zasilania programowanego układu! Po raz kolejny opłaca się przeczytać dokładnie jego instrukcję obsługi, żeby wiedzieć w jaki sposób ewentualnie włączyć taką opcję. Jeśli nie nie chcemy/wiemy jak tego dokonać, to należy zaopatrzyć się w dodatkowe źródło zasilania (stabilne 5V) i podłączyć układ następująco:

Sposób połączenia programatora z programowanym mikrokontrolerem z uwzględnieniem zewnętrznego źródła zasilania
Zwróćcie uwagę, że wszystkie linie masy (GND) są wspólne dla całego układu! To bardzo ważne, sporo osób o tym zapomina. Ważne jest także połączenie wszystkich 4 pinów GND w złączu, bo niektóre programatory mogą mieć podpięty do masy tylko jeden z nich i może się zdarzyć, że będzie to pin „losowy”, akurat nie ten, który wybraliście. Takie błędy również się zdarzały w sprawdzanych przeze mnie układach.
Na rysunku powyżej nie uwzględniłem połączeń, które chcecie wykorzystać programując ów mikrokontroler – diod LED, przełączników itp. Pokazałem tylko sposób, w jaki należy podłączać programator. Jeśli podłączycie wszystko jak na rysunku i nie dodacie nic więcej, to owszem – zaprogramujecie Wasz układ. Sęk w tym, że po zaprogramowaniu będzie wykonywać swój program, ale nie będzie tego widać „na zewnątrz”. O podłączaniu „peryferiów” pewnie jeszcze kiedyś napiszę, na razie zakładam, że mieliście już do czynienia z elektroniką analogową i wiecie, jak np. podłączyć do takiego mikrokontrolera przykładową diodę LED. Wystarczy jej anodę podłączyć do portu mikrokontrolera (np. PB1), a katodę, przez szeregowy rezystor (np. 1000 Ohmów) do masy.
Nie pozostało nam nic, jak tylko podłączyć jeden koniec taśmy ISP do programatora, drugi do programowanego układu, a kabel USB do naszego komputera.
Etap IV
Nadszedł czas, by nareszcie zaprogramować nasz mikrokontroler. Mamy już wszystko podłączone, system Windows powinien automatycznie wykryć nasz programator (zakładam, że przełączyliście programator we wspominany przeze mnie wcześniej tryb HID). Mamy plik HEX (lub BIN) z naszym programem, mamy fizyczną infrastrukturę potrzebną do programowania. To, czego nam brakuje, to tzw. uploader, czyli aplikacja zajmująca się przesyłaniem pliku do mikrokontrolera, za pośrednictwem programatora. Do najpopularniejszej aplikacji tego typu należy avrdude. Być może nazwa ta obiła się już Wam o uszy. Avrdude jest aplikacją konsolową (wymaga wpisywania określonych komand z linii poleceń), a przez to momentami nieco niewygodną. Na szczęście ktoś rozwiązał ten problem za nas i utworzył tzw. nakładkę GUI, czyli po prostu dodał do avrdude „okienko” z polami wyboru i przyciskami. Tak naprawdę, tego typu nakładek jest mnóstwo. Z mojej strony mogę polecić stosowanie nakładki SinaProg 2. Program można pobrać z mojego „Chomika”:

Pobierz “SinaProg 2.0” SinaProg2.zip – Pobrano 7600 razy – 4,07 MB
Szczegółowo o tej aplikacji napisałem już w artykule „SinaProg, czyli prosty i darmowy „kombajn” do programowania AVR„, nie ma więc sensu się powtarzać. Chociaż artykuł traktuje o wersji 1.7.5, to wizualnie nie odbiega ona od wersji 2, po prostu została pozbawiona kilku denerwujących błędów. W skrócie: testujemy nasze połączenie z programatorem i programowanym układem. Wybieramy plik HEX lub BIN, który chcemy umieścić w pamięci układu. Klikamy „Program” w sekcji „Flash”. Czekamy chwilkę i… GOTOWE!. Nasz układ jest zaprogramowany. Prawda, że proste? Okej, może tak nie wyglądać (zwłaszcza biorąc pod uwagę obszerność tego artykułu), ale gdy poznacie ogólne zasady i kilka razy zaprogramujecie „procki” bazując na tym opisie, to wkrótce zaczniecie to robić sami, z pamięci. Po kilku powtórzeniach, programowanie stanie się dla Was bułką z masłem. Tego Wam serdecznie życzę. Powodzenia!
Na początku korzystałem z Atmel Studio. Ale teraz programuje w Eclipse. Do tego plugin i można kompilować bezpośrednio z programu. Program działa szybciej niż Atmel Studio, nie trzeba wgrywać dodatkowo podczas instalacji kilka innych programów. No i najważniejsze, pokazuje na bieżąco nasze błędy 😉
Pozdrawiam!
Dobrze wiedzieć, dzięki za info 🙂
Pozdrawiam
Super artykul