Spisu treści:

Samouczek asemblera AVR 1: 5 kroków
Samouczek asemblera AVR 1: 5 kroków

Wideo: Samouczek asemblera AVR 1: 5 kroków

Wideo: Samouczek asemblera AVR 1: 5 kroków
Wideo: AVR Ассемблер. Урок 1. Вводный. AVR Assembler. Lesson 1. Promo. 2024, Listopad
Anonim
Samouczek asemblera AVR 1
Samouczek asemblera AVR 1

Zdecydowałem się napisać serię tutoriali jak pisać programy w języku asemblera dla Atmega328p, który jest mikrokontrolerem używanym w Arduino. Jeśli ludzie pozostaną zainteresowani, będę publikować jeden raz w tygodniu, aż zabraknie mi wolnego czasu lub ludzie przestaną je czytać.

Używam Arch linux i pracuję na atmega328p-pu ustawionym na płytce prototypowej. Możesz to zrobić tak samo jak ja lub możesz po prostu podłączyć arduino do komputera i w ten sposób pracować na mikrokontrolerze.

Będziemy pisać programy dla 328p, takie jak ten, który jest w większości arduino, ale należy pamiętać, że te same programy i techniki będą działać również dla dowolnego mikrokontrolera Atmel, a później (jeśli będzie zainteresowanie) będziemy pracować z niektórymi z inne też. Szczegóły dotyczące mikrokontrolera można znaleźć w kartach katalogowych Atmel i instrukcji zestawu instrukcji. Dołączam je do tej instrukcji.

Oto, czego będziesz potrzebować:

1. Deska do krojenia chleba

2. Arduino, czyli po prostu mikrokontroler

3. Komputer z systemem Linux

4. Asembler avra za pomocą git: git clone https://github.com/Ro5bert/avra.git lub jeśli używasz ubuntu lub systemu opartego na debianie, po prostu wpisz „sudo apt install avra”, a otrzymasz oba asemblery avr i awantura. JEDNAK, jeśli uzyskasz najnowszą wersję za pomocą github, otrzymasz również wszystkie niezbędne pliki dołączane, innymi słowy, ma już pliki m328Pdef.inc i tn85def.inc.

5. avrdude

Kompletny zestaw moich samouczków asemblera AVR można znaleźć tutaj:

Krok 1: Zbuduj tablicę testową

Zbuduj tablicę testową
Zbuduj tablicę testową

Możesz po prostu użyć swojego arduino i zrobić wszystko w tych samouczkach, jeśli chcesz. Jednakże, ponieważ mówimy o kodowaniu w języku asemblerowym, nasza filozofia z natury polega na usunięciu wszystkich peryferii i bezpośredniej interakcji z samym mikrokontrolerem. Więc nie sądzisz, że fajniej byłoby zrobić to w ten sposób?

Dla tych z was, którzy się z tym zgadzają, możesz wyciągnąć mikrokontroler z arduino, a następnie zacząć od skonstruowania "Breadboard Arduino", postępując zgodnie z instrukcjami tutaj:

Na zdjęciu pokazuję mój zestaw składający się z dwóch samodzielnych Atmega328p na dużej płytce prototypowej (chcę mieć możliwość utrzymania poprzedniego samouczka podłączonego i załadowanego na jednym mikrokontrolerze podczas pracy nad następnym). Zasilanie mam tak ustawione, że sama górna szyna ma 9V a wszystkie pozostałe 5V z regulatora napięcia. Do programowania układów używam również płytki zaciskowej FT232R. Kupiłem je i sam umieściłem na nich bootloadery, ale jeśli właśnie wyciągnąłeś jeden z Arduino, to już jest w porządku.

Zauważ, że jeśli próbujesz tego z ATtiny85, możesz po prostu pobrać programator Sparkfun Tiny tutaj: https://www.sparkfun.com/products/11801#, a następnie po prostu podłączyć go do portu USB w komputerze. Najpierw musisz zainstalować bootloader na Attiny85, a najprostszym sposobem jest użycie Arduino IDE. Musisz jednak kliknąć plik i preferencje, a następnie dodać ten adres URL nowych tablic: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json, który umożliwi Ci zainstalowanie bootloadera (jeśli twój ATtiny85 jeszcze go nie posiadał).

Krok 2: Zainstaluj asembler i Avrdude

Możesz teraz pobrać i zainstalować asembler i avrdude z linków podanych w pierwszym kroku tego samouczka. Jest prawdopodobne, że jeśli już pracowałeś z Arduino, to masz już zainstalowany avrdude.

Po zainstalowaniu avra zauważysz, że istnieje podkatalog, który jest z nią związany o nazwie "źródła", a wewnątrz tego katalogu znajduje się kilka plików dołączanych. To są wszystkie mikrokontrolery, które można zaprogramować za pomocą avra. Od razu zauważysz, że nie ma pliku dla 328p, którego tutaj używamy. Załączyłem jeden. Plik powinien nazywać się m328Pdef.inc i należy go umieścić w katalogu include lub gdziekolwiek indziej. Będziemy włączać go do naszych programów asemblerowych. Wszystko to polega na nadaniu każdemu z rejestrów w mikrokontrolerze nazwy z karty katalogowej, abyśmy nie musieli używać ich nazw szesnastkowych. Powyższy plik include zawiera "dyrektywy pragma", ponieważ został zaprojektowany do programowania w C i C++. Jeśli znudzi Ci się patrzenie, jak asembler wypluwa „ignorowanie dyrektywy pragma”, po prostu wejdź do pliku i usuń lub skomentuj wszystkie wiersze zaczynające się od #pragma

Dobra, teraz, gdy masz gotowy mikrokontroler, gotowy asembler i programistę, możemy napisać nasz pierwszy program.

Uwaga: Jeśli używasz ATtiny85 zamiast ATmega328P, potrzebujesz innego pliku dołączanego o nazwie tn85def.inc. Dołączę go również (zauważ, że musiałem nazwać go tn85def.inc.txt, aby Instructables pozwolił mi go przesłać.) JEDNAK, jeśli masz asembler avra z github, to już masz z nim oba te pliki. Dlatego polecam go pobrać i skompilować samodzielnie: klon git

Krok 3: Witaj świecie

Celem tego pierwszego samouczka jest zbudowanie standardowego pierwszego programu napisanego podczas nauki nowego języka lub odkrywania nowej platformy elektronicznej. "Witaj świecie!." W naszym przypadku chcemy po prostu napisać program w asemblerze, zaasemblować go i wgrać do naszego mikrokontrolera. Program spowoduje włączenie diody LED. Spowodowanie "migania" diody LED, tak jak w normalnym programie Hello World w Arduino, jest w rzeczywistości znacznie bardziej skomplikowanym programem w języku asemblerowym, więc jeszcze tego nie zrobimy. Zamierzamy napisać najprostszy kod "nagich kości" z minimalnym niepotrzebnym puchem.

Najpierw podłącz diodę LED z PB5 (patrz schemat pinów), która jest również nazywana Digital Out 13 na arduino, do rezystora 220 omów, a następnie do GND. Tj.

PB5 -- LED -- R (220 omów) -- GND

Teraz napiszemy program. Otwórz swój ulubiony edytor tekstu i utwórz plik o nazwie „hello.asm”

;witaj.asm

; włącza diodę LED podłączoną do PB5 (wyjście cyfrowe 13).include "./m328Pdef.inc" ldi r16, 0b00100000 out DDRB, r16 out PortB, r16 Start: rjmp Start

Powyżej jest kod. Za chwilę przejdziemy przez to linijka po linijce, ale najpierw upewnijmy się, że możemy uruchomić ją na Twoim urządzeniu.

Po utworzeniu pliku, w terminalu montujesz go w następujący sposób:

avra cześć.asm

to zbierze twój kod i utworzy plik o nazwie hello.hex, który możemy przesłać w następujący sposób:

avrdude -p m328p -c stk500v1 -b 57600 -P /dev/ttyUSB0 -U flash:w:hello.hex

jeśli używasz arduino płytki prototypowej, będziesz musiał nacisnąć przycisk resetowania na arduino płytki prototypowej tuż przed wykonaniem powyższego polecenia. Zauważ, że być może będziesz musiał dodać sudo z przodu lub wykonać je jako root. Zauważ też, że w niektórych arduino (takich jak Arduino UNO) prawdopodobnie będziesz musiał zmienić bitrate na -b 115200 i port -P /dev/ttyACM0 (jeśli otrzymasz błąd od avrdude dotyczący nieprawidłowej sygnatury urządzenia, po prostu dodaj - F do polecenia)

Jeśli wszystko działało tak, jak powinno, teraz zapali się dioda LED….. „Hello World!”

Jeśli używasz ATtiny85, polecenie avrdude będzie wyglądało następująco:

avrdude -p attiny85 -c usbtiny -U flash:w:hello.hex

Krok 4: Hello.asm Linia po linii

Aby zakończyć ten samouczek wprowadzający, przejdziemy przez program hello.asm linia po linii, aby zobaczyć, jak to działa.

;witaj.asm

; włącza diodę LED podłączoną do PB5 (wyjście cyfrowe 13)

Wszystko po średniku jest ignorowane przez asembler i stąd te dwie pierwsze linijki to po prostu "komentarz" wyjaśniający, co robi program.

.zawiera "./m328Pdef.inc"

Ta linia mówi asemblerowi, aby dołączył pobrany plik m328Pdef.inc. Możesz umieścić to w katalogu podobnych plików dołączanych, a następnie zmienić powyższą linię, aby wskazywała tam.

ldi r16, 0b00100000

ldi jest skrótem od "load direct" i mówi asemblerowi, aby wziął rejestr roboczy, w tym przypadku r16, i załadował do niego liczbę binarną, w tym przypadku 0b00100000. 0b z przodu mówi, że nasza liczba jest binarna. Gdybyśmy chcieli, moglibyśmy wybrać inną bazę, na przykład szesnastkową. W takim przypadku nasza liczba wynosiłaby 0x20, co jest liczbą szesnastkową dla 0b00100000. Albo moglibyśmy użyć 32, co jest podstawą dziesiętną dla tej samej liczby.

Ćwiczenie 1: Spróbuj zmienić liczbę w wierszu powyżej na szesnastkową, a następnie dziesiętną w swoim kodzie i sprawdź, czy nadal działa w każdym przypadku.

Korzystanie z binarnych jest jednak najprostsze ze względu na sposób działania portów i rejestrów. Omówimy porty i rejestry atmega328p bardziej szczegółowo w przyszłych samouczkach, ale na razie powiem tylko, że używamy r16 jako naszego „rejestru roboczego”, co oznacza, że będziemy go używać jako zmiennej, którą przechowujemy liczby w. „Rejestr” to zestaw 8 bitów. Oznacza 8 miejsc, które mogą mieć wartość 0 lub 1 („wyłączone” lub „włączone”). Kiedy ładujemy liczbę binarną 0b001000000 do rejestru za pomocą powyższej linii, po prostu zapisaliśmy tę liczbę w rejestrze r16.

wyjście DDRB, r16

Ta linia mówi kompilatorowi, aby skopiował zawartość rejestru r16 do rejestru DDRB. DDRB to skrót od "Data Direction Register B" i ustawia "piny" na PortB. Na mapie pinoutów dla 328p widać, że jest 8 pinów oznaczonych PB0, PB1, …, PB7. Te piny reprezentują „bity” „PortB”, a kiedy ładujemy numer binarny 00100000 do rejestru DDRB, mówimy, że chcemy, aby PB0, PB1, PB2, PB3, PB4, PB6 i PB7 były ustawione jako piny INPUT, ponieważ mają 0 jest w nich, a PB5 jest ustawiony jako pin OUTPUT, ponieważ umieściliśmy 1 w tym miejscu.

wyjście Port B, r16

Teraz, gdy ustaliliśmy kierunki pinów, możemy teraz ustawić na nich napięcia. Powyższa linia kopiuje tę samą liczbę binarną z naszego rejestru pamięci r16 do PortB. To ustawia wszystkie piny na 0 woltów, z wyjątkiem pinu PB5 na HIGH, który wynosi 5 woltów.

Ćwiczenie 2: Weź multimetr cyfrowy, podłącz czarny przewód do masy (GND), a następnie przetestuj każdy z pinów PB0 do PB7 czerwonym przewodem. Czy napięcia na każdym z pinów są dokładnie takie, jakie odpowiadają włożeniu 0b001000000 w PortB? Jeśli są takie, które nie są, dlaczego myślisz, że tak jest? (patrz mapa pinów)

Początek:

rjmp Start

Wreszcie pierwszy wiersz powyżej to „etykieta”, która oznacza miejsce w kodzie. W tym przypadku oznaczanie tego miejsca jako „Start”. Druga linia mówi „względny skok do etykiety Start”. W rezultacie komputer zostaje umieszczony w nieskończonej pętli, która po prostu wraca do startu. Potrzebujemy tego, ponieważ nie możemy po prostu zakończyć programu lub spaść z klifu, program musi po prostu działać, aby światło nadal świeciło.

Ćwiczenie 3: Usuń powyższe dwie linie z kodu, aby program spadł z urwiska. Co się dzieje? Powinieneś zobaczyć coś, co wygląda jak tradycyjny program "mrugnięcia" używany przez Arduino jako ich "hello world!". Jak myślisz, dlaczego to działa w ten sposób? (Pomyśl o tym, co musi się stać, gdy program spadnie z klifu…)

Krok 5: Wniosek

Jeśli dotarłeś tak daleko, to gratulacje! Możesz teraz pisać kod asemblera, składać go i ładować na swój mikrokontroler.

W tym samouczku nauczyłeś się korzystać z następujących poleceń:

ldi hregister, number ładuje liczbę (0-255) do górnej połowy rejestru (16-31)

out ioreregister, register kopiuje numer z rejestru roboczego do rejestru I/O

rjmp label przeskakuje do wiersza programu oznaczonego etykietą (który nie może być dalej niż 204 instrukcje -- tj. względny skok)

Teraz, gdy te podstawy zostały usunięte, możemy nadal pisać ciekawszy kod i ciekawsze obwody i urządzenia bez konieczności omawiania mechaniki kompilacji i przesyłania.

Mam nadzieję, że podobał Ci się ten samouczek wprowadzający. W następnym samouczku dodamy kolejny komponent obwodu (przycisk) i rozszerzymy nasz kod o porty wejściowe i decyzje.

Zalecana: