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

BASCOM - jak przerwać procedurę i wrócić do pętli DO...LOOP?

wicy 09 Sty 2006 09:29 2841 16
REKLAMA
  • #1 2161807
    wicy
    Poziom 22  
    Posty: 670
    Pomógł: 30
    Ocena: 111
    Witam. Mam program, który działa w pętli DO..LOOP typu:
    
    DO
    ...
    IF warunek THEN procedura
    ...
    LOOP
    
    przerwanie:
    ...
    return
    
    sub procedura
    ...
    end sub
    

    Procedura wywołana w pętli głównej ma opóźnienia na WAITMS. Chciałbym przy pomocy przerwania (przycisk) zrezygnować w dowolnym momencie z wykonywania 'procedury' i wyjść z jej obsługi do pierwszej instrukcji w pętli DO...LOOP (nie do następnej linii po wywołaniu procedury), natomiast przerwanie wywołane już w trakcie obsługi procedury powróci mi spowrotem do niej. Wstawienie etykiety przed 1 istrukcją pętli DO i użycie w obsłudze przerwania skoku GOTO spowoduje pewnie po jakimś czasie przepełnienie stosu. Jak można wyskoczyć z obsługi przerwania w inne miejsce niż pkt wejścia w przerwanie??
  • REKLAMA
  • #2 2161882
    genetix
    Poziom 24  
    Posty: 669
    Pomógł: 42
    wicy napisał:
    Wstawienie etykiety przed 1 istrukcją pętli DO i użycie w obsłudze przerwania skoku GOTO spowoduje pewnie po jakimś czasie przepełnienie stosu.
    No i tak ma być. Przyjęcie obsługi przerwania polega na odłożeniu na stosie adresu powrotu a następnie wykonanie skoku. Instrukcja reti pobiera ze stosu adres i dzięki niemu powraca w poprzednie miejsce. Jeśli chcesz wyjść z przerwania zwykłym skokiem pozostawasz na stosie adres odłożony przy przyjęciu przerwania.
    wicy napisał:
    Jak można wyskoczyć z obsługi przerwania w inne miejsce niż pkt wejścia w przerwanie??
    Zatem przed "oddaniem skoku" z procedury obsługi przerwania należy zdjąć adres powrotu ze stosu...
    irqPrzerwanie:
    pop r16
    pop r16
    rjmp skok_tam_gdzie_chcesz; czyli Twoje "goto"
    reti ;<- ta instrukcja się nigdy nie wykona

    teraz przetłumacz to na bascom.
    powodzenia,
    genetix
  • #3 2161987
    wicy
    Poziom 22  
    Posty: 670
    Pomógł: 30
    Ocena: 111
    Czyli program miałby wyglądać z grubsza tak?
    
    on int0 przerwanie [u]NOSAVE[/u]
    
    DO
    etykieta
    ...
    IF warunek THEN procedura
    IF inny_warunek THEN inna_procdura
    ...
    LOOP
    
    przerwanie:
    PUSHALL
    ...cialo przerwania
    POPALL
    if wywolany_z_procedury THEN goto etykieta
    return
    

    Z tego co piszą w helpie opcja NOSAVE nie odkłada stanu rejestrów na stos, ale nie mam pewności, czy nie odkłada też adresu powrtou. Może bardziej zaawansowani Bascomowcy podpowiedzą...?

    Instrukcja reti na końcu jest konieczna i się wykona bo ten niestandardowy wyskok z przerwania ma być tylko w jednym, konkretnym wypadku, w jednej z procedur programu. W innych jest standardowo.

    Jeszcze tylko spytam - kombinując już.. Gdzie jest przechowywany adres powrotu z procedury przerwania?? R16? Skoro tak, to czy nie prościej w procedurze przerwania "podmienić" ten adres na adres etykiety i zakończyć procedure standardowym reti??
  • #4 2162076
    elektryk
    Poziom 42  
    Posty: 11029
    Pomógł: 439
    Ocena: 240
    wicy napisał:
    Jeszcze tylko spytam - kombinując już.. Gdzie jest przechowywany adres powrotu z procedury przerwania?? R16? Skoro tak, to czy nie prościej w procedurze przerwania "podmienić" ten adres na adres etykiety i zakończyć procedure standardowym reti??
    Jasne że będzie działać, podobny trick wykorzystuje system operacyjny którego używasz przy przełączaniu zadań. Pytanie tylko czy aby to jest koniecznie? Dużo prościej do tego wykorzystać semafor i obędzie się bez komplikacji.
  • REKLAMA
  • #5 2162431
    genetix
    Poziom 24  
    Posty: 669
    Pomógł: 42
    wicy napisał:
    Jeszcze tylko spytam - kombinując już.. Gdzie jest przechowywany adres powrotu z procedury przerwania??


    genetix napisał:
    Przyjęcie obsługi przerwania polega na odłożeniu na stosie adresu powrotu a następnie wykonanie skoku.
  • #6 2163419
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 51
    W zasadzie wystarczy napiasć no comment , ale ... zdięcie ze stosu adresu powrotu i wskoczenie do etykiety , też nie zda egzaminu.

    Piotrek
  • REKLAMA
  • Pomocny post
    #7 2163534
    genetix
    Poziom 24  
    Posty: 669
    Pomógł: 42
    :arrow: zumek
    Trzeba jeszcze włączyć na nowo przerwania (sei).
  • REKLAMA
  • #8 2163927
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 51
    genetix napisał:

    Trzeba jeszcze włączyć na nowo przerwania (sei).

    Akurat nie to miałem na myśli (ale sei też).Chodzi mi o to , że na stosie mogą zostać "śmieci" i po iluśtam takich "wyskokach" , stos się "zapcha" ;)

    Piotrek
  • #9 2165333
    wicy
    Poziom 22  
    Posty: 670
    Pomógł: 30
    Ocena: 111
    :idea: Dzięki genetix za podpowiedź. Właśnie w testach brakowało mi zadziałania przerwania po wyskoczeniu z jego obsługi. Czy sei ustawia tylko globalną maskę zezwolenia na przerwania, czy jeszcze coś? Jestem w Bascomie i muszę to ustawić "ręcznie".
    A pisząc
    Cytat:
    Jeszcze tylko spytam - kombinując już.. Gdzie jest przechowywany adres powrotu z procedury przerwania??
    miałem na uwadze znany mi już fakt, że przy wejściu w procedurę obsługi przerwania na stos odkładany jest m.in. adres powrotu, ale nie wiem jeszcze pod jaki adres się on odłoży, żeby go ew. zdjąć/pobrać bezpośrednio lub ew wstawić pod ten adres adres etykiety (czy tak się da?). Tak czy siak to już chyba zbędne kombinacje. Program działa już jak chciałem.
    Interesuje mnie jeszcze, zumek, o jakich "śmieciach" mówisz, bo to jakbyś mi powiedział, że polecenie X=1 czasem ustawi X na 2 :?: Skoro odkładam coś na stos i potem to coś z niego zdejmuję co może na nim zostac?
  • #10 2165435
    genetix
    Poziom 24  
    Posty: 669
    Pomógł: 42
    Jak sama nazwa wskazuje możesz zdjąć to, co ostatnio odłożyłeś...
    Widzisz, jakbyś chciał się nauczyć assemblera tobyś wiedział dokładnie co się z czym dzieje... Adres wierzchołka stosu siedzi we wskaźniku stosu - (rejestry SPH:SPL) i wskazuje na puste miejsce, czyli jest zwiększany po odłożeniu elementu. Dlatego "ręczne" zdjęcie danej ze stosu wymaga:
    1. Zmniejszenia SPH:SPL o jeden
    2. Odczytu danej spod adresu SPH:SPL
    Programowo robi się to rozkazem pop [reg]
  • #11 2165553
    wicy
    Poziom 22  
    Posty: 670
    Pomógł: 30
    Ocena: 111
    Genetix... Dzięki za cierpliwe tlumaczenie, ale to znam, bo to ogólne zasady działania stosu i to nie jest kwestia znania, czy nie znania assemblera... Pytanie gorące brzmi: która dana siedząca na stosie jest daną (danymi - zależnie od trybu adresowania) wskazującą na adres powrotu. Czy adres jest odkładany jako pierwszy, jako ostatni, jako który??
  • #12 2165676
    genetix
    Poziom 24  
    Posty: 669
    Pomógł: 42
    Wydaje mi się, że nie dokońca czaisz temat...

    W momencie wykonywania pierwszego rozkazu w programie obsługi przerwania adres powrotu jest na wierzchołku stosu, ale czy dalej tam będzie zależy tylko i wyłącznie od tego, czy np. nie odłożysz tam jeszcze czegoś. Częsty błąd to odłożenie "na chwilę" jakiegoś rejestru na stos i nie zdjęcie go przed powrotem z przerwania, co powoduje powrót z przerwania pod zły adres...
    Aha i na stosie nie ma "danej wskazującej na adres" tylko jest kopia 16-bitowego licznika programu, czyli PC (program counter). Prościej rzecz ujmując jest to adres w pamięci programu, który zostanie załadowany do PC bezpośrednio ze stosu.

    Dodano po 2 [minuty]:

    Aha, może masz na myśli jak bascom to robi? tzn. gdzie jest adres w przypadku przekazywania danych przez stos... tego już nie wiem, trzebaby obejrzeć wygenerowany prez bascoma plik asemblerowy i tam poszukać...
  • #13 2165785
    wicy
    Poziom 22  
    Posty: 670
    Pomógł: 30
    Ocena: 111
    No dobra... czyli jestem kolejny kroczek do przodu :D Adres powrotu jest na wierzchu stosu zaraz po wejsciu w obsługę przewania.
    I jeszcze jedno:
    Cytat:
    adres w pamięci programu, który zostanie załadowany do PC bezpośrednio ze stosu
    doczytałem że za to "przeładowanie" odpowiada właśnie RETI. A żeby "ręcznie" wyskoczyć z przerwania trzeba: zdjąć to co w procedurze wlazło na stos, zdjąć adres powrotu, ustawić zezwolenia na przerwania, czyli w Bacscom załatwić to powinno:
    
    przewanie:
    PUSHALL
    ...'instrukcje
    POPALL
    SREG.7=1
    IF warunek THEN goto etykieta
    RETURN
    
    albo lepiej po wyskoku po etykiecie dać sreg.7=1. Rejestr PC nie musi być odtwarzany, bo zawiera już nowy wskaźnik PC=etykieta. Dobrze kombinuję? I chyba po POPALL przydałby się jeszcze dwa POP-y dla zdjecia zbędnego już adresu powrotu, którego POPALL nie zdejmie. Tak może być??

    Aha.. w sumie na cholerę mi adres powrotu jak i tak skakać mam pod etykiete... :D
  • Pomocny post
    #14 2165871
    genetix
    Poziom 24  
    Posty: 669
    Pomógł: 42
    wicy napisał:
    I chyba po POPALL przydałby się jeszcze dwa POP-y dla zdjecia zbędnego już adresu powrotu, którego POPALL nie zdejmie. Tak może być??
    dokładnie - jak tego nie zrobisz, to z każdym przerwaniem będzie Ci rósł stos o 2 bajty, aż zacznie Ci nadpisywać jakieś dane - wtedy program się "wysypie".

    wicy napisał:
    Aha.. w sumie na cholerę mi adres powrotu jak i tak skakać mam pod etykiete... :D
    Dokładnie tak.
  • #15 2165907
    wicy
    Poziom 22  
    Posty: 670
    Pomógł: 30
    Ocena: 111
    Dzięki!
    Dokładnie działa jak ta lala :D
    Przed skokiem trzeba zdjąć aż 4 POPy bo zapomniałem, że oprócz adresu powrotu jest odkładany na stos adres powrotu podprocedury z której program ma również wyskoczyć do pętli głównej.

    Myslałem wzcześniej jak bezpośrednio podmienić adres powrotu dla procedury przerwania odłożony na stosie na adres etykiety do której ma być wyskok. Myślę, że nawet nie potrzeba wiedzieć pod jakim adresem odkładane są te dwa bajty. Wystarczy zdjąć dwa bajty ze stosu i wepchnąć w odpowiedniej kolejności dwa bajty z nowym adresem skoku. Po wywołaniu reti teoretycznie procesor powinien się dać oszukać i sam sobie wczyta do PC nowy adres skoku... :idea:
  • #16 2165922
    genetix
    Poziom 24  
    Posty: 669
    Pomógł: 42
    tak, można również wrzucić adres do rejestru Z i zrobić IJMP.
  • #17 2171972
    wicy
    Poziom 22  
    Posty: 670
    Pomógł: 30
    Ocena: 111
    Uwagi praktyczne już po próbach z programem :D
    Dopiero jak pozmieniałem właściwy program, jak zobaczyłem to w symulatorze doszedłem do jeszcze prostszego rozwiązania.
    Można podmieniać adresy powrotu w obszarze adresowym stosu, można sobie zdejmować ileś tam danych ze stosu - tylko po co...
    Wystarczy ustawić wskaźnik stosu SPL na adres początkowy stosu (akurat taki adres jest wskazywany w pętli głównej programu do której wyskakuję), zezwolić na przerwania i skoczyć :idea:
    Zauważyłem też, że w normalnym trybie żandna instrukcja nie zeruje danych w obszarze stosu po zdjęciu danej ze stosu, adresy te są nadpisywane przez kolejne odłożenie. Po zdjęciu ze stosu pozostają na nim jakieś nieistotne śmieci tyle że procesor ich nie widzi bo wskaźnik stosu na nie nie wskazuje już. Odpada więc problem zdejmowania adresów powrotu ze stosu bo już są nieistotne i zostaną nadpisane przy kolejnych odłożeniach np. przez wykonanie innych procedur w programie.
    W najprostrzej wersji program wygląda teraz tak:
    
    on int0 guzik nosave
    
    do
      etykieta:
      SREG.7=1
      ...
      CALL procedura1
      CALL procedura2
      ...
    loop
    
    guzik:
      IF ma_byc_wyskok THEN
        SPL=&HDF
        GOTO etykieta
      END IF
    return
    

Podsumowanie tematu

✨ Dyskusja dotyczy problemu przerwania wykonywania procedury wywoływanej w pętli DO...LOOP w Bascom AVR i powrotu do początku tej pętli bez przepełnienia stosu. Standardowe wywołanie przerwania odkłada na stos adres powrotu, a instrukcja RETI przywraca go, co uniemożliwia bezpośredni skok do etykiety w pętli bez ryzyka narastania stosu i błędów. Proponowane rozwiązania obejmują ręczne zdejmowanie adresu powrotu ze stosu w procedurze przerwania (pop instrukcje), a następnie wykonanie skoku RJMP do etykiety w pętli, z ponownym włączeniem przerwań (sei). Alternatywnie można manipulować wskaźnikiem stosu (SPL) ustawiając go na początkowy adres stosu, co pozwala na "oczyszczenie" stosu i bezpieczny powrót do pętli bez konieczności zdejmowania adresów powrotu. Dyskutowano także o strukturze stosu, gdzie na wierzchu znajduje się 16-bitowy adres powrotu (PC), oraz o konieczności zachowania porządku na stosie, aby uniknąć "śmieci" i przepełnienia. Wskazano, że instrukcja RETI jest odpowiedzialna za przywrócenie adresu powrotu, a ręczne manipulacje wymagają ostrożności. W Bascomie można stosować instrukcje PUSHALL i POPALL do zachowania rejestrów, a także ustawiać flagę przerwań w rejestrze SREG. Podsumowując, najprostsze i stabilne rozwiązanie to ustawienie wskaźnika stosu na początkowy adres stosu i skok do etykiety w pętli, co eliminuje problem przepełnienia stosu i pozwala na przerwanie procedury w dowolnym momencie.
Wygenerowane przez model językowy.
REKLAMA