Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[atmega8][Bascom] Zewnętrzne przerwania uniemożliwiają komunikację przez I2C

komanche 15 Apr 2012 19:54 3488 10
  • #1
    komanche
    Level 13  
    Witam!
    Kolega poprosił mnie o zrobienie mini-komputerka do Opla Corsy, mającego wyświetlać dane na wyświetlaczu radia. Problem pojawił się, kiedy zechciałem wyświetlać na bieżąco prędkość - program zgłupiał (choć, raz na kilka odświeżeń wyświetlacza pojawiła się poprawna prędkość) a przy większych prędkościach Atmega ulegała resetom lub się zawiesza.
    Wyświetlacz to standardowy TID, korzystający ze zmodyfikowanego I2C do komunikacji, prędkość zbierana jest z wbudowanego w skrzynię impulsatora dającego 16256 impulsów/kilometr. Poniżej program, opierający się na znalezionej w sieci metodzie wyświetlania danych na TID. W załączniku schemat urządzenia.
    [atmega8][Bascom] Zewnętrzne przerwania uniemożliwiają komunikację przez I2C

    Cały kod:
    Code: vbnet
    Log in, to see the code


    A tutaj tylko część odpowiedzialna za obliczanie prędkości:
    Code: vbnet
    Log in, to see the code


    Proszę o pomoc, bo zadanie mnie odrobinę przerasta. Dawno nie bawiłem się mikrokontrolerami i większości rzeczy pozapominałem. Może zabrałem się za mierzenie prędkości od złej strony? Mam wrażenie, że problem leży w przerwaniach, które mogą pojawić się w trakcie przesyłania danych na ekran wyświetlacza i zakłócać transmisję. Jeśli ktoś, kto zna Bascoma trochę lepiej niż ja (a o to nie trudno) zna sposób na mierzenie prędkości z przyzwoitą rozdzielczością, który nie zakłóci wyświetlania, czekam. Układ jest na razie zmontowany "na pająka" i przelutowanie impulsów np. na wejście jakiegoś timera nie stanowi problemu.

    Pozdrawiam!
  • #2
    speedy9
    Helpful for users
    Rzuciłem okien na kod i nie znalazłem w procedurze wyświeltlania po I2C "DISABLE INTERRUPTS". Powinno pomóc. Możesz też wyłączać tylko INT0 lub INT1. Pamiętaj tylko by je potem włączyć po zakończeniu wyświetlania ("ENABLE INTERRUPTS").
  • #3
    komanche
    Level 13  
    To była moja pierwsza myśl, Disable INT0 umieściłem w pętli głównej na zasadzie
    Code: vbnet
    Log in, to see the code



    I działanie to przyniosło efekt w postaci narastania licznika impulsów z f<1Hz i w konsekwencji V<0.1 km/h. W tym momencie własnie straciłem wiarę we własne siły. Częstotliwość impulsów nie jest aż tak duża, żeby atmega8 nie dała sobie z tym rady - jest to około 4,515imp/s/kph (451,5 imp/s dla 100km/h)
  • #4
    Mundi1970
    Level 24  
    Problem na pewno jest tu :):

    Code: vbnet
    Log in, to see the code

    Jeżeli wykorzystujesz opcje Nosave , to musisz wiedzieć jakie rejestry (R0-R31) wykorzystuje twoja procedura przerwanie. Przed wykonaniem przerwania musisz je sam wysłać na stos, a po zakończeniu przerwania z powrotem ściągnąć ze stosu. Skonfiguruj przerwanie bez opcji Nosave, a kompilator sam zadba o wszystko :). Druga sprawa brak definicji wielkości stosów, zainteresuj się $hwstack, $swstack i $frame.
  • #5
    komanche
    Level 13  
    Mundi1970, bardzo dziękuję Ci za trafną odpowiedź. Tak kończy się korzystanie z poleceń, których działania się nie rozumie. Nadal męczy mnie jeden problem, mianowicie raz na kilka odczytów pojawia się dziwna wartość (np. utrzymując Vconst = 50km/h raz na kilka odświeżeń wyświetlacza pojawia się wartość 35km/h albo 70km/h - przykłady przypadkowe, nie stanowią reguły). Nie wiem teraz, czy jest to objaw braku bezwładności wobec wskazówkowego prędkościomierza samochodu czy efekt błędów obliczeń. Próba uśrednienia pomiaru na zasadzie
    Code: vbnet
    Log in, to see the code

    Kończy się całkowitą utratą poprawności wskazań. Nieszczęśliwie kończy się również wyłączenie przerwań na czas wyświetlania napisu na wyświetlaczu - mierzona prędkość wynosi wtedy niewiele ponad 0. Na etapie uśredniania korzystam ze zmiennych typu single, jeśli ma to jakiekolwiek znaczenie. Dla prędkości do 20km/h (ok 90imp/s) błąd praktycznie nie występuje, pojawia się dopiero powyżej tej wartości.
  • Helpful post
    #6
    xury
    Automation specialist
    Aż mnie dziwi, że przy takiej ilości zagnieżdżonych skoków program się nie wysypuje. Albo może się wysypuje i stąd te dziwne wyniki. Za radą kolegi Mundi1970 zainteresuj się definicjami stosów i przebadaj zagnieżdżanie podprogramów.
  • #7
    komanche
    Level 13  
    Kod obsługujący wyświetlacz nie jest mojego autorstwa, nie analizowałem go i cieszyłem się, że działa. Czy wobec tego, lepiej byłoby zrobić mniej podprogramów, przepisując ich treść w miejsce poleceń gosub*? Czy może przyniesie to efekt odwrotny do zamierzonego?
    Stosy to dla mnie czarna magia, wiem tylko, że każdy przeskok wymaga zapisania adresu zwrotnego, ale nic poza tym :oops:


    * - Czy mając kod
    Code: vbnet
    Log in, to see the code


    Przerobienie go do postaci:
    Code: vbnet
    Log in, to see the code


    Spowoduje poprawę jego jakości?
  • Helpful post
    #9
    Mundi1970
    Level 24  
    komanche wrote:
    Stosy to dla mnie czarna magia, wiem tylko, że każdy przeskok wymaga zapisania adresu zwrotnego, ale nic poza tym :oops:

    No przy takim podprogramie to 1 megabajtowy stos to za mało :D, to się chyba nazywa rekurencja:

    Code: vbnet
    Log in, to see the code


    Przy wartości 31249 wpisywanej do timera1, przerwanie od przepełnienia licznika występuje co 1,09718400 sek. Żeby odliczyć 1 sekundę, musisz wpisać 34286.
  • #10
    komanche
    Level 13  
    Wziąłem sobie Wasze uwagi do serca, choć nie wiem, czy dobrze je zrozumiałem.
    Kod wygląda teraz tak:

    Code: vbnet
    Log in, to see the code


    Poczyniłem następujące zmiany:
    •Zamieniłem polecenia gosub [x] na kod kryjący się w podprogramie [x]
    •Usunąłem nosave z przerwań
    •Usunąłem przerwanie od timer1
    •Pozbyłem się zapętlenia w postaci
    Code: vbnet
    Log in, to see the code

    zastępując je drugą pętlą Do::Loop until

    Ktoś ma jeszcze jakieś propozycje, jak usprawnić ten program, albo widzi jakiś błąd w moim dotychczasowym postępowaniu?


    Edit: Xury, do mnie trochę jak do dziecka, ale zapewne chodzi Ci o błąd w postaci zapętlenia podprogramów? Po dokonaniu w/w zmian, objętość kodu wzrosła o około 30%, rozumiem już, co miałeś na myśli pod pojęciem "redukcji kodu wynikowego". Teraz już nie wiem, dobrze zrobiłem pozbywając się nadmiaru gosub?
  • #11
    xury
    Automation specialist
    Tu nie chodzi o ilość Gosub'ów ale o rekurencyjność i iloś zagnieżdżeń. Trzeba pilnować by każdy podprogram kiedyś zakończył się i wyszedł przez Return. Czym więcej zagnieżdżeń tym więcej potrzeba pamięci na tzw. HW Stack. Jeśli masz wolny RAM to zwiększ ilość pamięci na hwstack ,a przy okazji możesz dorzucić na framesize i swstack.
    Podkreślam jeszcze raz, że nie każę Ci rezygnować z "Gołsabów" tylko pilnować by nie zrobić gdzieś zapętlenia rekurencyjnego ,oraz ustawić odpowiednią ilość pamięci na stosy. Jest to bardzo ważna sprawa (o ile nie najważniejsza) ponieważ zbyt mała rezerwa RAMU na stosy będzie skutkować nadpisaniem zmiennych (tzw. stack owerlap), a jak wiadomo wtedy cały program zaczyna żyć własnym życiem. Dla zobrazowania problemu proponuję zrobić sobie taki eksperyment i zapuścić taki przykładowy program jak ten co podałem wcześniej w symulatorze i obserwować co się dzieje z pamięcią RAM, patrząc na nią od końcowych adresów, gdzie jest stos właśnie i jak po pewnym czasie stos się rozrośnie na tą cześć gdzie znajdują się zmienne.