Aktyw Forum

Zarejestruj się na forum.ep.com.pl i zgłoś swój akces do Aktywu Forum. Jeśli jesteś już zarejestrowany wystarczy, że się zalogujesz.

Sprawdź punkty Zarejestruj się

[tiny45][asm]Błąd w programie, optymalizacja kodu

Awatar użytkownika
GVolt
-
-
Posty:1
Rejestracja:3 lis 2008, o 19:04
Lokalizacja:TBG
Kontaktowanie:
[tiny45][asm]Błąd w programie, optymalizacja kodu

Postautor: GVolt » 15 gru 2008, o 18:33

Witam!
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 :P). 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 ;========================================================= ;=========================================================
A poza tym witam wszystkich, bo jest to mój pierwszy post na tym forum :607:
Ostatnio zmieniony 18 gru 2008, o 14:12 przez GVolt, łącznie zmieniany 6 razy.

tg3a
-
-
Posty:243
Rejestracja:26 maja 2008, o 19:46
Lokalizacja:Warszawa

Postautor: tg3a » 15 gru 2008, o 20:37

Witam. Na wstępie porada odnośnie operacji na fladze C (i na innych).
Oto komplet instrukcji asemblera operujących na bitach rejestru SREG:
SEC (Set Carry) C ← 1
CLC (Clear Carry) C ← 0
SEN (Set Negative Flag) N ← 1
CLN (Clear Negative Flag) N ← 0
SEZ (Set Zero Flag) Z ← 1
CLZ (Clear Zero Flag) Z ← 0
SEI (Global Interrupt Enable) I ← 1
CLI (Global Interrupt Disable) I ← 0
SES (Set Signed Test Flag) S ← 1
CLS (Clear Signed Test Flag) S ← 0
SEV (Set Twos Complement Overflow) V ← 1
CLV (Clear Twos Complement Overflow) V ← 0
SET (Set T in SREG) T ← 1
CLT (Clear T in SREG) T ← 0
SEH (Set Half Carry Flag in SREG) H ← 1
CLH (Clear Half Carry Flag in SREG) H ← 0
Poza tym na flagi C, N, Z, S, V i H w określonych sytuacjach można też wpływać innymi rozkazami, zgodnie z funkcjami tych flag i wynikiem wykonywanej operacji. (Ale nieczęsto można w ten sposób "upiec dwie pieczenie przy jednym ogniu". W tym programie akurat by się dało: gdyby zamiast clr r22 zrobić sub r22,r22, to właśnie mielibyśmy to, o co chodzi, czyli i zerowy rejestr r22, i zerowy wskaźnik C w jednym rozkazie.) Warto w szczególności pamiętać o rozkazach ROL i ROR, które dokonują rotacji bitów w lewo lub w prawo w danym rejestrze poszerzonym o flagę C (a więc przy rotacji w lewo bit 7 danego rejestru wchodzi na flagę C, a ta z kolei wchodzi na bit 0, a przy rotacji w prawo odwrotnie).
Analizy optymalności programu na razie jeszcze nie przeprowadzałem. Może inni potrafią to zrobić szybciej i lepiej ode mnie.
Pozdrawiam, i życzę sukcesów w zmaganiach z asemblerem.

Wróć do „Projektowanie PCB, programy EDA, CAD, narzędziowe”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 89 gości