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

AVR - Jak wykryć zakończenie transmisji RS485 bez użycia delay?

Marek_Gorecki 25 Cze 2016 11:08 1809 28
  • #1 15767264
    Marek_Gorecki
    Poziom 16  
    Witam,
    Używam RS485 do transmisji danych.
    Transmisja wygląda następująco ( w uproszczeniu):

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



    Zauważyłem, że musi być po printfie krótki delay, aby dane zdążyły wyjść.
    I teraz pytanie.
    Czy da się to łatwo przerobić, aby ten delay usunąć.
    Czy jest jakaś flaga , która informuje o tym, że już wszystko wyszło?
  • #2 15767271
    excray
    Poziom 41  
    Z pewnością. Po pierwsze sprawdzasz czy cała tablica została wysłana a po drugie czy USART zakończył nadawanie ostatnio przekazanego mu znaku.
  • #3 15767297
    Marek_Gorecki
    Poziom 16  
    Ale jak to zrobić, używając printfa?
  • Pomocny post
    #4 15767311
    excray
    Poziom 41  
    Nie wiem jaka jest implementacja. Jak sprzętowa to po transmisji sprawdzać stan flagi TXC - zamiast delay wstawić coś w stylu: while(!(UCSRA & (1<<TXC)));. Ewentualnie nie używać printfa tylko skrobnąć własna procedurę do wysyłania danych przez USARTa?
  • #5 15767384
    Marek_Gorecki
    Poziom 16  
    Jak wstawiłem while(!(UCSRA & (1<<TXC)));
    i od razu przełączyłem na nadawanie to ucina mi kilka znków.
  • #6 15767390
    excray
    Poziom 41  
    A jaki masz mikroprocesor?
  • Pomocny post
    #7 15767460
    jnk0le
    Poziom 18  
    Jeśli nie angażujesz przerwań w komunikację to flagę TXC musisz ręcznie czyścić po każdej pętli while(!(UCSRA & (1<<TXC)));

    Cytat:
    Bit 6 – TXCn: USART Transmit Complete
    This flag bit is set when the entire frame in the Transmit Shift Register has been shifted out and
    there are no new data currently present in the transmit buffer (UDRn). The TXCn Flag bit is auto-
    matically cleared when a transmit complete interrupt is executed, or it can be cleared by writing
    a one to its bit location.
  • #8 15767502
    Marek_Gorecki
    Poziom 16  
    Procesor to ATMEGA 644P

    Zrobiłem tak:

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

    ale dalej giną ostatnie znaki.
    Jak dołożę opóźnienie 3ms to idzie wszystko.
  • #9 15767953
    Konto nie istnieje
    Konto nie istnieje  
  • #10 15768084
    Marek_Gorecki
    Poziom 16  
    Piotrus_999 napisał:
    sprawdzaj jeszcze czy bufor jest pusty.


    ale jak to zrobić w przykładzie powyższym?
  • #11 15768143
    Konto nie istnieje
    Konto nie istnieje  
  • #12 15768205
    grko
    Poziom 33  
    Cytat:

    Zauważyłem, że musi być po printfie krótki delay, aby dane zdążyły wyjść.
    I teraz pytanie.
    Czy da się to łatwo przerobić, aby ten delay usunąć.
    Czy jest jakaś flaga , która informuje o tym, że już wszystko wyszło?


    Możesz wyłączyć buforowanie dla stdout na początku programu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    albo po każdym printf:

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



    Cytat:

    Jest jeszcze inna zagwozdka: vprintf ma swój bufor wypełniany przez vnsprinf - następne wywołanie go "wiciera". Wszystko zależy od implementacji.


    "Wyciera" powiadasz. Mógłbyś ten cudowny efekt opisać?
  • #13 15768219
    Konto nie istnieje
    Konto nie istnieje  
  • Pomocny post
    #14 15769471
    jnk0le
    Poziom 18  
    To może tak:

    1. Z czym się komunikujesz ?
    2. Warto by pokazać reszte kodu, szczególnie jeśli jest to oparte na jakiejś bibliotece a nie najprostszym pollingu.
    3. Jeśli o bibliotekach mowa, to możesz sprawdzić czy z moją biblioteką będzie to działać prawidłowo. (rs485 wymaga parę zmian w configu)
  • Pomocny post
    #15 15769701
    tmf
    VIP Zasłużony dla elektroda
    @Marek_Gorecki Jeżeli korzystasz z funkcji xprintx to i tak musisz zaimplementować funkcje odpowiedzialne za wysyłanie pojedynczych znaków. I to w tych funkcjach po prostu dodaj oczekiwanie na zakończenie transmisji. W efekcie, kiedy printf zakończy się wykonywać będziesz miał pewność, że możesz od razu przełączyć się na odbiór. Ceną tego będzie nieco wolniejsze wysyłanie znaków. Alternatywnie delay po print też nie jest złe - uwzględniając głębokość nadajnika UART w AVR. Inna możliwość to dodanie sprawdzenia flagi pustego bufora nadajnika, ale to zasadniczo jest równie uciążliwe jak delay.
  • #16 15770259
    Marek_Gorecki
    Poziom 16  
    Piszę w Codevision.
    U mnie funkcja printf korzysta z takiej funkcji wysyłającej jeden znak (aby móc wysyłać na różne uarty):

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


    Czy da się coś tu dodać, aby zrobić to opóźnienie na wysłanie?
  • #17 15770281
    tmf
    VIP Zasłużony dla elektroda
    Tak, dodaj po zapisie do UDR sprawdzanie bitu TXC w rej. UCSR. Dzięki temu funkcja nie zakończy się dopóki USART nie zakończy wysyłania wszystkiego co jest. Pamiętaj tylko, że trzeba ręcznie skasować za każdym razem TXC poprzez wpisanie na jego pozycję wartości 1. Wadą tego rozwiązania jest to, że transmisja będzie ciut wolniejsza (nie wykorzystujesz bufora), ale za to jest to proste do implementacji.
  • #18 15770321
    Marek_Gorecki
    Poziom 16  
    Dziękuje Panie Tomku.
    Poprawiłem program, czy tak według Pana będzie dobrze? :

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


    Dodano po 10 [minuty]:

    Sprawdziłem.
    Nadal urywa dwa ostatnie znaki.
    Chyba użyje delaya.
    Problem dotyczy zawsze dwóch ostatnich znaków.
    Wydaje mi się, że funkcja printf wykonuje wysyłke wszystkich znaków, za wyjątkiem dwóch ostatnich , które lądują w buforze.
    Jeśli pierwszą instrukcja po printfie jest przełacznik z nadajnika na odbiornik, to te dwa znaki giną.
  • #19 15770411
    Konto nie istnieje
    Konto nie istnieje  
  • #20 15770455
    Marek_Gorecki
    Poziom 16  
    Piotrus_999 napisał:
    U mnie działa taka kolejność - tak przetestowałem dla zabawy:

    1. Sprawdzaj czy bufor jest pusty
    2. Zeruj TXC - pisząc jedynkę.
    3. Pisz dane
    4. czekaj na TXC


    Czyli tak:


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


    ?
  • #21 15770475
    Konto nie istnieje
    Konto nie istnieje  
  • #22 15770506
    Marek_Gorecki
    Poziom 16  
    Masz rację.
    Ten bit to UDRE0.
    Czyli ten zapis ma być tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #23 15770574
    Konto nie istnieje
    Konto nie istnieje  
  • #24 15771611
    Marek_Gorecki
    Poziom 16  
    Niestety ,ale nie działa.
    Widać tylko pojedyńcze znaki i to uszkodzone - takie krzaczki.
    Chyba najlepsza metodą będzie delay 3ms.
  • #25 15771681
    excray
    Poziom 41  
    Najlepszą metodą będzie napisanie własnej procedury do wysyłania danych po RSie.
  • #26 15771693
    Marek_Gorecki
    Poziom 16  
    excray napisał:
    Najlepszą metodą będzie napisanie własnej procedury do wysyłania danych po RSie.


    Tak, ale ja bardzo mocno używam zalety printfa.
    Wysyłam mieszankę tekstowo liczbową, wpisuje wartości w hexach itp.
    Idealnie nadaje mi się do tego printf.
    Inaczej bardzo skomplikuje mi się kod.
    Wiem, że printf jest bardzo "ciężki", ale mam dużo wolnego miejsca w procku.

    Spróbuje jeszcze sprintfa , może to jest lepsza droga.

    pozdrawiam
  • #27 15771760
    grko
    Poziom 33  
    Piotrus_999 napisał:
    GrzegorzKostka napisał:
    "Wyciera" powiadasz. Mógłbyś ten cudowny efekt opisać?

    Opisałem prostymi słowy.

    GrzegorzKostka napisał:
    Możesz wyłączyć buforowanie dla stdout na początku programu:


    Nie mozesz bo nie jest buforowany - w takim sensie jak w "normalej" bibliotece standardowej

    Niestety fflush na AVR-ach nie robi tego o czym myslisz

    Cytat:
    int fflush( FILE * stream). Flush stream . This is a null operation provided for source-code compatibility only


    równie dobrze moze zrobić NOP-a

    Widziałem gdzieś implementacje "bogatsze" ale ich waga raczej zniechęca do użycia


    Odnosisz się do kombinacji avr-gcc + avr-libc. Autor jednak korzysta z kompilatora Codevision. Nie wiadomo czy tam stdout nie jest przypadkiem buforowany. Nie byłbym taki pewien, że nie jest.

    Odnośnie tego co napisałeś "prostymi słowy"
    Cytat:

    Jest jeszcze inna zagwozdka: vprintf ma swój bufor wypełniany przez vnsprinf - następne wywołanie go "wiciera". Wszystko zależy od implementacji.


    WTF???
  • #29 15777919
    arturt134
    Poziom 27  
    Generalnie, zamiast funkcji printf ja używam funkcji sprintf, która pisze do bufora. A czy bufor wyślę przez UART-a, USB, SPI czy cokolwiek innego, to już sprawa drugorzędna. Najlepiej rozdzielić drukowanie od wysyłania, wtedy jest łatwiej.
REKLAMA