Wikipedysta:Silmethule/Programowanie AVR z avr-gcc

Z Wikibooks, biblioteki wolnych podręczników.

Próba przetłumaczenia niemieckiego AVR-GCC-Tutorial opublikowanego na licencji CC-BY-SA przy pomocy szczątkowej znajomości języka niemieckiego i Google Translate.

Wymagana wiedza[edytuj]

Od czytelnika wymagana jest znajomość podstaw programowania w języku C. Można się tego nauczyć ze źródeł online, np. z kursu programowania w języku C na polskich Wikibooks. Żadne wcześniejsze doświadczenia z programowaniem mikrokontrolerów nie są wymagane, czy to w asemblerze, czy w jakimkolwiek innym języku.

Przedmowa[edytuj]

Kurs ten ma na celu wprowadzić czytelnika do programowania mikrokontrolerów w:AVR firmy Atmel w języku programowania C przy pomocy darmowego kompilatora avr-gcc, będącego częścią GNU Compiler Collection.

Tekst ten będzie często odwoływałs ię do standardowej biblioteki avr-libc, do której dostarczona jest dokumentacja online, a w niej znaleźć można dużo przydatnych informacji na temat kompilatora i programowania kontrolerów AVR (do pakietu WinAVR jest dołączona i standardowo instalowana dokumentacja biblioteki avr-libc).

Kompilator oraz biblioteka avr-libc są ciągle rozwijane. Część różnic, jakie pojawiły się w trakcie rozwoju avr-gcc w kolejnych wersjach zostało wyjaśnionych w głównym tekście oraz dodatkach, początkujący powinni jednak zainstalować najnowszą dostępną wersję (w przypadku MS-Windows: aktualną wersję pakietów WinAVR; w przypadku Linuksa: najnowszą wersję avr-gcc dostępną poprzez menadżera pakietów).

Kurs ten oryginalnie został napisany przez Christiana Schifferlego, wiele nowych sekcji i uaktualnień napisał Martin Thomas.

Wersję niemiecką kursu w formacie PDF można znaleźć tutaj (może nie być aktualna):

AVR-GCC-Tutorial.pdf

Rozdziały zaawansowane [TODO][edytuj]

Aby ten ogromny kurs uczynić wygodniejszym w czytaniu i edycji, część zagadnień niedotycząca bezpośrednio programowania za pomocą avr-gcc została wydzielona do innych artykułów [a tutaj prawdopodobnie cały kurs zostanie podzielony na pojedyncze artykuły pod koniec tłumaczenia, kwestie zaawansowane zostaną przetłumaczone na samym końcu, jeśli w ogóle], wszystkie te artykuły należą do kategorii avr-gcc Tutorial.

→ UART
→ Wejścia i wyjścia analogowe (ADC)
→ Timer i licznik AVR-ów
→ Sterowanie LCD
→ Watchdog
→ O Makefile’ach
→ Dostosowywanie starych kodów źródłowych
→ Asembler i wstawki asemblerowe (inline assembler)

Co robic, gdy coś nie działa?[edytuj]

  • Sprawdź, czy problem dotyczy konkretnie avr(-gcc), czy może wystarczy przypomnienie sobie pewnych wiadomości na temat języka C. Zogólnymi problemami z C można sobie poradzić za pomocą znajomego z biura, pokoju, czy mieszkania obok. W innym przypadku należy się poradzić jakiejś książki do nauki języka C (lub materiałów dostępnych online).
  • (ang.) Przeczytaj dokumentację avr-gcc, przede wszystkim (choć najlepiej nie tylko) sekcję Related Pages/Frequently Asked Questions = Często zadawane pytania (i odpowiedzi do nich). Aktualnie dostępne jedynie po angielsku.
  • (niem.) Przeczytaj artykuł AVR-GCC na Wiki mikrocontroller.net.
  • (ang.) Poszukaj opisu podobnych problemów na forum AVRfreaks.
  • Poszukaj przykładowych kodów źródłowych. Szczególnie w dziale Projects na AVRfreaks (dla zarejestrowanych).
  • Nigdy nie zaboli też poszukanie w Google’u bądź Yahoo.
  • W przypadku problemów z obsługą wnętrzności AVR-ów: przeczytaj kartę katalogową (datasheet) kontrolera (i zdecydowanie najlepiej zrób to dwukrotnie). Datasheety znajdziesz na stronach Atmela w postaci plików PDF. Korzystaj z pełnych kart katalogowych (complete) a nie streszczeń (summary).
  • (niem.) Mimo że przykładowe programy w artykule AVR-Tutorial są napisane w asemblerze AVR, objaśnienia do nich i użyte techniki programistyczne znajdują też zastosowanie w programach w C.
  • Napisz post na jednym z wymienionych forów lub wyślij maila na listę dyskusyjną. Podaj jak najwięcej informacji możesz: użyty kontroler, wersja kompilatora,użyte biblioteki, wyciąg z kodu źródłowego, lub lepiej projekt testowy[1] ze wszystkimi plikami potrzebnymi, by odtworzyć problem, również pełen komunikat błędu bądź dokładny opis niepożądanego zachowania. W przypadku peryferiów zewnętrznych opisz sposób ich połączenia lub naszkicuj schemat (np. za pomocą Andys ASCII Circuit (niem.) lub ASCII Flow (ang.). Zobacz również: „Jak mądrze zadawać pytania”.

Generowanie kodu maszynowego[edytuj]

Kompilator avr-gcc (z pomocą dodatkowych programów takich jak np. preprocesor, asembler i linker) produkuje z kodu źródłowego w C kod maszynowy dla kontrolera AVR. Zazwyczaj wygenerowany kod jest w formacie Intel HEX („plik hex”). Program programujący (np. AVRDUDE, PonyProg, czy AVRStudio/STK500-plugin) odczytuje ten plik i przesyła zawartą w nim informację (kod maszynowy) do pamięci mikrokontrolera. Z zasady „jedynie” kompilator avr-gcc (i kilka programów pomocnicznych) z odpowiednimi opacjami zostaje wywołany, by wygenerować „plik hex” ze źródła w języku C. Zasadniczo stosowane są dwa różne podejścia:

  • Wykorzystanie zintegrowanego środowiska programistycznego (IDE = Integrated Development Environment), ze wszystkimi ustawieniami dostępnymi np. w oknach dialogowych. Między innymi można użyć AVRStudio od wersji 4.12 (bezpłatne na atmel.com) łącznie z WinAVR jako zintegrowanym środowiskiem dla kompilatora (w tym wypadku trzeba mieć zainstalowane na komputerze AVRStudio i WinAVR). Inne IDE (nie wyczerpując tematu): Eclipse for C/C++ Developers (tj. z dołączonym CDT) i AVR-Eclipse Plugin (dla wielu platform, m. in. Linuksa i MS Windowsa, IDE i plugin darmowe), KontrollerLab (Linux/KDE, darmowe). AtmanAvr (MS Windows, relatywnie tanie), KamAVR (MS-Windows, darmowe, najwyraźniej już nierozwijane), VMLab (MS Windows, od wersji 3.12 również darmowe). Zintegrowane środowiska programistyczne bardzo się różnią w obsłudze między sobą i nie są dostępne na wszystkie platformy, na jakich można uruchomić kompilator (np. AVRStudio jest tylko dla MS-Windows). By dowiedzieć się w jaki sposób połączyć kompilator avr-gcc z IDE należy zajrzeć do dokumentacji danego środowiska.
  • Użycie programu make z odpowiednimi Makefile’ami. Poniższa sekcja opisuje generowanie kodu maszynowego dla AVR-ów (“pliku hex”) z kodu źródłowego C („pliku c”) oparte o program make i Makefile’e. Wiele z opisanych opcji można znaleźć również w konfiguracji pluginu avr-gcc dla AVRStudio (AVRStudio tworzy pojedynczy Makefile w każdym podkatalogu katalogu projektu).

Przy przejściu z Makefile’ów szablonu WinAVR do AVRStudio należy się upewnić, że AVRStudio (tj.: AVRStudio w wersji 4.13) przy tworzeniu nowego projektu nie włącza opcji optymalizacji (czyt. o narzędziu make w module C, zazwyczaj: -Os) i nie dołącza biblioteki matematycznej avr-libc (libm.a, opcja linkera -lm). (Uwaga: W wersji 4.16 obie one są domyślnie już ustawione). Obie są standardowe przy używaniu Makefile’ów z szablonu WinAVR i powinny być zatem ustawione na „manual” w konfiguracji pluginu avr-gcc z AVRStudio, by również AVRStudio generował odpowiednio zoptymalizowany kod.

Pierwszy przykład[edytuj]

Na początek zaprezentowany jest drobny przykład użycia kompilatora i programów pomocnicznych (tak zwanego toolchainu). Szczegółowe opisy pojawią się w dalszych częściach tego kursu.

Program powinien włączyć pewne wyjścia mikrokontrolera, a inne wyłączyć. Przykład jest zaprogramowany dla kontrolera ATmega16 (karta katalogowa), może być jednak łatwo zmodyfikowany do działania z dowolnym mikrokontrolerem rodziny AVR.

Krótkie słowo o sprzęcie: w tym programie wszystkie piny portu B (PORTB) są ustawiane jako wyjścia, część z nich jest ustawiona w stan wysoki (HIGH), gdy inne w niski (LOW). Ustawienie to w zależności od podłączonego do nich sprzętu może być krytyczne. Najbezpieczniejszą sytuacją jest, gdy do pinów nic nie jest podłączone, a działanie programu kontroluje się mierząc wyjściowe napięcie za pomocą multimetru. Napięcie należy mierzyć pomiędzy pinem GND a właściwym pinem należącym do portu B.

Na początku kod źródłowy aplikacji, znajdujący się w pliku tekstowym o nazwie main.c.

/* Wszystkie znaki pomiędzy ukośnikiem i gwiazdką 
   a gwiazdką i ukośnikiem są komentarzem */

// Komentarze do końca linii również są możliwe
// wszystkie znaki zaczynając na dwóch ukośnikach
// a kończąc na znaku końca linii są komentarzem

#include <avr/io.h>             // (1)

int main (void) {               // (2)

   DDRB  = 0xFF;                // (3)
   PORTB = 0x03;                // (4)

   while(1) {                   // (5)
     /* pętla nieskończona */   // (6)
   }                            // (7)

   /* nigdy się nie wykonana */
   return 0;                    // (8)
}
  1. W tej linii dołączany jest tak zwany plik nagłówkowy („plik h”, „header file”). W pliku avr/io.h zdefiniowane są nazwy rejestrów, używanych później. Również na Windowsie używa się / do zaznaczania podkatalogów w ścieżkach do plików nagłówkowych, a nie \.
  2. Tu zaczyna się właściwy program. Każdy program w języku C zaczyna się od pierwszych instrukcji w funkcji main.
  3. Styki AVR-a (piny) są połączone w bloki nazywane portami. W przypadku ATmegi16 wszystkie porty mają 8 wyprowadzeń, w przypadku mniejszych AVR-ów możliwe są porty krótsze niż 8-stykowe. Zgodnie z definicją (por. karta katalogowa) należy ustawić odpowiednio wszystkie bity w rejestrze kierunku danych (data direction register, DDR) odpowiadające pinom jako wyjście[2], instrukcja DDRB=0xff ustawia wszystkie bity portu B jako wyjście.
  4. Tutaj na pinach powiązanych z dwoma pierwszymi bitami portu (PB0 i PB1) pojawia się logiczne 1, na pozostałych pinach portu B (PB2-PB7) jest 0. Na aktywne wyjścia (logiczne 1 lub „high”) podane jest napięcie robocze (VCC, zazwyczaj 5 woltów), wyjścia nieaktywne operują na 0 woltach (GND, napięcie odniesienia). Dobrze jest od razu wspomnieć o innej możliwej notacji, wygodniejszej przy debugowaniu i bardziej przenośnej, często wykorzystywanej w innych tutorialach i ogólnie kodach źródłowych społeczności. Przypisanie wygląda następująco, więcej o tym w artykule Operacje bitowe modułu C:
    PORTB = (1<<PB1) | (1<<PB0);
    
  5. to początek pętli głównej (main-loop). Jest to nieskończona pętla, zawierająca powtarzające się ciągle instrukcje.
  6. W tym przykładzie pętla główna jest pusta. Kontroler przechodzi cały czas przez tę pętlę, nic poza tym się nie dzieje. Pętla główna jest potrzebna, ponieważ na kontrolerze nie ma żadnego systemu operacyjnego, który mógłby przejąć kontrolę po zakończeniu programu. Bez tej pętli, po zakończeniu, program z funkcji main powraca, wszystkie przerwania zostają wyłączone i powstaje w ten sposób inna nieskończona pętla.
  7. Koniec pętli głównej, powrót do otwierającego nawiasu klamrowego, czyli do 5.
  8. to zakończenie programu. Linia ta jest umieszczona jedynie ze względu na kompatybilność z językiem C[3]:
    int main(void)
    
    mówi nam, że funkcja zwraca wartość typu całkowitego (int). Instrukcja ta nigdy nie jest osiągana, ponieważ program nigdy nie opuszcza pętli głównej.

Um diesen Quellcode in ein lauffähiges Programm zu übersetzen, wird hier ein Makefile genutzt. Das verwendete Makefile findet sich auf der Seite Beispiel Makefile und basiert auf der Vorlage, die in WinAVR mitgeliefert wird und wurde bereits angepasst (Controllertyp ATmega16). Man kann das Makefile bearbeiten und an andere Controller anpassen oder sich mit dem Programm MFile menügesteuert ein Makefile "zusammenklicken". Das Makefile speichert man unter dem Namen Makefile (ohne Endung) im selben Verzeichnis, in dem auch die Datei main.c mit dem Programmcode abgelegt ist. Detailliertere Erklärungen zur Funktion von Makefiles finden sich im Artikel Exkurs: Makefiles.

D:\przyklad>dir

 Katalog: D:\przyklad

2006-11-28  22:53    <DIR>          .
2006-11-28  22:53    <DIR>          ..
2006-11-28  20:06               621 main.c
2006-11-28  20:03            16 810 Makefile
               2 plik(ów)         17 431 bajtów

Nun gibt man make all ein. Falls das mit WinAVR installierte Programmers Notepad genutzt wird, gibt es dazu einen Menüpunkt im Tools Menü. Sind alle Einstellungen korrekt, entsteht eine Datei main.hex, in welcher der Code für den AVR enthalten ist.

D:\przyklad>make all

-------- begin --------
avr-gcc (GCC) 3.4.6
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Compiling C: main.c
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -f
unsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef
 -Wa,-adhlns=obj/main.lst  -std=gnu99 -Wundef -MD -MP -MF .dep/main.o.d main.c -
o obj/main.o

Linking: main.elf
avr-gcc -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -funs
igned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -W
a,-adhlns=obj/main.o  -std=gnu99 -Wundef -MD -MP -MF .dep/main.elf.d obj/main.o
--output main.elf -Wl,-Map=main.map,--cref    -lm

Creating load file for Flash: main.hex
avr-objcopy -O ihex -R .eeprom main.elf main.hex

Der Inhalt der hex-Datei kann nun zum Controller übertragen werden. Dies kann z. B. über In-System-Programming (ISP) erfolgen, das im AVR-Tutorial: Equipment beschrieben ist. Makefiles nach der WinAVR/MFile-Vorlage sind für die Nutzung des Programms AVRDUDE vorbereitet. Wenn man den Typ und Anschluss des Programmiergerätes richtig eingestellt hat, kann mit make program die Übertragung mittels AVRDUDE gestartet werden. Jede andere Software, die hex-Dateien lesen und zu einem AVR übertragen kann[4], kann natürlich ebenfalls genutzt werden.

Startet man nun den Controller (Reset-Taster oder Stromzufuhr aus/an), werden vom Programm die Anschlüsse PB0 und PB1 auf 1 gesetzt. Man kann mit einem Messgerät nun an diesem Anschluss die Betriebsspannung messen oder eine LED leuchten lassen (Anode an den Pin, Vorwiderstand nicht vergessen). An den Anschlüssen PB2-PB7 misst man 0 Volt. Eine mit der Anode mit einem dieser Anschlüsse verbundene LED leuchtet nicht.

Przypisy

  1. Projekt zawierający funkcję powodującą błąd, program używający tej funkcji, powodując błąd i wszystkie inne elementy potrzebne do odtworzenia problemu, ale bez żadnych niepotrzebnych do tego celu funkcji, zmiennych, poleceń.
  2. Tzn. ustawić 1 dla każdego pinu wyjściowego, 0 oznacza wejście
  3. W rzeczywistości często linia ta jest zbędna. Standard języka C99 pozwala opuścić instrukcję return w funkcji main, jest ona wtedy automatycznie tworzona przez kompilator na samym końcu funkcji i zwraca wartość 0. Kompilatory GCC zachowują się tu zgodnie ze standardem
  4. z. B. Ponyprog, yapp, AVRStudio