logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[asm] Dziwne zachowanie programu na ATtiny2313 z diodami LED na porcie B

Lysoleq 01 Lut 2008 23:35 1860 19
REKLAMA
  • #1 4760683
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    Witam. Napisałem program którego zachowanie jest dla mnie dziwne.

    Konfiguracja układu:
    ATtiny2313 podłączony do zasilania +5V, oraz 8 diod LED podłączonych przez rezystor 330Ω do portu B.

    Program:
    
    .include "tn2313def.inc"
    
    .def		acc = r20
    
    .dseg
    .org	0x0060
    Zmienna1:	.BYTE 1
    Zmienna2:	.BYTE 1
    
    .cseg
    .org	0x000	rjmp Reset
    
    .org	0x005	rjmp PRZERWANIE
    
    Reset:
    clr		r21
    
    ldi		acc,0xFF
    out		DDRB,acc	;Port B wyjściem
    out		PORTB,acc	;w stanie wysokiej impedancji
    
    ldi		acc,0x00
    out		DDRD,acc	;Port D wejściem
    out		PORTD,acc	;w stanie wysokiej impedancji
    out		DDRA,acc	;Port A wejściem
    out		PORTA,acc	;w stanie wysokiej impedancji
    clr		acc
    ldi 	acc, low(RAMEND)			 ;Pobierz najwyższy adres pamięci RAM
    out 	SPL,acc 
    sei
    
    Main:
    ldi		r16,(0<<CS00)|(1<<CS01)
    out		TCCR1B,r16
    clr		r16
    ldi		r16,1<<TOIE1
    out		Timsk,r16
    ldi		r16,0xFE
    sts		Zmienna1,R16
    ldi		r16,0xFD
    sts		Zmienna2,R16
    clr		r17
    rjmp	Czekaj
    
    Czekaj:
    nop
    rjmp Czekaj
    
    PRZERWANIE:
    cpi		r17,1
    breq	Przerwanie2
    inc		r17
    lds		r16,Zmienna1
    out		PortB,r16
    sei
    rjmp	Czekaj
    
    Przerwanie2:
    lds		r16,Zmienna2
    out		PortB,r16
    clr		r17
    sei
    rjmp	Czekaj
    


    Początkowo program działa poprawnie. Zapala na zmianę dwie diody, ale po przejściu kilkudziesięciu cykli zapalają się wszystkie diody i miga tylko ta podłączona do Pinu 1. Po zresetowaniu mikrokontrolera wszystko wraca do normy. Gdzie leży przyczyna tego problemu?
  • REKLAMA
  • #2 4764937
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    Myślałem że komórka RAM po pewnym czasie ulega zapisaniem jakimś śmieciem, więc w wersji drugiej zapisywałem w komórce z której pobrałem dane, te same dane po wykonaniu operacji. Efekt był taki sam.
  • Pomocny post
    #3 4765019
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    Cytat:
    "Początkowo program działa poprawnie"


    to nie dziwne, że na początku działa ci poprawnie a potem leci w przysłowiowe "maliny"

    nie potrafisz kolego jeszcze dobrze się posługiwać przerwaniami i samą konstrukcją programu - masz tak namieszane że szok

    w zasadzie czytając sam program to nie wiadomo dokładnie co chciałeś uzyskać

    pierwsza wskazówka - najpierw musisz zrozumieć co to jest przerwanie i jak się je obsługuje.

    podprogram przerwania wywołuje się automatycznie przez różne źródła jak liczniki, przerwania zewn, UART itp itd. Podprogram przerwania musi trwać bardzo krótko i co ważne musi być powrót z przerwania za pomocą rozkazu "reti"

    a u ciebie następuje przerwanie a z niego skaczesz sobie jakimś rjmp do pętli - brak powrotu z przerwania reti powoduje że na stosie cały czas odkłada się adres PC przy skoku do przerwania i nie zostaje zdjęty rozkazem reti. A to powoduje że po niedługiej chwili stos zaczyna zajmować całą pamięć SRAM i rzeczywiście masz swój kolejny efekt jakby ci się zmienne nadpisywały jakimiś bzdurami a tymczasem to normalne zjawisko w twoim programie. Gdy już nadpisze się cały SRAM to zaczyna się nadpisywać od początku i dochodzi powoli do totalnego crasch'u. Poza tym nie wiesz widzę o tym, że przy wejściu do przerwania trzeba odłożyć na stos "ręcznie" zawartość rejestrów które używasz w przerwaniu i używane są jednocześnie w pętli głównej bo inaczej to przerwanie zmienia ci ich zawartość łącznie z rejesterem statusu i to kolejna przyczyny błędnego działania takiego programu

    zapamiętaj sobie konstrukacja podprogramu przerwania zawsze powinna wyglądać tak:

    Przerwanie:
      push R16
      In R16, SREG
      push R16
    
      ... odłożenie innych ew używanych rejestrów
    
      // --> właściwy program obsługi przerwania
    
      ... zdjęcie ze stosu innych ew używanych rejestrów
    
      pop R16
      out SREG, R16
      pop R16
    
      reti



    widzisz tę konstukcję ??? - wejście do przerwania zapamiętanie na stosie R16 oraz SREG, następnie program właściwy, potem zdjęcie ze stosu aktualnej wartości R16 i co ważne SREG !!!! - a następnie to czego u ciebie totalnie brakuje to rozkaz RETI, który powoduje, że procesor zaczyna wykonywać program główny dokładnie w tym miejscu gdy go przerwał przed wejściem do procedury obsługi przerwania

    teraz jaśniej?

    pozdrawiam i powodzenia
  • REKLAMA
  • #4 4765095
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    Dziękuje za pomoc, zaraz wprowadzę zmiany w życie i dam znać jaki uzyskałem efekt.

    Programowaniem mikrokontrolerów zajmuje sie dopiero od dwóch tygodni i wiem faktycznie mało. Przeczytałem książkę "Mikrokontrolery AVR Attiny w praktyce" Rafała Baranowskiego i bazując na niej staram się zrozumieć działanie poszczególnych elementów ATtiny.


    Zastosowałem się do Twoich porad. Teraz program działa zgodnie z ideą dla jakiej został stworzony. Dziękuje bardzo za pomoc.
  • #5 4766304
    szymtro
    Poziom 30  
    Posty: 1421
    Pomógł: 101
    Ocena: 59
    W takich prostych i krótkich programach nie warto marnować stosu i czasu na push i pop w przerwaniach.
    Używasz mało rejestrów wiec resztę można sobie spokojnie użyć jak stos czy ram:
    timer0_przepełnienie: ;R2-pamięć systemu, r20,r21,r22,r23,r24,r25 ;przerwanie 64Hz
      in r2,sreg ;kopia bitów systemowych
      ;--------------------
      ;--------------------
      out sreg,r2 ;przywrócenie bitów systemowych
    W avr przerwanie automatycznie blokuje następne więc w każdym przerwaniu można używać tych samych rejestrów (np Z, X, R0, R1).

    A kolega mirek zapomniał jak to jest być "zielonym" i zadawać oczywiste pytania.
  • REKLAMA
  • #6 4766359
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    Cytat:
    "A kolega mirek zapomniał jak to jest być "zielonym" i zadawać oczywiste pytania."


    szymtro -> z całym szacunkiem, ale chyba coś ci się pomyliło. Właśnie bardzo dobrze rozumiem początkujących i dlatego starałem się tak w miarę dokładnie wytłumaczyć gdzie leżą przyczyny błędnego działania programu kolegi autora wraz podpowiadaniem jak to można naprawić

    a dodatkowo nie zgodzę się z kolegą, żeby właśnie początkującemu tłumaczyć , że nie warto marnować stosu i czasu na push i pop itp...

    oczywiście - ktoś już doświadczony dobrze poradzi sobie z takimi technikami ale one i tak wcale do niczego dobrego nie prowadzą i nawet zaawansowanemu programiście procków może to pomieszać szyki jak się plącze takie rozwiązania. Szczgólnie gdy się wraca do napisanego kodu po dłuższym czasie - wtedy ciężko jest dojść nawet o co chodziło gdy sami pisaliśmy takie coś.

    Poza tym to ani wielka strata czasu ani stosu aby zachowywać porządek w pisaniu kodu - nawet w prostych programach - tym bardziej, że nawet jeśli jesteś zaawansowanym programistą w asemblerze to możesz skorzystać z makr, które to będą robić za ciebie a dzięki temu kod będzie o wiele bardziej przejrzysty - i to jest bardzo ważne. Nawet nie wspominałem koledze autorowi , że i bez rozkazu reti można sobie radzić odpowiednio manipulując stosem - bo to nie jest droga aby pomóc początkującemu kolego szymtro

    polecam post kolegi Dar.El - oraz jego wiele fajnych makr, które fajnie się wykorzystuje pisząc coś w asemblerze.

    https://www.elektroda.pl/rtvforum/topic665818.html

    tak więc reasumując polecam nadal swoim może wg ciebie nie obiektywnym zdaniem ale zachowanie porządku w kodzie szczególnie przy programowaniu w takim języku jak asembler.

    pozdrawiam i proszę nie traktować moich wypowiedzi jakbym chciał komuś dopiec bo nigdy tego nie zamierzałem
  • REKLAMA
  • #7 4767012
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    Bardzo zależy mi na przejrzystości pisanych programów i możliwości ich szybkiej modyfikacji. Może i przy prostych programach pewne rzeczy są zbyteczne, to wolę od samego początku wyrabiać w sobie pewne dobre nawyki.
  • Pomocny post
    #8 4767709
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    dlatego też proponuję ci jak najwięcej posługiwać się etykietami, zresztą w przypadku zmiennych już to robisz ale warto też robić to w przypadku stałych, np adresów przerwań, adresów pamięci itp...

    ... skąd brać te nazwy? - zajrzyj sobie do plików typu def (definicje dla danego procka) i tam masz wszystko dokładnie - wystarczy tylko użyć kopiuj wklej, poniżej pokazuję ci przykład jak warto definiować początek kodu:

    .cseg						;
    .org 		0				;
    rjmp		RESET			;
    
    .org		INT0addr		;
    rjmp		Przerwanie_INT0
    ;reti						;
    .org		INT1addr		;
    reti						;
    .org		ICP1addr		;
    reti						;
    .org		OC1addr			;
    reti						;
    .org		OVF1addr		;
    reti						;
    .org		0x06;		;
    ;rjmp 		PrzrwanieT0;				;
    reti
    .org		URXCaddr		;
    reti						;
    .org		UDREaddr		;
    reti						;
    .org		UTXCaddr		;
    reti						;
    .org		ACIaddr			;
    reti
    
    RESET:
      // --> tu początek programu


    chodzi mi to o przejrzyste zdefiniowanie wektorów przerwań (warto zamiast wartości liczbowych - adresów wstawiać ich nazwy) - wszystkich przerwań i wstawienie w odpowiednie miejsca rozkazóe reti, nie ma co żałować czasu na wpisanie tego - potem jest zawsze jaśniej a co ważne - czasem gdy zdefiniujesz tylko te przerwania które niby używasz a gdzieś nieopatrznie w kodzie uruchomisz przerwanie, które nie ma zdefiniowanego rozkazu reti to sam już czujesz co się może dziać? znowu co jakiś czas program będzie szedł w "maliny" ..... oczywiście znajdą się i tacy, którzy zaczną płakać że to marnotrawienie pamięci itp, że samemu wie się co się robi ale to niestety tylko świadczy o braku doświadczenia a potem borykania się o wiele więcej godzin z uruchamianiem własnego kodu

    w następnych linijkach po tym pierwsze co rób to zawsze ustawienie rejestru stosu dla każdego procka to ważne - potwm wiadomo inicjalizacja portów i swoich zmiennnych a potem ciało programu

    idąc tą drogą na pewno będzie ci łatwiej zaczynać z tym trudnym ale jakże przyjemnym językiem. Na pewno warto go poznać - a potem do większych projektów wybrać sobie język wyższego poziomu jak C albo Bascom. Najważniejsze że wtedy pisząc w tych językach już się wie co "w trawie piszczy" i łatwiej się w tym wszystkim poruszać

    życzę powodzenia w asemblerze

    pozdrawiam

    Dodano po 17 [minuty]:

    aha przy okazji zobacz sobie jak fajnie można sobie podefiniować kolory jeśli piszesz program używając AvrStudio4.... to tylko zmiana pliku ini dla avrstudio, jak będziesz chciał to ci go podeślę... a do tego jak to zmieniać doszedł kiedyś i pochwalił się tym tu na elektrodzie kolega Dar.El ... (muszę o tym wspomnieć)

    [asm] Dziwne zachowanie programu na ATtiny2313 z diodami LED na porcie B

    [asm] Dziwne zachowanie programu na ATtiny2313 z diodami LED na porcie B

    pozdr
  • #9 4767886
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    Dzięki za rady z tymi przerwaniami. Wyczytałem w jakimś kursie że powinno sie tak robić, więc tak też postępuje.

    W chwili obecnej borykam się z poleceniami "reti" i "ret". Wiem już że powodują one powrót do miejsca w którym wywołano pewien podprogram, lub przerwanie i że działają z poleceniami zachowującymi adres, jak np.: rcall. Staram się więc wykonywać funkcje w postaci:

    
    rcall Funkcja1
    
    Funkca1:
    ...
    ret
    


    Lecz mimo wszystko czasami program skacze do jakiejś funkcji, czego zupełnie nie rozumiem (zwłaszcza gdy funkcja Y jest w funkcji X), ale pracuje nad tym :).

    Dzięki za porady, wszystkie są dla mnie cenne.
  • Pomocny post
    #10 4767992
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    tak jak piszesz reti używasz tylko do powrotów z przerwań, natomiast samo ret do powrotów z funkcji (podprogramów)

    aby dosyć jasno pisać kod należałoby się trzymać pewnej zasady, o którą czasem wiadomo ciężko ale...

    .... otóż po tei inicjalizacji robisz tzw pętlę główną (zamkniętą) - występuje ona w każdym języku wyższego poziomu jak Bascom lub C.

    czyli jest sobie:

    
    ; ********************* pętla główna programu
    Petla_glowna:
      // --> kod pętli
    
      rcall funkcja_1
      ---> skok do funkcji_1
    
      rcall funkcja_2
      ---> skok do funkcji_2
    
      // --> kod petli
      rjmp Petla_glowna 
    ;*********************** koniec pętli głównej
    
    
    
    ;**************************
    ; funkcja1 
    ; parametry wejściowe przekazywane przez: xxxx
    ; parametry wyjściowe przekazywane przez: xxxx
    funkcja_1:
    
      //--> kod funkcji1
      ret
    
    
    
    ;***************************
    ; funkcja2 
    ; parametry wejściowe przekazywane przez: xxxx
    ; parametry wyjściowe przekazywane przez: xxxx
    funkcja_2:
    
      //--> kod funkcji2
      ret

    jak wspominałem to tylko teoria a program potrafi się czasem mocno rozrastać i wtedy trzeba umieć panować nad rozkazami rcall oraz rjmp, brne, breq itp

    tu nie ma jakichś jasnych zasad odnośnie np tego aby nie robić zagnieżdżonych funkcji itp ale warto wyraźnie rozdzielać dla oczy kod pętli głównej i właśnie funkcji oraz podprogramów aby było widać skąd wracamy rozkazem ret a skąd wracamy za pomocą skoku w inne miejsce za pomocą np rjmp

    dodatkowo warto też pamiętać o najważniejszym czyli o ty, że czasem skaczesz rcall gdzieś tam i wykonujesz przez chwilę całkiem odrębną rzecz a jednocześnie używasz rejestru SREG lub innych rejetrów, które czasem w funkcji mogą niechcąco zmienić wartość tych z programu głównego i po powrocie za pomocą ret już są zniszczone wartości i znowu program może iść "w maliny"

    wydaje mi się, że z tym skakaniem do innej funkcji niż byś oczekiwał masz problemy głównie ale nie przy użyciu rcall tylko przy skokach warunkowych typu breq, brne itp itp

    taaaak przy nich trzeba trochę posiedzieć i dobrze na początku załapać jak one działają i w oparciu o jakie znacziki dokonują skoku a co za tym idzie co powoduje zmianę tych znaczników

    ... poza tym wszystkim poczytaj o makrach - one ułatwią ci mnóstwo rzeczy jak się nauczysz nimi choć troszkę posługiwać

    powodzenia
  • #11 4768131
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    mirekk36 napisał:

    ... poza tym wszystkim poczytaj o makrach - one ułatwią ci mnóstwo rzeczy jak się nauczysz nimi choć troszkę posługiwać

    a polecasz jakas dobra lekture? z moich obserwacji wynika, ze makra swietnie nadaja sie do wywolywania funkcji. w skrocie - mamy np funkcje ktora przyjmuje 5 wartosci w rejestrach od R1 do R5, oraz zwraca jakis ciag danych pod adres podany w R6. wiec zamiast za kazdym razem bawic sie w inicjalizowanie 6 rejestrow, pisze sie makro, ktore robi to za nas, a na dowidzenia wywoluje CALLa. o tym mowisz, czy o czyms innym?

    0x41 0x56 0x45!!
  • #12 4768431
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    Z tego co mi wiadomo to MACRA nie wywołuje się RCALL, tylko po prostu wpisuje jego nazwę i parametry, np.:

    
    .MACRO Czas_licznika
    push	acc
    ldi		acc, INT((@0)*CZESTOTLIWOSC_uP/DZIELNIK_TIMER0+0.5)
    out		OCR0A,acc
    in		acc,TCCR0B
    sbr		acc,1<<CS00		
    out		TCCR0B,acc
    pop		acc
    .ENDM
    


    Po wpisaniu "Czas_licznika 1" ustawiony będziesz miał licznik OCR0A na 1 ms.

    Masz racje że błędy wyskakują mi tylko wtedy gdy operuje którąś z funkcji brne, breq, brlo, itd.
  • #13 4768444
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    Freddie Chopin -> przykro mi ale też nie znalazłem jakiejś dobrej lektury w której dużo i z wieloma przykładami byłoby na ten temat.

    ale nie ma jak to czytanie wielu książek i z każdej po trochu, do tego internet i przykłady na żywo z programów plus dużo własnych prób i do czegoś się powoli dochodzi. Jak widzisz powyżej podałem fajny link do postu kolegi Dar.El , który opracował wiele makr no i jest też tam trochę wiedzy na ten temat - polecam

    a kolega Lysoleq podał właśnie bardzo dobry przykład jak można stosować makra i ma rację, że nie wykorzystuje ich się aby skakać do nich racll itp....

    to jest tak, że definiuje je się w kodzie programu ale preprocesor zamienia je na odpowiednie fragmenty kodu i wstawia je tam gdzie zostały użyte. Innymi słowy mówiąc, jeśli makro jest tylko zdefiniowane a nie zostało użyte to kompilator nie wstawi go niegdzie do kodu bo jak?

    oczywiście makra to wspaniała rzecz ale też nie można przesadzać z ich użytkowaniem

    pozdrawiam
  • #14 4768525
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    
    .include "tn2313def.inc"
    
    
    .equ	CZESTOTLIWOSC_uP = 8000000
    .equ	KIER_IR	= DDRD	;rejestr kierunku port podczerwieni
    .equ	OUT_IR = PORTD	;rejestr wyjściowy portu podczerwieni
    .equ	IN_IR = PIND	;rejestr wejściowy portu podczerwieni
    .equ	PIN_IR = 3		;numer lini sygnałowej	
    .equ	DZIELNIK_TIMER0 = 256000
    
    .def	acc = r16 	;akumulator
    .def	acc2 = r17
    
    
    .cseg
    
    .org	0x000	
    		rjmp Reset
    .org	0x002	
    		rjmp INT1_IRQ
    .org	0x00D	
    		rjmp TIMER0_IRQ
    
    
    .MACRO Czas_licznika
    push	acc
    ldi		acc, INT((@0)*CZESTOTLIWOSC_uP/DZIELNIK_TIMER0+0.5)
    out		OCR0A,acc
    in		acc,TCCR0B
    clr		acc
    sbr		acc,1<<CS00		
    out		TCCR0B,acc
    pop		acc
    .ENDM
    
    Reset:
    ldi 	         acc, 0x00         
    out	        SREG,acc
    ldi		 acc,LOW(RAMEND)		
    out		SPL,acc				;Inicjalizacja wskaźnika stosu
    rcall	        INIT_IR
    sei
    rcall	Main
    
    Main:
    nop
    rjmp	Main
    
    INIT_IR:
    push	acc
    in		acc,SREG
    push	acc
    
    cbi		KIER_IR,PIN_IR		;Ustaw jako wejście DDRB,3 [poziom 0]
    sbi		OUT_IR,PIN_IR		 
    
    
    in		acc,EIFR
    cbr		acc,1<<INTF1		;Flaga przerwania
    out		EIFR,acc
    
    in		acc,MCUCR
    sbr		acc,1<<ISC11		;Wyzwalany zboczem opadającym
    out		MCUCR,acc
    
    in		acc,GIMSK
    sbr		acc,1<<INT1			;Aktywacja przerwania
    out		GIMSK,acc
    inc		acc
    
    in		acc,TIMSK
    sbr		acc,1<<OCIE0A			;Aktywacja przerwania
    out		TIMSK,acc
    inc		acc
    
    pop		acc
    out		SREG,acc
    pop		acc
    ret
    
    INT1_IRQ:
    push	      acc
    in		acc,SREG
    push	      acc
    push	      acc2
    
    ldi		acc,0		
    out	       OCR0A,acc
    
    Czas_licznika 0.9
    lds		acc2,IR_BIT
    cpse	       acc,acc2
    Czas_licznika 1.5
    
    pop		acc2
    pop		acc
    out		 SREG,acc
    pop		acc
    reti
    
    TIMER0_IRQ:
    jakaś tam funkcja
    reti
    
    


    Dlaczego po wykonaniu przerwania INT1_IRQ program skacze do 0x00D a następnie do TIMER0_IRQ? Myślałem że zaczynam to rozumieć, ale widocznie coś przeoczyłem...
  • #15 4768612
    n01x
    Poziom 12  
    Posty: 101
    Pomógł: 2
    Ocena: 1
    mirekk36 napisał:


    aha przy okazji zobacz sobie jak fajnie można sobie podefiniować kolory jeśli piszesz program używając AvrStudio4.... to tylko zmiana pliku ini dla avrstudio, jak będziesz chciał to ci go podeślę... a do tego jak to zmieniać doszedł kiedyś i pochwalił się tym tu na elektrodzie kolega Dar.El ... (muszę o tym wspomnieć)


    Ja poprosze raz: piotrek(_at_)polmark.tarnow.pl
  • #16 4768675
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    Lysoleq ->
    Cytat:
    "Dlaczego po wykonaniu przerwania INT1_IRQ program skacze do 0x00D a następnie do TIMER0_IRQ?"


    tak na wstępie - to teraz aż przyjemnie patrzy się na twój kod ;) .... ale do rzeczy - mówisz , że program jakby skacze do przerwania Timera po przerwaniu INT1

    .... nie mogę teraz za bardzo tego przeanalizować ale może być taka sytuacja, że: wystąpiło przerwanie INT1 i podczas jego obsługi wystąpiło przrwanie od Timer1 - wtedy prockek po zakończeniu obsługi pierwszego przerwania odrazu zaczyna wykonywać to co się dzieje w drugim i stąd takie zjawisko - zresztą całkiem normanle.

    n01x -> ok umieszczam ten plik ini tutaj, ale zanim go podmienisz zajrzyj sobie do swojego oryginalnego, zrób jego kopię na wszelki wypadek i zobacz co się pozmieniało żeby mieć nad tym kontrolę własną jak coś
    Załączniki:
    • AvrStudio_asm.zip (1.95 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #17 4768799
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    Cytat:
    tak na wstępie - to teraz aż przyjemnie patrzy się na twój kod


    Dzięki mirekk36, staram się wcielać w życie dobre rady bardziej doświadczonych.

    Też myślałem, że problem polega równoczesnym zajściu dwóch przerwań, ale nie zależnie od tego jaki czas przerwania ustawie [od 1ms do 8ms] dzieje się zawsze tak samo. Program po prostu wraca do przerwania TIMER0_IRQ. Po dojściu do instrukcji RETI przerwania INT1_IRQ, licznik OCR0A zawsze przeskakuje do wartości w której następuje przerwanie. Wygląda to tak jakby program uciekał gdzieś i dopiero przerwanie zegara sprowadza go na ziemię...

    Problem leży gdzieś tu:
    
    .MACRO Czas_licznika
    push   acc
    ldi      acc, INT((@0)*CZESTOTLIWOSC_uP/DZIELNIK_TIMER0+0.5)
    out      OCR0A,acc
    in      acc,TCCR0B
    clr      acc
    sbr      acc,1<<CS00      
    out      TCCR0B,acc
    pop      acc
    .ENDM 
    


    po wycięciu instrukcji push i pop wszystko wraca do normy. Czy w MAKRAch nie można używać tych funkcji?
  • #18 4769836
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    Lysoleq -> ... poczekaj, ale ty po wejściu w przerwanie INT1 inicjujesz Timer0 prawda? czyli ma się wykonać za jakiś tam czas przerwanie no i wykonuje się. Czyli po rozkazie reti skacze do obsługi przerwania timera0. Przecież w pętli głównej masz tylko nop - więc co ten cały program ma robić?

    jak rozumiem czeka na zbocze opadające na INT1, w tym przerwaniu inicjalizuje Timer0 tak więc kolejną rzeczą będzie wykonanie programu obsługi przrwania Timer0 - no może po drodze będzie wykonanych kilka instrukcji nop w pętli glównej

    ... sorki ale już dosyć dawno nie pisałem w asm więc trudno mi tak na gorąco przeanalizować szczegóły inicjalizacji jaką zrobiłeś choć wygląda ok ale mogę się mylić w swojej analzie ;) pamięć zawodzi po jakiejś tam przerwie

    ... na jakiej podstawie sądzisz że po rozkazie reti nie wraca do pętli głównej? czym i jak to badasz?

    wg mnie po reti zdejmowany jest ze stosu PC i wykonuje się być może kilka przebiegów tej pustej pętli i po chwili skok do obsługi przrwania Timer0

    .... ale może ktoś inny jeszcze na to spojrzy , kto akurat siedzi na bieżąco w asm avr

    ... może napisz jeśli to nie tajemnica co chcesz tak w ogóle uzyskać - to może łatwiej będzie trafić na jakiś trop gdzie robisz błąd

    pozdr
  • #19 4770642
    Lysoleq
    Poziom 17  
    Posty: 264
    Pomógł: 25
    Ocena: 12
    Mirekk36 popełniam dużo błędów więc zanim umieszczę program we FLASHu przeprowadzam na komputerze jego symulacje i widzę jak działa krok po kroku. Ten akurat po wyjściu z INT1_IRQ powinien wrócić do MAIN (podczas niej został zainicjowane przerwanie INT1) i wykonywać tą pustą pętle. Zamiast tego program natychmiast przepełnia licznik i skacze do TIMER0_IRQ. Przez natychmiast mam na myśli skok np. od 0x0F nawet do 0xFF wartości licznika, podczas wykonywania reti. Znalazłem problem - funkcja push i pop w MACRO, tylko nie wiem czemu usunięcie tych instrukcji rozwiązuje problem. Nie lubię rozwiązań w stylu "tak działa więc tak musi być", wolałbym zrozumieć dlaczego ich usunięcie eliminuje problem.
  • #20 4770970
    mirekk36
    Poziom 42  
    Posty: 9195
    Pomógł: 964
    Ocena: 2289
    posłuchaj odłożenie na stos i zdjęcie w makrach to normalna sprawa, powiem więcej, wrzuciłem sobie ten kod jak go napisałeś powyżej też do symulatora w AVrStudio4 i po zasymulowaniu wystąpienia przerwania działa wszystko tak jak sądziłem i jak pisałem tzn po reti wraca ponownie do Main a nie tak jak ty piszesz do przerwania Timer0

    więc albo w międzyczasie coś jeszcze dopisałeś i pozmieniałeś albo nie wiem co ...

    oczywiście zaremowałe tylko tą linijkę "jakaś funkcja" w przerwaniu Timer0 oraz zmieniłem linijkę:

    lds acc2,IR_BIT

    na

    lds acc2, 100

    żeby działało w symulatorze

    i naprawdę wszystko chula po przerwaniu INT1 i po jego reti i jak widzisz również z tym push acc i pop acc w tym makrze, które w przerwaniu jest 2 razy podstawiane, więc u ciebie to jakiś dziwny właśnie przypadek, że po wyjęciu push i pop działa poprawnie - masz rację z takimi sytuacjami zawsze trzeba walczyć aż się dojdzie co jest przyczyną wadliwego działania a nie uznawać że teraz jest OK.... bo z kolei za parę chwil okaże się że w innym miejcu taka konstrukcja też nie działa itp itp

    mam nadzieję, że zassałeś ze stronki Atmela najnowszą wersję AvrStudio i że zainstalowałeś odpowiednie serwispacki do niego?????

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z działaniem programu asemblerowego na mikrokontrolerze ATtiny2313, sterującym 8 diodami LED podłączonymi do portu B. Głównym problemem było nieprawidłowe zachowanie przerwań, szczególnie brak użycia instrukcji "reti" w obsłudze przerwań, co powodowało przepełnianie stosu i nieoczekiwane nadpisywanie zmiennych. Wskazano, że podprogram przerwania musi być krótki i kończyć się instrukcją "reti" dla poprawnego zwolnienia stosu. Autor programu uczył się obsługi przerwań i struktury asemblera, wdrażając dobre praktyki, takie jak stosowanie etykiet i czytelnej organizacji wektorów przerwań. Poruszono także temat użycia makr w asemblerze, gdzie problemem okazało się stosowanie instrukcji push i pop w makrze inicjującym timer, co w symulacji powodowało błędy, a ich usunięcie eliminowało problem. Dyskutowano o różnicach między instrukcjami "ret" (powrót z funkcji) i "reti" (powrót z przerwania) oraz o konieczności stosowania pętli głównej programu. Wskazano, że przerwania mogą się nakładać, co jest normalne, a poprawna obsługa wymaga zrozumienia ich działania i właściwego zarządzania stosu. Autor potwierdził, że po zastosowaniu rad program działa zgodnie z założeniami.
Wygenerowane przez model językowy.
REKLAMA