Skocz do zawartości
Zaloguj się, aby obserwować  
kermit

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

Pomocna odpowiedź

Witam w drugiej częśći kursu programowania w języku assembler, w pierwszej części trochę was oszczędziłem, ale dziś bierzemy się ostro do roboty. W tej lekcji dowiemy się co to są etykiety, zajmiemy się opóznieniami, zaimpelementujemy do programu obsługę stosu oraz nauczymy sie obsługiwać przycisk(tzw. microswitch).

Ćwiczenie 1- przycisk i etykiety:

w poprzedniej części jedynie zapaliliśmy naszą diodę led podłączoną anodą(+) do linii PC0, dzisjaj wykonamy już bardziej ambitne zadanie i sprawimy, że nasza dioda zapali się dopiero po przyciśnięciu przycisku, a zgaśnie gdy przycisk zostanie zwolniony. Montujemy układ wg. Poniższego schematu:

Lewa strona układu, pozostała bez zmian względem schematu który widzieliśmy w pierwszej części kursu, natomiast po prawej stronie jak widzimy przybył nam jeden microswitch oraz kondensator o pojemności 100nF, po co nam ten kondensator? Otóż microswitche mają to do siebie, że po wciśnięciu przez kilkanaście/kilkadziesiąt milisekund występuje tzw. Efekt drgania styków, który objawia się tym, że zamiast czystego zwarcia, styki przycisku są zwieranie i rozwieranie, zjawisko takie może być bardzo nie pożądane, więc najlepiej za wczasu nauczyć się je eliminować .Jest jeszce druga tzw. Programowa metoda eliminacji drgania styków, ale o tym powiem póżniej.

Gdy zmontujemy nasz układ, uruchamiamy AVR studio, tworzymy nowy projekt i przystępujemy do pisania programu:

.nolist
.include "m32def.inc"
.list

.cseg
.org 0

cbi DDRA,0 	 // ustawiamy jako linie WEJŚĆIOWĄ pin do którego podlączony jest microswitch
sbi PORTA, 0 //podciągamy go przez wewnętrzny opornik do napięcia zasilania

sbi DDRC,0 //ustawiamy jako linie WYJŚCIOWĄ pin do którego podłączonona jest nasza dioda LED

main:
cbi PORTC, 0	//wyłącz diodę led
sbic PINA, 0	//jeśli bit nr0 w rejestrze PINA jest wyzerowany(przycisk wciśnięty) pomiń następną instrukcję
rjmp main		//jeśli bit jest ustawiony (przycisk zwolniony)instrukcja nie zostanie pominięta i nastąpi skok do main
rjmp LED_on		// jeśli bit jest wyzerowany skocz do funkcji która zapali diode 

LED_on:
sbi PORTC, 0	//ustaw bit nr0 w rejestrze PORTC (zapal diodę led)
sbic PINA,0		//jeśli bit nr0 w rejestrze PINA jest wyzerowany(przycisk zwarty do masy,czyli wscisniety),pomin nastepna instrukcje
rjmp main		//jesli przycisk został zwolniony(bit nr0 w rejestrze PINA jest ustawiony)zostanie wykonany skok do funckji main
rjmp LED_on		//jesli przycisk jest nadal wcisniety(bit nr0 w rejestrze PINA jest wyzerowany) to nastąpi skok do etykiety LED_on

najpierw wpisaliśmy dyrektywy dla kompilatora i ustawiliśmy nasze piny, czyli linię nr0 portu A jako linię wejściową, czyli musieliśmy wyzerować bit o numerze 0 w rejestrze DDRA (wszystkie bity w rejestrach I/O są domyślnie ustawione jako zero, ale lepiej nie ufać wartościom domyślnym i wyzerować konkretny bit), następnie podciągamy nasza linie wejściową poprzez rezystor wewnętrzny do napięcia zasilania(gdy przycisk będzie zwolniony bit nr0 w rejestrze PINA, będzie ustawiony), robimy to poprzez ustawienie(wpisanie wartości 1, używamy instrukcji sbi) bitu 0 rejestru PORTA, ostatnim krokiem jest ustawienie linii 0 portu C do której jest podłączona nasza dioda, jako linie wyjściową .

omówmy teraz pętle główną:

pętla główna(main) sprawdza nam czy przycisk został wciśnięty(bit nr0 w rejestrze PINA wyzerowany), jeśli tak, następuje skok(instrukcja rjmp) do podprogramu "LED_on" który włącza diode, oraz sprawdza czy przycisk nie został zwolniony(czyli bit nr0 w rejestrze PINA ustawiony ), jeśli został, wykonywany jest skok do pętli "main"

i po kolei, co oznaczają poszczególnie linie:

" main: "- jest to tzw. Etykieta, czyli adres w pamięci programu, jest nam ona potrzebna wtedy gdy chcemy za pomocą instrukcji (w tym wypadku "rjmp") wykonać skok do miejsca w programie gdzie została użyta ta etykieta.

Etykiety zapisujemy ze znakiem dwukropka na końcu .

rjmp - Relative Jump- skocz do etykiety "nazwa etykiety"

sbic – Skip if Bit in I/O Register Cleared – nie wykonuj następnej instrukcji jeśli bit w rejestrze wejścia/wyjścia jest wyzerowany "którym rejestrze", "numer bitu"

Cwiczenie 2 -opóżnienia, stos

Pora abyśmy nauczyli się powodować opóznienia w programie, do tego posłuży nam ten sam układ który wykorzystywaliśmy w ćwiczeniu poprzednim, zmienimy tylko trochę jego działanie, otóż gdy przycisk zostanie wciśnięty-dioda zacznie mrugać (z opózniem 250ms)

.nolist
.include "m32def.inc"
.list

.cseg
.org 0

cli //wyłączenie przerwań
ldi R16, HIGH(RAMEND)		//załadowanie adresu końca pamięci[stała RAMEND - zdefiniowana w pliku m32def.inc](starszej jego częśći) SRAM do R16
out SPH, R16				//załadowanie zawartości rejestru R16 do SPH(starszej częśći) rejestru który przechowuje tzw. wskaźnik końca stosu
ldi R16, LOW(RAMEND)		//załadowanie (mlodszej czesci) adresu konca pamieci sram do R16
out SPL, R16				//przepisanie R16 do SPL -rejestru który przechowuje wskażnik końca stosu(młodszej czesci)

cbi DDRA,0 	 // ustawiamy jako linie WEJŚĆIOWĄ pin do którego podlączony jest microswitch
sbi PORTA, 0 //podciągamy go przez wewnętrzny opornik do napięcia zasilania

sbi DDRC,0 //ustawiamy jako linie WYJŚCIOWĄ pin do którego podłączonona jest nasza dioda LED

main:
cbi PORTC, 0	//wyłącz diodę led
sbis PINA, 0	//jeśli przycisk jest zwolniony pomiń następną instrukcje
rjmp LED_on		//instrukcja wykonywana gdy przycisk jest wciśnięty, skok do etykiety LED_on
rjmp main		//instrukcja wykonywana gdy przycisk jest zwolniony ,skok do etykiety main


LED_on:			//tutaj następuje skok gdy przycisk został wciśnięty = bit nr0 w PINA wyzerowany
sbi PORTC, 0	//zapal diodę LED 
rcall delay		//wywołaj podprogram opózniający
cbi PORTC, 0	//zgaś diode LED
rcall delay		//wywołaj podprogram opózniający
sbic PINA,0		//pomin następna instrukcje jeśli bit nr 0 w PINA jest wyzerowany = przycisk wicsniety
rjmp main		//instrukcja wykonywana gdy przycisk zostanie zwolniony ,skok do etykiety main
rjmp LED_on		//instrukcja wykonywana gdy przycisk jest wcisniety, skok do etykiety LED_on

delay:
; ============================= 
;    delay loop generator 
;     250000 cycles:
; ----------------------------- 
; delaying 249999 cycles:
         ldi  R16, $A7
WGLOOP0:  ldi  R17, $02
WGLOOP1:  ldi  R18, $F8
WGLOOP2:  dec  R18
         brne WGLOOP2
         dec  R17
         brne WGLOOP1
         dec  R16
         brne WGLOOP0
; ----------------------------- 
; delaying 1 cycle:
         nop
; ============================= 
ret

na początku program może wyglądać na trochę skomplikowany, ale starałem się opisac go jak najdokładniej komentarzami i myślę, że to powinno wystarczyć do zrozumienia idei jego działania.Tutaj chciałbym wyjaśnić tylko kilka spraw które mogą być nie jasne otóż po pierwsze:

po co nam stos ?

Fragment kodu odpowiedzialny za jego implementację w programie:

cli //wyłączenie przerwań
ldi R16, HIGH(RAMEND)		//załadowanie adresu końca pamięci[stała RAMEND - zdefiniowana w pliku m32def.inc](starszej jego częśći) SRAM do R16
out SPH, R16				//załadowanie zawartości rejestru R16 do SPH(starszej częśći) rejestru który przechowuje tzw. wskaźnik końca stosu
ldi R16, LOW(RAMEND)		//załadowanie (mlodszej czesci) adresu konca pamieci sram do R16
out SPL, R16				//przepisanie R16 do SPL -rejestru który przechowuje wskażnik końca stosu(młodszej czesci)

otóż jest on nam potrzebny ,ponieważ używamy pózniej instrukcji rcall jest to instrukcja która wykonuje skok do podprogramu (podobnie jak instrukcja rjmp) tyle, że po napotkaniu w podprogramie instrukcji ret następuje powrót do adresu(powiększonego o 1) z którego nastąpił skok do podprogramu. W naszym programie instrukcje "rcall" używamy do wywołania podprogramu opózniającego, po wykonaniu tego podprogramu (i co za tym idzie opóznienia trwającego 250ms)po powrocie wykonywana jest instrukcja "sbic PINA,0", czyli do powrotu nie potrzebujemy etykiety.

I jeszcze słów kilka o podprogramie opózniającym, otóż nie napisałem go sam, ponieważ w przypadku assemblera pisanie pętli opózniających jest bardzo czasochłonne, użyłem do tego specjalnego programu który generuje nam kod pożądanego opóznienia, program ten jest darmowy i można go pobrać ze strony: http://www.home.unix-ag.org/tjabo/avr/AVRdelayloop.html

gdy uruchomimy program wybieramy jakie potrzebujemy opóznienie, jakie jest taktowanie naszego mikrokontrolera oraz jakich rejestrów chcemy użyć w pętli, następnie klikamy przycisk "go" i w polu obok zostaje wygenerowana pętla opózniająca, wystarczy skopiować ją do naszego programu i gotowe. Jeżeli będziemy używali tego podprogramu częśćiej niz raz możemy dodać nad nim etykietę(w przypadku naszego programu to "delay:") a na końcu rozkaz "ret". Za pomocą pętli opóżniających możemy również programowo eliminiować drgania styków, a polega to na tym, że po wykryciu wciśnięcia przycisku w programie następuje opóżnienie trwające co najmniej 50ms, następnie po raz kolejny sprawdzamy czy przycisk jest wciśnięty,jeśli tak program idzie dalej, jeśli nie następuje powrót do pętli sprawdzającej stan przycisku.

nowe instrukcje które pojawiły się w programie:

rcall - Relative Call Subroutine - skok względny do podprogramu,"etykieta do której ma odbyć się skok"

ret – powrót z podprogramu do miejsca z którego nastąpił skok

dec - decrement – dekrementuj(pomniejsz o 1), "nazwa rejestru"

brne – branch if not equal – skocz jeśli nie jest równe, " do etykiety "

nop – no operation – nic nie rób

Sbis - Skip if Bit in I/O Register Set, czyli pomiń następną instrukcje, jeśli bit w rejestrze I/O jest ustawiony "nazwa rejestru", "numer bitu" .

Na zakończenie słów kilka o symulatorze:

w AVR studio 4 mamy dostępny również symulator, który bardzo pomaga w diagnozowaniu błędów w programie, oraz gdy chcemy zobaczyć jak będzie przebiegało jego wykonywanie, aby uruchomić symulator musimy skompilować program->

na górnym pasku wybrać debug->

w rozwiniętym pasku wybrać start debugging->

klikamy F11 ->

przeskakująca strzałka wskazuje nam instrukcję która zostanie wykonana w następnym kroku .

Stan rejestrów możemy modyfikować i podglądać po prawej stronie okna programu,po lewej stronie widzimy informacje dt. Jednsotki centrlanej

przydatne pdfy:

http://www.atmel.com/Images/doc1022.pdf - poradnik dla użytkownika assemblera AVR ,możemy znależć tu wsyztskie instrukcjie wypisane w tabeli

http://www.atmel.com/images/doc0856.pdf - zdecydowanie bardziej rozbudowany przewodnik, jak widać mamy opisaną po kolei każdą instrukcje i nie tylko.

http://www.atmel.com/Images/doc2503.pdf - nota aplikacyjna naszej atmegi32

Starałem się uniknąć błędów w artykule, ale jeśli jednak jakiś znajdziecie, czy to rzecozwy, czy ortograficzny to proszę śmiało pisać. To by było na tyle, do zobaczenia w następej części.

asm.jpg.ad14cae307ae7bff99a1f4595e637b82.jpg

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Hm.. Szczytna seria artykułów, tylko pytanie kto dzisiaj programuje w ASM. Poza mną 😉 i to jeszcze tylko specyficzne wypadki.

Co do samego arta, to aby opis programowania w ASM miał spójność, najpierw należałoby by przedstawić rdzeń AVR, tryby adresowania i całą listę instrukcji, a dopiero potem podawać przykłady programów.

Tak to powstaje kogel mogel, który tylko miesza początkującemu w głowie, bo zachodzi tylko skąd co się bierze i dlaczego tak a nie inaczej. A w ASM często można napisać to samo na 5 sposobów, używając różnych podejść i instrukcji.

Ogólnie artykuł o robieniu wstawek ASM np. w C czy BASCOM byłby git w tej formie, ale o samym ASM, to trzeba liczyć się z 7-10 częściowym artem na dzień dobry jak ma to być spójne i porządne. Sam kurs ASM na 8051 z EDW ma chyba z dobre 24 części, z czego połowa to tylko opis procesora i instrukcji ASM.

Udostępnij ten post


Link to post
Share on other sites

Jak pisałem już w pierwszej części ,umiejętność programowania w asm jest przydatna ,więc zawsze warto umieć posługiwać się tym językiem ,nawet programując w C (np. czasem zachodzi konieczność napisania wstawki). A co do tego ,że w artykule jest kogel mogel ,po części masz trochę racji, ale nie do końca się z tobą zgadzam, ponieważ czytanie, że gdzieś tam występują takie a takie rejestry czy że mamy architekturę 8-bitową itp. bez napisania co to oznacza z punktu widzenia programisty, nie jest zbyt pouczające i w sumie po przeczytaniu suchych faktów o architekturze i tak nam niewiele daje.

edit:to widać mamy trochę odmienne zdanie bo wg. mnie asm jest właśnie takim językiem ,że jak załapiemy na czym polega idea programowania w tym języku niewiele trzeba ,aby swobodnie go używać. Wydaję mi się, że trochę demonizujesz ten język 😉

__________

Komentarz dodany przez: Treker

Interpunkcja. Spacje po, a nie przed... 🙂

Udostępnij ten post


Link to post
Share on other sites

Dla tego napisanie dobrego kursu o ASM jest tak trudne, trzeba umiejętnie pokazywać wiele rzeczy naraz. ASM jest przydatny i to bardzo, szczególnie jak się pisze GRY :-> , albo programy gdzie trzeba wycisnąć ostatni dech z proca, czy pracować ekstremalnie energo oszczędnie, na np. kwarcu zegarkowym i takie rzeczy jak czas wykonania pojedynczej instrukcji, czy dostępu do danych nabierają znaczenia.

Udostępnij ten post


Link to post
Share on other sites

Jestem zielony w sprawach architektury uC, ale ogólnie wiem co to rejestr, itp.

Póki co rozumiem o czym się do mnie pisze : D (Ciekawe jak będzie później ^^)

Bym potestował na medze 8, ale czekają mnie poprawki na dniach (ehh te studia nieszczęsne 😃), więc nie mam "aż" tyle czasu 😉

Udostępnij ten post


Link to post
Share on other sites

Poradnik trafia w sedno, fakt faktem poznaj assembler a reszta języków programowania to już małe piwo 😉

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!

Anonim
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.

Zaloguj się, aby obserwować  

×
×
  • Utwórz nowe...