Napisałem sobie program w assemblerze w AVR Studio 4 na µK ATTiny45. Jest to mój pierwszy program w asm dla avr (nie licząc zwykłego migania ledem ). Program powinien powodować: -najpierw wolne mryganie diody led,
-po naciśnięciu przycisku przejść do szybszego mrygania
-po kolejnym naciśnięciu przycisku powrócić do wolnego mrygania
i tak w kółko.
W programie chciałem wyeliminować drganie styków i zbyt szybkie przeskoki do następnych trybów (tutaj na razie tylko tryby "wolno" i "średnio"). Program zamiast działać jak powyżej, wykonuje cały czas pętlę "WOLNO". Według mnie problem polega na niewyzerowaniu znacznika C przed wykonaniem odejmowania (W treści programu zaznaczyłem gdzie chciałem umieścić zerowanie flagi C). Próbowałem zerować instrukcjami cbi, clr, cbr lecz kompilator nie przyjmuje SREG jako operandu. Moje pytanie brzmi więc: Jak wykonywać operacje na bitach rejestru SREG? Czy jest to wogóle możliwe? W 8051 znacznik C można wyczyścić/ustawić instrukcją CLR/SET, a tutaj ??
Ponadto proszę o sprawdzenie całego kodu i wskazówki co mogłem wykonać lepiej (optymalizacja kodu).
;***************************************
Do programu wniosłem jak na razie cztery poprawki:
(oznaczyłem je gwiazdkami)
-zasugerowana przez tg3a zamiana "clr r22" na "sub r22,r22",
dzięki czemu flaga C jest już zerowana
-przeniosłem etykietę "wracaj" przed operację zdejmowania ze stosu. Wcześniej była umieszczona za instr. pop, przez co oczywiście program nie mógł działać poprawnie.
-zmiana w pewnym miejscu "ret" na "rcall wracaj", związane także ze zdejmowaniem ze stosu
-zmiana wartości opóźnienia w procedurze TR_SW_TEST na dużo mniejszą.
Program jednak nadal nie działa tak jak chciałem, tzn reaguje już na naciśnięcie przycisku (a raczej jego przytrzymanie). Może przesadziłem z opóźnieniem, ale to nie jedyny problem. Gdy trzymam przycisk dioda mrygnie 2 razy wolno, po tym kilka razy szybciej i znowu dwa razy wolno i tak w kółeczko. Za nic w świecie nie chce pozostać w pętli "szybko".
;********************************************************
Kod: Zaznacz cały
.include "tn45def.inc"
.cseg
.org 0x00
;====================================
;
;Autor: Marcin Wójcikowski
;
;Data: 15 grudnia 2008r
;
;====================================
;LED świeci gdy PB0 = 0
;stan aktywny SW_TRYB [PB2(INT0)] to stan niski (0)
;=======================================================
ldi r16,1 ;PB0 jako wyjście, PB2 wejście
out ddrb,r16
ldi r16,5 ;dioda zgaszona, PB2 = 1
out portb,r16
;====================
;=============================================
WOLNO:
clr r20
L00:
ldi r21,255
rcall LEDONOFF ;wywołaj procedurę zasw i zgasz diody
inc r20 ;zwiększ r20 o 1
rcall TR_SW_TEST ;wywołaj procedurę sprawdzenia przycisku SW_TRYB
sbrc r22,0 ;jeśli SW_TRYB NIE był nac. to przeskocz nast. instr.
rjmp srednio
rjmp L00 ;powtórz pętlę
;=============================================
srednio:
clr r20
L01:
ldi r21,100
rcall LEDONOFF
inc r20
rcall TR_SW_TEST
sbrc r22,0
rjmp wolno ;wolno tylko tymczasowo, potem szybko itd.
rjmp L01
;============================================
;======================================
TR_SW_TEST: ;sprawdza czy został naciśnięty klawisz SW_TRYB
;ponadto sprawdza przycisk jedynie gdy r20 > v = 2
;jest to eliminacja niechcianego przeskoku do kolejnego trybu
;Procedura ta także jest odporna na drgania styków.
;UWAGA: Jeśli klawisz został naciśnięty to r22 = 255
push r20
push r21
;************************************
sub r22,r22 ;wyzeruj r22 i flagę C
;zmienione z "clr r22"
;************************************
subi r20,2 ;odejmij liczbę 2 od rejestru r20
brcs wracaj ;jesli bylo przeniesienie to wracaj
sbic pinb,2 ;jeśli przycisk naciśnięty to pomiń nast. instrukcję
;*****************
rcall wracaj
;*****************
ldi r21,18 ;zmiana wartości wpisywanej 80 na 18
;**************
rcall czekaj
sbis pinb,2
ser r22 ;jeśli switch został był nacisn, to r22 = 255
;************************************
wracaj: ;przeniosłem etykietę wracaj przed operacje
;zdejmowania ze stosu. Wcześniej przez nieuwagę
;umieściłem ją za instrukcjami pop co było
;jednym z powodów złego działania programu
pop r21
pop r20
;*********************************************************
ret
;============================
;===========================================
LEDONOFF: ;częstotliwość zależna od wartości r21
rcall czekaj
cbi portb,0
rcall czekaj
sbi portb,0
ret
;=========================================================
;=========================================================
Czekaj: ;czas opóźnienia zależny od r21
;przed wywołaniem procedury należy określić zawartość r21 !!!
;dla r21 = 24, procedura czekaj zajmuje 19804cykle
;zegara, czyli dla 1MHz jest to 19,804ms
;dla r21 = 25 czyli większe o 1 od poprzedniego to dodatkowo 800 cykli
;dla r21 = 26 czyli większe o 2 od 24 to dłużej o 2x800 cykli itd.
push r20
push r16
ldi r20,200
W0:
mov r16,r21
W1:
nop
dec r16
brne W1 ;jeśli flaga zera jest wyzerowana to skocz
;tzn jeśli r16 jeszcze nie jest zerem
dec r20
brne W0
pop r16
pop r20
ret ;wróć do miejsca skąd została wywołana procedura
;=========================================================
;=========================================================