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

Gdzie Codevision utrzymuje swój stos ?

rpal 18 Sie 2009 00:49 1200 9
  • #1 6904438
    rpal
    Poziom 27  
    Możliwe że z racji późnej pory nic konstruktywnego nie wpadło mi do głowy stąd pytanie na forum. Mam napisany doś duży program na atmega32 który to między innymi posiada absługę menu na LCD i kolejno wybierane opcje sterują zasadniczym programem. Zrobiłem tez procedurę sprawdzająca bezczynność obsługi klawiatury i w zalezności od czasu "nic nie robienia" program automatycznie generuje kod znaku "ESC" czyli ucieczki z menu piętro wyżej. Pod drodze znajdują się procedury zapamietania ekranu i przywrócenia jego poprzedniego stanu. Procedury te utrzymują przechowując w lokalnej zmiennej zapamiętany obraz pamięci DRAM z LCD. Przyszło mi do głowy aby w przypadku bezczynności opuścić aktualny poziom menu i przjeść do jego najwyższego poziomu. Lokalne "podmenu" zagłebiają się najwyzej do na "4-5"poziom i to co w pierwszej chwili wpadło mi do głowy to użyć stosu aby z tamtąd dobrać się do adresu nadrzędnej procedury (procedura main) która to wywołuje kolejne, itd.. Pytanie gdzie znajduje się ten stos i jak się do niego dobrać ? Krótko mówiac chodzi o ustalenie adresu miejsca w pamięci programu które wywołuje kolejne procedury. Jesli to będe miał reszta to pikuś odwołam się do niego jako wskaźnika funkcji i jakoś to poleci dalej. Może któś podrzucić mi jakieś sensowne i w miarę proste rozwiazanie :) Na etapie aktualnej "prowizorki" program działa dośc sprawnie tylko że owa bezczynność a w zasadziej jej sprawdzanie powoduje że kolejno przechodzę przez wszystkie poziomy menu aż do menu nadrzędnego, a chciałbym tego uniknąć i przejśc wprost do głownej częsci programu programu.
  • Pomocny post
    #2 6904481
    BoskiDialer
    Poziom 34  
    Jeśli kolejne poziomy menu robisz przez dodatkowe wywołania funkcji, to po wykryciu nieaktywności możesz wysłać jakiś kod Super-escape, który spowoduje powrót przez wszystkie poziomy - jedna funkcja to przechwyci, zakończy co ma, zwróci wartość przez return oznaczającą odebranie tego kodu, przez co poprzednie funkcje wykryją ten przypadek i również się same zakończą. Możesz zrobić zmienną globalną, którą jeśli funkcje wykryją że jest ustawiona, będą wychodzić aż do najwyższego poziomu gdzie zmienna zostanie wyzerowana. Generalnie grzebanie po stosie jest najgorszą rzeczą jaką można zrobić, gdyż funkcje mogą się nie zakończyć, mogą nie przywrócić pewnych rejestrów które powinny zostać przywrócone przed powrotem do głównej funkcji etc. Najlepiej zmusić kod żeby sam rozwinął stos.
  • #3 6904620
    rpal
    Poziom 27  
    No tak, wyleczyłem się z grzebania w stosie.Globalnych zmiennych jakoś nie darzę sympatią traktując je jako zło konieczne ale chyba nie ma innego wyjścia. Dzięki za radę.
  • #4 6905266
    szelus
    Poziom 34  
    Jeżeli chcesz "zwinąć" stos zgodnie z zasadami języka C , to możesz jeszcze wykorzystać parę funkcji setjmp/longjmp (z biblioteki AVR libC).
  • #5 6905585
    BoskiDialer
    Poziom 34  
    szelus napisał:
    Jeżeli chcesz "zwinąć" stos zgodnie z zasadami języka C , to możesz jeszcze wykorzystać parę funkcji setjmp/longjmp (z biblioteki AVR libC).

    Osobiście wolał bym nie używać tych funkcji, gdyż przy wywołaniach na więcej niż jeden poziomów w głąb mogą pojawić się problemy, no i brak jest możliwości zwalniania innych zasobów.

    Jeśli detekcja braku aktywności nie następuje w przerwaniu, to można pominąć używanie zmiennej globalnej. Wszystkie funkcje domyślnie zwracają np 0, ale jeśli któraś wykryje brak aktywności to zakończa co ma i zwraca np 1 - znak dla funkcji nadrzędnej że ma się zakończyć. Alternatywnie można rekurencyjnie przekazywać wskaźnik na zmienną, która jest przy detekcji ustawiana co zmusza kolejne funkcje do zakończenia się.
  • #6 6906329
    rpal
    Poziom 27  
    Użyłem sugesti kol. Boskiego i stworzyłem sobei znak superEsc :)
    Bezczynnośc wykrywa u mnie przerwanie timera i wstawia w bufor klawiatury mój znak Esc co nie znaczy że jest to kod 27 :)
    W ten sposób na początek to rozwiązałem jednak z pewnymi wadami typu wcześniej wymienione kolejne przejścia przez poziomy menu. Ze szkodą dla tzw. czytelności jednak posłużyłem się w efekcie poleceniem "go to" i w ten oto naganny sposób opuszczam definitywnie kolejne poziomy menu kiedy to lenistwo nie pozwala nadusić opowiedni klawisz. Niepokoi mnie natomiast coś innego a mianowicie co się dzieje tak naprawdę z pamięcią RAM pozostałą po zmiennych lokalnych ? Logika podpowiada mi że znikają jedknak przy okazji debugowania dopatrzyłem się że nie tak do końca. Fakt że spostrzeżenia dotyczyłe w wyniku niedopatrzenia zmiennej której w epilogu funcji nie zainicjowałem i jak się okazało jej wartość pozostawała przez cały czas na ostatnio używanej wartości. Sądziłem że zasoby RAM będą dynamicznie przydzielane ale jak widać byłem w błędzie. Pytanie brzmi tak, zaufać twórcy kompilatora i nie zawracać sobie głowy tym co się dzieje z RAM po wyjściu z funkcji czy też procedur i końcu żywota lokalnych zmiennych ? Czy też jednak bliżej się jak sobie gospodaruje pamięcią ? Jest to o tyle istotne że 2 kB które mam do dyspozycji jest dość ostro eksploatowane i wiele mi jej nie zostało.
  • #7 6906388
    BoskiDialer
    Poziom 34  
    Część zmiennych może trafić do rejestrów, o nich nie ma sensu mówić. Zmienne lokalne przydzielane są na stosie, tak więc nie ma mowy o pozostawaniu zmiennych - wychodząc z funkcji wskaźnik stosu jest przywracany do wartości z przed wywołania. Przy kolejnym wywołaniu funkcji zwolniona pamięć zostanie przydzielona innej funkcji. Patrząc w debugerze wydawać się może, że zmienne dalej istnieją, zachowują wartość (gdyż stos nie jest czyszczony przy zwalnianiu), w rzeczywistości jednak obszar pamięci przez nie zajmowany może zostać przydzielony innym zmiennym. Stos to nie sterta, tutaj pamięć nigdy nie wycieka - wychodząc z funkcji zwalniana jest cała ramka.
  • #8 6906394
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Jeśli tylko nie rozwalasz normalnego toku programu, to na pewno kompilator zatroszczy się o to, żeby stos po wyjściu z funkcji był zwalniany. To że jakaś zmienna miała tą samą wartość niczego nie dowodzi, bo "zwolnienie" stosu to po prostu przesunięcie wskaźnika jego końca - wartości które tam były nie są modyfikowane, a więc i nie są zamazywane.

    4\/3!!
  • #9 6906408
    szelus
    Poziom 34  
    Ze zmiennymi masz prosto. Zmienne globalne, oraz zmienne lokalne w funkcjach zadeklarowane jako static mają miejsce w pamięci przydzielone na stałe (stały adres).

    Zmienne lokalne funkcji (automatyczne) są przydzielane na stosie bądź w rejestrach. Jeżeli są zlokalizowane na stosie, to po opuszczeniu funkcji stos ulega zwinięciu i zmienne zostają automatycznie zwolnione. Ew. alokację w rejestrach kompilator realizuje tylko w ramach jednej funkcji (przy włączonej optymalizacji i w ramach dostępnych, wolnych rejestrów).

    Moga występować jeszcze zmienne alokowane z tzw. sterty (heap) przy pomocy malloc/free, ale to jawnie i w AVR raczej nie polecane. :)
  • #10 6906455
    rpal
    Poziom 27  
    Kolega szelus uspokoił moje wątpliwości :) Wszystkie zmienne mam w pamięci , zatem na stosie bo wyłączyłem utrzymywanie ich w rejestrach. W sumie niepotrzebnie sobie tym głowę zawracałem bo skoro czegoś nie zainicjowałem to nie ma się co dziwić że są tam jakieś krzaki, natomiast jest znamienne że mimo całego melanżu który na stosie się dzieje, jakimś przypadkiem jedna przypadkowa lokalna zmienna trafiała właśnie na ten sam adres :)
REKLAMA