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

[mega32][BASCOM] wys. LED na przerwaniach i problem z uartem

thorin00 08 May 2010 13:53 1317 3
  • #1
    thorin00
    Level 14  
    witam

    mam zrobioną obsługę wyświetlacza led na przerwaniach i problem z odbieraniem znaków przez uart mianowicie uart "gubi" znaki podczas odbioru, jeżeli wyłączę przerwania przerwania problem znika, niestety wyświetlacz muszę mieć zrobiony na przerwaniach i nie wiem jak mam się z tym problemem uporać. poniżej zamieszczam wybrane fragmenty kodu.
    
    $regfile = "m32def.dat"
    $crystal = 14745000
    $baud = 19200
    
    Config Serialin = Buffered , Size = 50
    Config Serialout = Buffered , Size = 20
    Config Timer0 = Timer , Prescale = 64
    
    On Timer0 Wyswietlacz
    Enable Timer0
    Start Timer0
    Enable Interrupts
    
    Do
       B_uart = Ischarwaiting()
       If B_uart = 1 Then Gosub Odbierzuart
    Loop
    
    
    Wyswietlacz:
          Stop Timer0
          Godziny = _hour
          Minuty = _min
          Cyfra(1) = Godziny / 10
          Cyfra(2) = Godziny Mod 10
          Cyfra(3) = Minuty / 10
          Cyfra(4) = Minuty Mod 10
          If Cyfra(1) = 0 Then Cyfra(1) = 10
          W1 = Lookup(cyfra(1) , Segmenty)
          W2 = Lookup(cyfra(2) , Segmenty)
          W3 = Lookup(cyfra(3) , Segmenty)
          W4 = Lookup(cyfra(4) , Segmenty)
          Reset D1disp1
          Portb = W1
          Waitms 3
          Set D1disp1
          Reset D1disp2
          Portb = W2
          Waitms 3
          Set D1disp2
          Reset D1disp3
          Portb = W3
          Waitms 3
          Set D1disp3
          Reset D1disp4
          Portb = W4
          Waitms 3
          Set D1disp4
          Start Timer0
      Return
    
    Odbierzuart:
       Waitms 100
       Dane_uart = ""
          Do
          A_uart = Inkey()
          Dane_uart = Dane_uart + Chr(a_uart)
          B_uart = Ischarwaiting()
          Loop Until A_uart = Chr(13) Or B_uart = 0
       Odebralem = 0
       Odebralem = Instr(dane_uart , "MODAA")
       If Odebralem > 0 Then
          Godzina_uart = Mid(dane_uart , 6 , 2)
          Minuta_uart = Mid(dane_uart , 8 , 2)
          _hour = Val(godzina_uart)
          _min = Val(minuta_uart)
          End If
       Return
    
  • #2
    Dawid_20
    Level 17  
    Obsługa UART jest przerywana TIMEREM i dlatego gubi znaki. Zrób odbiór UARTU na przerwaniach, odbieraj w nim tylko pojedynczy znak i ładuj go do bufora (nie czekaj w tej funcji,aż odbierzesz wszystkie znaki), a po odebraniu końcowego znaku ustawiasz flagę, że skończył. I w pętli głównej dekodujesz sobie na spokojnie tą ramkę. Popróbuj może jeszcze ze zmianą częstotliwości odświeżania LED
  • #3
    Nagus
    Level 27  
    Zrobiłeś typowy błąd: obsługa przerwania jest za długa. Jak uart ma nie gubić znaków, skoro u ciebie obsługa przerwania trwa ponad 12ms? W tym czasie główna pętla stoi!
    Jedna z fundamentalnych zasad: w przerwaniu robimy tylko niezbędne minimum operacji. Im mniej instrukcji tym lepiej. Totalnym bezsensem jest umieszczenie całej obsługi wyświetlacza w przerwaniu. To czy kolejna cyfra wyświetli się za 3 ms czy za 3.1 ms jest naprawdę nieistotne.
    W związku z powyższym, w przerwaniu wyświetlacza powinno się znaleźć tylko ustawienie flagi "aktualizuj wyświetlacz", a cała obsługa powinna odbywać się w pętli głównej.
    W obsłudze uart naprawdę potrzebujesz tego czekania (i blokowania) przez 100 ms?

    Obsługę uart też trzeba zrobić inaczej, bo czekanie na przysłanie wszystkich znaków również blokuje program.
    Albo robisz obsługę na przerwaniach - w przerwaniu zrzucasz kolejne znaki do bufora, ustawiasz flagę że przyszło, reszta obsługi w głównej pętli,
    albo wplatasz odpytywania uart w główną pętlę. W tym przypadku wypadałoby wpleść to w procedurę opóźnień: w pętli odpytujesz uart + drobne opóźnienie, tak by razem to miało ok. 3 ms (precyzja nie jest tu istotna).
  • #4
    mirley
    Level 17  
    Witam

    W obsłudze przerwania nie powinno być żadnych waitms itp poleceń które blokują program, Wykorzystaj timer i flagi do odliczania konkretnych odcinków czasu a wszystko inne powinno leżeć w do loop.

    W przerwaniu nie ma po co wyłaczać timera, tylko trzeba zrobić dzielnik tak aby flaga była ustawiana co 4ms lub 3ms tak jak chciałeś mieć. Potem trzeba dać zmienną która sie cyklicznie zmienia wybierając na którym wyświetlaczu ma się co wyświetlać.


    Zaraz po sprawdzeniu czy jest znak w buforze możesz dać polecenie input, wtedy program poczeka na wszystkie znaki jakie powinny być w paczce.