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

[ATmega8][C] USART - rozdzielenie wysyłanych i odbieranych danych

myku1 04 Kwi 2013 22:55 3402 23
  • #1 12156658
    myku1
    Poziom 10  
    Witam,
    mam problem z danymi przesyłanymi przez usart. Projektuję kontroler obrotów wentylatorów.

    Co 1s wywoływane jest przerwanie od timera0, w którym wysyłane są dane o temperaturze i wypełnieniu PWM dwóch wentylatorów (dane w HEX, niebieskie cyfry i litery w terminalu na zdj. 2). Chciałbym, aby dane te były wpisywane w odpowiednie pola do tego przeznaczone (TextBoxy na zdj.1). Nie wiem, jak to zrobić. Może ktoś z was ma pomysł?

    Dodatkowo z programu wysyłane są dane ustawiające niektóre parametry pracy wentylatorów ([rodzaj_sterowania prędkość_wentylatora start_przy pełna_moc_przy] czarne cyfry i litery w terminalu na zdj.2). Są one wysyłane ręcznie, na żądanie użytkownika. Ich wysłanie powoduje wywołanie przerwania w uC. Jak to zrobić, aby te parametry były prawidłowo zrozumiałe i wykonane na uC? Dlaczego dane te są następnie odsyłane przez uC? Nie mam takiej funkcji w kodzie (a może o tym nie wiem :)). Chciałbym, aby dane wysłane przez użytkownika nie były powtarzane i odsyłane z powrotem.

    Macie jakieś pomysły jak rozwiązać te trudności?

    [ATmega8][C] USART - rozdzielenie wysyłanych i odbieranych danych [ATmega8][C] USART - rozdzielenie wysyłanych i odbieranych danych
    [ATmega8][C] USART - rozdzielenie wysyłanych i odbieranych danych

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #2 12156993
    piotrva
    VIP Zasłużony dla elektroda
    Ustal sobie po stronie uC jakiś format ramki, np.
    0xFF - początek ramki
    [asci]
    [asci]
    [asci]-3 cyfrowa liczba w formacie ascii - PWM1
    [asci]
    [asci]
    [asci]-3 cyfrowa liczba w formacie ascii - PWM2
    0xFE - koniec ramki
    i potem w programie rozkodowuj wg. tych znaczników
  • #4 12157584
    BlueDraco
    Specjalista - Mikrokontrolery
    Przecież to nie działa. W przerwaniu timera wpychasz kolejno do UDR kilka danych nie sprawdzając, czy można to zrobić. Jeśli chcesz nadawać w przerwaniu timera, to musisz mieć przerwanie UART i (zapewne) bufor cykliczny.
  • #5 12158274
    Badmaneq
    Poziom 23  
    Odpowiedzi w sposób łopatalogiczny na Twoje problemy znajdziesz w książce:
    "Język C. Pasja programowania mikrokontrolerów 8-bitowych" wydawnictwo Atnel.
    No może poza programem na na PC. Btw. Program na PC napisany w C# ?
  • #6 12158949
    myku1
    Poziom 10  
    BlueDraco dlaczego twierdzisz że to nie działa jak działa. Dane przychodzą takie same jak zmierzone z czujników i wyświetlone na wyświetlaczu LCD. Rozumiem, że należałoby zrobić sprawdzenie czy UDR jest puste przed wysłaniem kolejnych danych? Tylko że program działa i bez tego, jedynie nie wiem dlaczego uC odsyła parametry które otrzyma od programu z PC.

    Badmaneq niestety nie mam dostępu do tej książki aktualnie. Tak program na PC napisany w C# w Visual Studio 2010.
  • #7 12159715
    BlueDraco
    Specjalista - Mikrokontrolery
    Tak, musisz sprawdzać przed zapisem UDR i czekać na zwolnienie bufora, a czekanie w przerwaniu to na ogół przestępstwo - zwykle rozwala to działanie oprogramowania.

    Prawdopodobnie to nie uC odsyła, a Ty masz włączone echo w terminalu.

    Jeżeli gdzieś w programie robisz rzeczy, których robić nie wolno, to szukanie błędów w innych częściach programu nie ma żadnego sensu.
  • #8 12160170
    myku1
    Poziom 10  
    A co myślisz o takim rozwiązaniu? Zda egzamin takie sprawdzenie UDR:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Zmiana w programie nie wpłynęła na jego działanie, działa tak samo jak przed nią.

    Echo w terminalu? Która funkcja była by od tego?

    Sprawdzałem w hyperterminalu i putty, i one nie obsługują transmisji z uC. Hyperterminal pokazuje przychodzące dane w formie znaczków. Wszystko natomiast działa z terminalem zrobionym w moim programie PC który służy do komunikacji.
  • #9 12160235
    BlueDraco
    Specjalista - Mikrokontrolery
    Tak, tak się sprawdza gotowość, ale NIE robi się tego w przerwaniu.

    Terminal nie wie, kto nadaje do niego dane. Jest mu wszystko jedno, czy odbiera z PC, modemu, mikrokontrolera, czy czegokolwiek innego. Terminal wyświetla to, co do niego nadajesz. Jeśli nadasz literę, to ją wyświetli. Nie twórz teorii mających wyjaśnić Twoje dziwne pomysły, bo do niczego w ten sposób nie dojdziesz.

    Po co włączasz przerwania z trzech źródeł w UART, skoro ich nie obsługujesz? Przerwanie odbioru UART tak zrobione nei ma sensu - lepiej testuj gotowość i odbieraj w pętli głównej.
  • #10 12160368
    tehaceole

    Poziom 28  
    Czy nie najprostszym sposobem dla Ciebie byłoby odsyłanie przez AVR odpowiedzi na zapytania co 1s z programu?? Pisałeś, że i tak z programu coś tam sobie konfigurujesz. Więc może warto pójść tym tropem?
  • #11 12160839
    myku1
    Poziom 10  
    BlueDraco przerwanie włączone jest tylko jedno (przerwanie odebrania danych). Pozostałych nie włączałem:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    tehaceole jeśli cię dobrze rozumiem to proponujesz aby program PC wysyłał komendę (żądanie) co 1s wysłania przez uC danych które przechowują potrzebne wartości (temperaturę 1-szego czujnika, pwm dla 1-szego wentylatora, temperaturę 2-go czujnika, pwm dla 2-go wentylatora). Komenda transmisji była by znakiem który nie występuje w przesyłanych wyżej wymienionych parametrów. Przez program PC wysyłam informację o rodzaju trybu pracy kontrolera: automatyczny i ręczny, dodatkowo parametry pracy wentylatorów gdy wybrany zostanie tryb ręczny.
  • #13 12165612
    myku1
    Poziom 10  
    dondu problem mam z rozpoznawaniem wysyłanych i odbieranych danych przez uC i aplikację na PC. Jak widzisz na przemian wysyłane są dane z uC pierwszego i drugiego czujnika temperatury oraz wypełnienie pwm pierwszego i drugiego wentylatora. Nie wiem jak poprawnie wyciągnąć te dane aby wyświetlały się w odpowiednich textboxach.

    Jak napisał piotrva najpierw powinienem zaproponować format ramki i rozpoznawać kiedy się zaczyna i kończy? Jak to później umieścić w textboxie?
    Obecnie wysyłanie wygląda tak co 1s: 23 3 25 5 [temp. 1 czuj. | pwm 1 went. | temp. 2 czuj. | pwm 2 went]

    Dodatkowo dane wysyłane są przez aplikację do uC. Jak to poprawnie wykonać? Też zaproponować format ramki? Jak później rozkodować ramkę przez uC żeby przypisał odpowiednie wartości do funkcji?
    Obecnie wysyłanie wygląda tak: 102 40 30 80 104 50 45 90 [komenda: praca ręczna | pwm 1 went. | temp. przy której startuje 1 went. | temp. przy której 1 went. działa na max | komenda: praca ręczna | pwm 2 went. | temp. przy której startuje 2 went. | temp. przy której 2 went. działa na max]
  • #14 12174426
    myku1
    Poziom 10  
    Witam ponownie. Poradziłem już sobie z odbieraniem i oddzielaniem danych przesyłanych z uC do odpowiednich texboxów.

    Zrobiłem tak jak sugerowaliście: uC przesyła poprawnie sformatowaną ramkę z której właściwie odczytuje dane, sprawdzam zajętość UDR (nie robię tego w przerwaniu tylko wystawiam w nim flagę, a reszta wykonywana jest w pętli while.

    Jedno nie daje mi spokoju. Cały czas otrzymuję informację zwrotną danych wysłanych do uC. Widać to w terminalu wykonanym w moim programie. W hyperterminalu i putty takie zjawisko nie występuje. Nie jest to odpowiedź uC ponieważ testowałem go z nieaktywną linią RX.
    Jest to problem ponieważ zakłóca mi prawidłowy odczyt w pierwszym textboxie (patrz zdjęcia). Co ciekawe dane które wysyłam są typu dziesiętnego np. 102 20 40 80 104 20 40 80, a terminal otrzymuję informację zwrotną tych samych liczb tylko że zapisaną w char kodzie f (Ph (P

    [ATmega8][C] USART - rozdzielenie wysyłanych i odbieranych danych [ATmega8][C] USART - rozdzielenie wysyłanych i odbieranych danych
  • #15 12174466
    BlueDraco
    Specjalista - Mikrokontrolery
    Co to znaczy "dane które wysyłam są typu dziesiętnego"? Pokaż kod programu na ATmega. Procesor nie wie, co to jest "typ dziesiętny" - on zna wyłącznie liczby binarne.
    Zapewne wysyłasz bajt o wartości dziesiętnej 102, czyli szesnastkowej 66, co terminal wyświetla jako literę 'f'.
  • #16 12174498
    myku1
    Poziom 10  
    Kod programu

    Kod: text
    Zaloguj się, aby zobaczyć kod
  • #17 12175059
    BlueDraco
    Specjalista - Mikrokontrolery
    Masz bezsensowne i zbędne przerwane odbioru UART oraz źle napisaneprzerwanie nadawania, które jest w kółko obsługiwane, bo nie usuwasz przyczyny jego zgłoszenia ani nie blokujesz go, kiedy nie ma nic do wysłania.

    Wyłącz przerwanie TX tuż przed wysłaniem ostatniego bajtu w procedurze obsługi przerwania. Włącz przerwanie TX kiedy masz gotowy bufor z danymi do wysłania.

    To też jest ciekawe:
    if(pomiary[z]==0){ //czy to koniec takstu w tablicy
    pomiary[z] = 0; //znak końca ciągu tekstu w tablicy
  • #18 12175210
    myku1
    Poziom 10  
    Dane z przerwania RX odbioru Uart jeszcze nie są obsługiwane ale będą, dlatego przerwanie jest aktywne lecz nie wykończone.

    Co do ciekawostki:
    if(pomiary[z]==0){ //czy to koniec takstu w tablicy
    pomiary[z] = 0; //znak końca ciągu tekstu w tablicy
    zostało z poprzednich prób i zapomniałem usunąć. Ostatecznie funkcja będzie wyglądać:

    void wyslij_pomiary(void){

    //funkcja rozpoczyna wysyłanie, wysyłając pierwszy znak znajdujący się
    //w tablicy pomiar[]. Pozostałe wyśle funkcja przerwania,
    //która zostanie wywołana automatycznie po wysłaniu każdego znaku.

    //Zaczekaj, aż bufor nadawania będzie pusty
    while (!(UCSRA & _BV(UDRE)));

    //bufor jest pusty można wysłać pierwszy znak
    UDR = pomiary[0]; //wyślij pierwszy znak
    }

    Przyczyna przerwania TX jest usuwana. Jest to flaga wyslij_flaga która jest zerowana po jej wywołaniu przez timer odmierzający 1s. To jest włączenie przerwania.

    Są dwie flagi wyslij_flaga i wyslano_flaga więc łatwo o pomyłkę. Za wyłączenie przerwania TX odpowiada druga flaga.
  • #19 12175223
    dondu
    Moderator na urlopie...
    Widzę, że wykorzystałeś prawie w całości kod z linku, który Ci podałem - dobrze, bo po to go opublikowałem :)

    BlueDraco pisząc o bezsensownym przerwaniu z odbioru, ma na myśli to, że ono właściwie nic nie robi poza ustawieniem flagi i odczytem odebranego bajtu. Równie dobrze więc można więc w pętli głównej sprawdzać flagę odbioru i tam odczytać odebrany bajt. W artykule, z którego pobrałeś kod przerwanie od odbioru danej występowało, ponieważ jest to kod rozwojowy do modyfikacji przez użytkowników.

    BlueDraco napisał:
    ... oraz źle napisane przerwanie nadawania, które jest w kółko obsługiwane, bo nie usuwasz przyczyny jego zgłoszenia ani nie blokujesz go, kiedy nie ma nic do wysłania.

    Wyłącz przerwanie TX tuż przed wysłaniem ostatniego bajtu w procedurze obsługi przerwania. Włącz przerwanie TX kiedy masz gotowy bufor z danymi do wysłania

    W oryginale kod miał na stałe zainicjowaną wysyłkę, czekając na podanie nowych danych do wysyłki, dlatego nie ma takiej potrzeby. Nadawanie zatrzymuje się samoistnie, gdyż w momencie gdy wysłany zostanie ostatni bajt, nie jest podawany do wysyłki następny.


    BlueDraco napisał:
    To też jest ciekawe:
    if(pomiary[z]==0){ //czy to koniec takstu w tablicy
    pomiary[z] = 0; //znak końca ciągu tekstu w tablicy

    Słuszna uwaga BlueDraco - z oryginały usunąłeś część tego fragmentu i teraz stał się on masłem maślanym.

    EDIT: Pisaliśmy równocześnie :)
  • #20 12175252
    myku1
    Poziom 10  
    Tak by wyglądało "przerwanie RX" w pętli głównej:

    if(bit_is_set(UCSRA,RXC))
    {
    odb_x=UDR;
    odb_flaga = 1;
    }

    Następny etap pracy to odbiór danych przez uC z ustawieniami pracy wentylatorów użytkownika, a nie jak dotąd liczonymi ze wzoru w uC.
  • #21 12175589
    BlueDraco
    Specjalista - Mikrokontrolery
    I wciąż to samo...

    Jeślłi odbierasz w pętli głównej, to wystarczy:
    if (przyszedł bajt)
    obrób go

    i żadne znaczniki informujące o tym, że bajt przyszedł, nie są potrzebne.

    Zastanówcie się Koledzy, co się będzie działo, kiedy wrzucicie do UDR ostatni bajt do nadania. Kto i kiedy skasuje zgłoszenie przerwania TXD po wysłaniu tego bajtu? W obsłudze przerwania to nie nastąpi, więc przerwanie pozostanie zgłoszone i będzie obsługiwane na okrągło - patrz granica stron 137/138 aktualnej wersji (aa) doc2486.pdf
    W związku z tym nie ma też sensu nadawanie pierwszego bajtu z bufora inaczej, niż w przerwaniu.
  • Pomocny post
    #22 12175628
    dondu
    Moderator na urlopie...
    BlueDraco napisał:
    Zastanówcie się Koledzy, co się będzie działo, kiedy wrzucicie do UDR ostatni bajt do nadania. Kto i kiedy skasuje zgłoszenie przerwania TXD po wysłaniu tego bajtu? W obsłudze przerwania to nie nastąpi, więc przerwanie pozostanie zgłoszone i będzie obsługiwane na okrągło - patrz granica stron 137/138 aktualnej wersji (aa) doc2486.pdf


    Flaga przerwania TXC jest gaszona automatycznie w momencie wejścia w przerwanie od zakończenia nadawania:

    Cytat:
    When the Transmit Compete Interrupt Enable (TXCIE) bit in UCSRB is set, the USART Transmit
    Complete Interrupt will be executed when the TXC Flag becomes set (provided that global interrupts
    are enabled). When the transmit complete interrupt is used, the interrupt handling routine
    does not have to clear the TXC Flag, this is done automatically when the interrupt is executed.

    Gdy zostanie nadany ostatni bajt wystąpi przerwanie USART_TXC_vect tak jak przy każdym poprzednim bajcie. Jednakże ponieważ ten bajt jest ostatni, to zawarty w funkcji przerwania if() wykona jedynie:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    czyli po wyjściu z funkcji obsługi tego przerwania, zostajemy ze zgaszoną flagą TXC i zakończonym wysyłaniem danych. Czyli posprzątane jest poprawnie :)

    Czy o to Ci chodziło?

    A program źródłowy z linku działa tak:



  • Pomocny post
    #23 12175873
    BlueDraco
    Specjalista - Mikrokontrolery
    Ok, nie zauważyłem, że mowa o przerwaniu od TXC, a nie od TXRE. Macie rację... Poniekąd...

    A nie zauważyłem, bo używanie TXC do czegokolwiek poza wyłączaniem/przełączaniem transceivera jest mało sensowne. Do nadawania danych normalnie służy przerwanie opróżnienia UDR - wtedy nie trzeba się łapać lewą ręką za prawe ucho i nadawać pierwszego bajtu inaczej niż kolejnych, tak, jak się to robiło kiedyś w fatalnym 16450 (zresztą bezsensownie skopiowanym przez NXP do układów serii LPC1xxx, więc problem istnieje i współcześnie) i jak to jest zrobione w tym programie.
  • #24 12179496
    myku1
    Poziom 10  
    Witam koledzy i wszystkim dziękuje za okazaną pomoc. Poradziłem sobie już z odbieraniem danych na komputerze oraz pozbyłem się "echa" w terminalu.

    Dzisiaj usiadłem do pracy nad odbieraniem danych na uC. Chce zastosować kod poniżej wykorzystujący bufor cykliczny, aby przetrzymywać całą ramkę wysłaną z komputera.

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Ramka składa się z 8 pozycji np. 102 22 45 90 104 10 32 80. W programie wygląda to tak:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Problem polega na tym że gdy wyśle dane z komputera to spełnia się warunek tmp_head == UART_RxTail //wąż zaczyna zjadać własny ogon (sygnalizowane przez wyświetlenie na lcd "Dane nadpisane"). Nie powinno się to dziać dla 64 bajtowego bufora. W czym jest błąd?
REKLAMA