Skocz do zawartości
kermit

[Kurs] Programowanie mikrokontrolerów AVR w języku assembler - część 1

Pomocna odpowiedź

Lekcja1: wstęp i pierwszy programik

poniższy artykuł jak już się pewnie domyślacie będzie dotyczył programowania mikrokontrolerów z rodziny AVR w języku assembler, czyli języku niskiego poziomu( takim języku który kompilator tłumaczy bezpośrednio na kod bajtowy).Zdecydowałem sie go napisać ,ponieważ chciałbym udowodnić, że jest to język naprawdę ciekawy i użyteczny a zarazem prosty -możliwe, że niektórzy czytający w tym momencie czują się delikatnie zmieszani, ponieważ często moża wyczytać na różncyh forach, że assembler jest językiem nielogicznym czy niezrozumiałym. W tym kursie postaram się udowodnić, że te negatywne opinie nt. Assemblera są co najmniej nie prawdziwe i po poznaniu jego prostych podstaw docenimy jego zalety. No więc po tym krótkim wstępie jako że, pisanie długich wywodów za dobrze mi nie idzie to wypisze punkt po punkcie jakie moim zdaniem są zalety oraz wady assemblera.

Zalety:

-prosta składnia, właściwie jedyne co musimy zapamiętać to tzw. Mnemoniki, czyli 2, 3 lub 4 literowy kod, oznaczjący konkrteną instrukcje dla naszego procesora, niektórym może wydawać się to awykonalne, ale w rzeczywistości gdy uświadomimi sobie, że mnemoniki są skrótem jakiejś konkretnej instrukcji (np. JMP - jump, CP - compare ) to robi się zdecydowanie łatwiej.Ogólnie mówiąc mamy zdecydowanie mniej róznych dziwnych znaczków, które występują w innych językach, a które często jest trudniej zapamiętać niz mnemoniki.

-Teraz UWAGA ,bardzo ważna zaleta asemblera – ucząc się tego języka, tak naprawdę uczymy się nie tylko języka, ale też architektury samego mikrokotnrolera ,co w przyszłości może baaardzo nam sie przydać np. Przy programowaniu w innych językach czy nawet przy programowaniu innych mikrokontrolerów.

-Assembler jest świetną podstawą do programowania uC(mikrokontrolera/-ów) w językach wysokiego poziomu, które najpierw są tłumaczone, przez kompilator właśnie do assemblera , dzieki znajomości tego języka łatwiej nam będzie przesiąść się na języki wysokiego poziomu, oraz łatwiej będzie o optymalizację i wykrywanie błędów w takim kodzie (np. C)

-assembler daje naprawdę małą objętość kodu wynikowego, żeby zająć pamięć przynajmniej połowy np. Poczciwej atmegi32 muslielibyśmy się naprawdę okropnie namęczyć.

-daje nam bardzo dobrą kontrole nad pracą uC, przez co możemy w nim pisać programy które sterują jakimś bardzo czasowo krytycznym procesem.

Wypisałem te zalety które akurat przyszły mi do głowy, zapewne można by ich jeszcze trochę wypisać, ale ich odkrywanie pozostawie wam 🙂

No i dla równowagi wady a właściwie jedna, ale dosyć spora wada:

-pisanie bardziej skomplikowanych programów zajmuje zdecydowanie więcej czasu, niż w językach wysokopoziomowych

nastała pora, aby przejść dalej, a mianowicie w czym będziemy pisali :

-Do pisania programów w asm wybrałem dosyć juz leciwe, ale proste w obsłudze i przejrzyste AVR studio 4, ponieważ do pisania naszych programów nic bardziej skomplikowanego nie jest nam potrzebne, a następne wersje AVR studio mają całą mase niepotrzebnych bajerów które właśćiwie powoduja głównie spowolnienie komputera i zajmują kilkanaście razy więcej miejsca na dysku.

A co będzimy programowali?:

-programowali będziemy jeden z najpopularniejszych mikrokontrolerów z rodziny AVR, a mianowicie Atmege32 zamontowaną na klasycznej płytce stykowej, wybrałem takie rozwiązanie z tego względu, że w odróżnieniu od płytek rozwojowych jest ono dosyć tanie i jeśli ktos nie posaida jeszcze płytki stykowej to raczej nie powinienn mieć problemu z nabyciem takowej, a taka płytka przyda nam się napewno jeszcze wiele razy.

Czym programujemy:

-ja będe używał programatora AVR isp mkII, ale jeśli ktos posiada inny programator też nie powinienn mieć problemu.

Ok, to by było na tyle, pora wziąść się do roboty :

pierwszy układ który zmontujemy będzie chyba najprostszy z możliwych, czyli zasilanie, programator oraz dioda podłączona anodą do portu PC0, a katodą przez rezystor do minusa zasilania

Gdy już zmontujemy układ według powyższego schematu pora przystąpić do pisania programu, którego zadaniem będzie zapalenie naszej diody LED, myślę, że uruchomienie avr studio jest na tyle banalne i było już wielokrotnie opisywane co gdzie i jak, że mogę pominąć tą część.

Przystępujemy więc do pisania programu ,pierwsze co wpisujemy to 5 dyrektyw dla komilatora które będą występowały praktycznie w każdym pisanym przez nas programie asm:

.nolist
.include "m32def.inc"
.list

.cseg
.org 0

oznaczją one :

.nolist – informuje kompilator aby nie kompilował następujących po niej wierszy

.include "m32def.inc" – jest to plik który zawiera definicje nazw rejestrów ,co ułatwia bardzo pisanie programów, bo nie musimy odnosić się do fizycznych adresów rejestrów, tylko możemy używać ich nazw (czyli np. Zamiast pisać 0x14, możemy napisać DDRC)

.list –informuje kompilator, aby kompilował następujące po tej dyrektywie wiersze.

.cseg – czyli skrót od "code segment", informuje kompilator ,że będziemy pisali w segmencie programu.

.org 0 – nakazuje, aby program był umieszczony w pamięci począwszy od adresu zerowego.

No więc wiemy już co oznaczją dyrektywy teraz pora na program właśćiwy który będzie wyglądał tak:

wersja I:

.nolist
.include "m32def.inc"
.list

.cseg
.org 0


sbi DDRC, 0  		//ustawiamy pin 0 portu C jako wyjściowy
sbi PORTC, 0		//ustawiamy stan wysoki na pinie 0 portu C

najprostszy z możliwych programów, czyli ustawienie bitu w rejestrze I/O* DDRC(data direction register) oraz PORTC, pierwszą instrukcją ustawiamy PORTC 0 jako port wyjściowy ,drugą ustawiamy go w stan wysoki ,aby nasza dioda mogła się zapalić.Następne kroki to :

klikamy przycisk F7 na klawiaturze ,aby skomilować program->

wybieramy tools na górze okna programu->

w rozwiniętym okienku wybieramy "program avr"->

klikamy "connect->

w okienku które sie nam pojawi wybieramy nasz programator->

gdy połączymy się z programatorem,wyskoczy nam okno dialogowe w którym wchodzimy w zakładkę program->

w podpunkcie "flash" wybieramy ścieżke do naszego pliku z programem(rozszerzenie .hex) -> klikamy "program"

Co dokładnie oznaczają instrukcje, oraz jaka jest ich składnia?:

sbi – "set bit in I/O" -czyli ustaw bit w rejestrze "wejśćia/wyjścia"(którym ,czyli np. DDRC , PORTC,lub PINC ) ,"o numerze"(rejestry są ośmiobitowe ,więc wybieramy z przedziału 0-7, w zależności który pin danego portu chcemy ustawić)

przeciwieństwem instrukcji "sbi" jest instrukcja "cbi" która zeruje dany pin.

Asembler jest językiem w którym wielkość liter nie ma znaczenia, więc instrukcja sbi = SBI, tak samo jest z nazwami rejestrów ddrc = DDRC

Wersja II:

teraz pora na drugą wersje programu który rówież zapali naszą diodę LED:

.nolist
.include "m32def.inc"
.list

.cseg
.org 0


ldi R16,0b00000001
out DDRC, R16
out PORTC, R16

najpierw ładujemy stałą 0b00000001 do jednego z rejestrów ogólnego przeznaczenia* w tym wypadku R16 ,następnie zawartość rejestru R16 ładujemy do rejestrów I/O DDRC(tym sposobem w rejestrze DDRC bit nr0 został ustawiony, czyli linia ta została ustawiona jako wyjściowa), następnie tą samą stałą z rejestru R16 ładujemy do rejestru PORTC(sytuacja analogiczna jak z rejestrem DDRC ,tyle że tym razem ustawiamy bit w PORTC, co skutkuje ustawieniem stanu wysokiego na linii 0 portu C)

i tu jeszcze jedna sprawa, użyłem w tym wypadku zapisu binarnego stałej ładowanej do rejestru ,aby było widać dokładnie który bit ustawiamy, ale równie dobrze moglibyśmi użyć zapisu szesnastkowego, wyglądało by to tak:

.nolist
.include "m32def.inc"
.list

.cseg
.org 0
<code/>
ldi R16,0x01
out DDRC, R16
out PORTC, R16

lub mojego ulubionego zapisu, wg mnie najwygodzniejszego:

.nolist 
.include "m32def.inc" 
.list 

.cseg 
.org 0 

ldi R16, (1<<PINC0)
out DDRC, R16
out PORTC, R16

znaczenie poszczególnych instrukcji:

ldi – "load immediate" -[załaduj bezpośrednio] "do rejestru ogólnego przeznaczenia" , "stałą K"

out – "out port"- [załaduj] "do rejestru" "z rejestru"

*od dłuższego czasu używam już słowa rejestr(ogólnego przeznaczenia , wejścia/wyjśćia) i może niektórzy którzy dopiero zaczynją zabawę z mikrokontrolerami mogą nie wiedzieć czym są te rejestry otóż już wyjaśniam:

rejestry są to niewielkie komórki pamięci w przypadku rejestrów systemowych(np. Używane przez nas DDRC, PORTC itp.) słuzą one sterowania konkretnymi peryferiami naszego mikrokontrolera np. W przypadku rejestru DDRn ustawienie w nim bitów powoduje ustawienie linii danego portu jako wyjśćie, a zerowanie jako wejśćie .

Rejestry ogólnego przeznaczenia(od R16 do R31) są do użytku programisty, można w nich przechowywać, zmienne lub stałe które wykorzystywane będą w programie.

Ze względu ,że nasze mikrokontrolery AVR są 8-bitowe to też wszystkie rejestry w nich są również 8-bitowe co oznacza, że największą wartość dziesiętną jaką możemy zaladować do pojedyńczego rejestru to 255.

komentarze:

wpisać komentarz w języki assembler możemy na 3 soposoby:

";" - znak średnika pozwala nam na napisanie komentarza do końca wiersz

"//" -a analogicznie jak w przypadku średnika

"/*"możemy pisać komentarz aż do odwołania znakiem "*/" .

Zakończenie:

Ok więc na tym zakończymy pierwszą część kursu, jeśli się on spodoba opublikuje następne jego części .Prosze pisać co można by jeszcze poprawić, dopisać itp.

__________

Komentarz dodany przez: Treker

Proszę poprawić interpunkcję. Spacje stawiamy po, a nie przed znakiem interpunkcyjnym.

asm.jpg.e8268782d1f7fa7ff2948b07260996d5.jpg

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites
wziąść
teraz pora na drugą wersje programu który będzie który rówież zapali diodę naszą diodę LED
Ze względu ,że mikrokontrolery nasze mikrokontrolery AVR są 8-bitowe
ldi R20,0x01

out DDRC, R16

out PORTC, R16

Nie bardzo rozumiem ten fragment. Wrzucamy do rejestru R20 jakąś wartość i co z nią? Potem odwołujemy się do R16. Jak to się ma do R20?

Udostępnij ten post


Link to post
Share on other sites

Już poprawione przepraszam za te błędy, wkradły się one do artykułu z powodu zmęczenia. 😉

Udostępnij ten post


Link to post
Share on other sites
-Teraz UWAGA ,bardzo ważna zaleta asemblera – ucząc się tego języka, tak naprawdę uczymy się nie tylko języka, ale też architektury samego mikrokotnrolera ,co w przyszłości może baaardzo nam sie przydać np. Przy programowaniu w innych językach czy nawet przy programowaniu innych mikrokontrolerów.

Od której należałoby zacząć. Bez przedstawienia architektury danego procesora, nauka ASMa mija się z celem. Same rzucenie paroma przykładami i troszką instrukcji to za mało. ASM wbrew pozorom nie jest taż taki prosty, dla tego powstały języki wysokiego poziomu, O ile zapamiętanie samych instrukcji nie jest jakim niesamowitym wyzwaniem, to wykonywanie operacji złożonych już tak, szczególnie obliczeniowo.

No i trzymaj się jakiś zasad pisania. Jak już przyjołeś że stałą do rejestru ładujesz takim sposobem:

LDI R16, 0b00000001

to potem nie rób tak

LDI R16, 0x01 bez wyjaśnienia tych zapisów, bo początkujący się załamią po pierwszych 2 listingach.

Ogólnie wziąłeś sobie na tapetę, bardzo, ale to bardzo trudny do zrobienia dobrze temat.

Udostępnij ten post


Link to post
Share on other sites
i tu jeszcze jedna sprawa, użyłem w tym wypadku zapisu binarnego stałej ładowanej do rejestru ,aby było widać dokładnie który bit ustawiamy, ale równie dobrze moglibyśmi użyć zapisu szesnastkowego, wyglądało by to tak:

Więc chyba wszystko wyjaśnione? 😉

kermit, poprawisz w końcu te R20? ; D

Udostępnij ten post


Link to post
Share on other sites

Witam. Mam pytanie dlaczego używa się rejestrów od r16 wzwyż a nie od r0?

Pozdrawiam.

Udostępnij ten post


Link to post
Share on other sites

wojakin,

Rejestry ogólnego przeznaczenia(od R16 do R31) są do użytku programisty, można w nich przechowywać, zmienne lub stałe które wykorzystywane będą w programie.

Udostępnij ten post


Link to post
Share on other sites

wn2001, R0 do R15 też, tylko że z tego co dobrze pamiętam niektóre instrukcje m.in. LDI są możliwe tylko na R16-R31

Udostępnij ten post


Link to post
Share on other sites

Harnas, a to przepraszam. Moja wiedza na temat ASM jest znikoma, myślałem jedynie, że mój poprzednik przeoczył ten fragment artykułu, stąd cytat 🙂

Udostępnij ten post


Link to post
Share on other sites

Dziękuję za informacje 🙂. Pozdrawiam.

Edit: Mam jeszcze pytanie przekazuje do funkcji SPIInt napisanej w asm wartość 8-bitową jako argument z pliku napisanego w c. Z tego co rozumiem adres tej wartości powinien wylądować w rejestrze X ale tak się nie dzieje. Co robię źle?

#include <avr/io.h>
extern void init (void);
extern void SPIInt (uint8_t edata);

int main (void)
{
       init();
       SPIInt(0xAB);
       while(1){

       }
       return 0;
}
#define __SFR_OFFSET 0
#include <avr/io.h>

.global init
.global SPIInt

init:
sbi DDRD, 0

; Set SPI out pin
ldi r16,(1<<PB4)|(1<<PB5)|(1<<PB7)
out DDRB,r16

; Enable SPI, enable SPI Interrupt, set Master Mode and set clock rate fck/16
ldi r16,(1<<SPIE)|(1<<SPE)|(1<<MSTR)|(1<<SPR0)
out SPCR,r16
ret

SPIInt:
ld r17,x
cpi r17,0xAB
breq on
reti

on:
sbi PORTD,0
reti

Edit 2: Znalazłem że kompilator wartość podaną jako argument wkłada do rejestru r24. Dla argumentów zawsze ten rejestr obowiązuje?

Udostępnij ten post


Link to post
Share on other sites

Witam

Jak  wyglądał by ten kod  C w j.ASM 

 kwarc 16 MHz ,Attiny 2313A

--------------------------------------------------------------------------------------

#include <avr/io.h>
#include <util/delay.h>
main()
{
DDRB = (1<<PB3)|(1<<PB4);
PORTB|=(1<<PB3);
while(1)
{
PORTB ^= (1<<PB3)|(1<<PB4);
_delay_us(128000000);
  }   
}  

 

Udostępnij ten post


Link to post
Share on other sites

@Anek40 witam na forum 🙂 Na czym dokładnie utknąłeś, próbowałeś zdziałać coś samodzielnie w tej kwestii?

PS Kody programów należy umieszczać za pomocą odpowiedniego narzędzia dostępnego w edytorze (przycisk "Wstaw kod"). Programy są wtedy prezentowane w czytelny sposób, a ich składania jest kolorowana. Tym razem poprawiłem to za Ciebie, ale pamiętaj o tej opcji w przyszłości. Z góry dziękuję za zrozumienie i pomoc w utrzymaniu porządku 😉

Udostępnij ten post


Link to post
Share on other sites

Jak w ASM napisać to:

PORTB ^= (1<<PB3)|(1<<PB4);

_delay_us(128000000);

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...