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

Atmega8 C - UART wysyła tylko 8 bajtów, mimo ustawienia 25 w WriteUART

daniel93 01 Mar 2013 16:43 2706 20
REKLAMA
  • #1 12003039
    daniel93
    Poziom 29  
    Mam takie funkcje do wysyłania danych:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

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


    Niestety co bym nie robił, to UART wysyła tylko 8 bajtów. Nawet polecenie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Powoduje wysłanie tylko 8 bajtów :(
    Wielkość tablicy buffn to 50x unsigned char.
  • REKLAMA
  • #2 12003367
    BlueDraco
    Specjalista - Mikrokontrolery
    1. Pokaż cały program, a przynajmniej wszystko, co ma związek z transmisją.

    2. Zmienna Licznik jest zbędna - inkrementuj wskaźnik i dekrementuj BufLen, będzie prościej, szybciej i łatwiej.
  • #3 12003591
    daniel93
    Poziom 29  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Jaki wskaźnik?
  • #4 12003868
    Andrzej__S
    Poziom 28  
    Zacznij od zmiany nazwy parametru funkcji (buffn):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Nie może być taka sama jak nazwa zmiennej globalnej:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #5 12004092
    BlueDraco
    Specjalista - Mikrokontrolery
    1. Masz źle podeklarowane funkcje - braki w listach argumentów.
    2. Używasz wielokrotnier tych samych nazw - to niby nie błąd, ale ciężko zapanować nad takim programem.

    3. Masz całkowicie źle napisaną obsługę przerwania RX. Wyświetlasz coś, liczysz CRC i nadajesz długie ciągi bajtów w przerwaniu - takich rzeczy nie wolno robić.

    Ale....

    To nie na tym polega błąd. Prawdopodobnie transmituje się tyle, ile trzeba, tylko program, który to odbiera (na PC?) źle wyświetla odbierane dane. Tam szukaj błędu.
  • #6 12011755
    daniel93
    Poziom 29  
    BlueDraco napisał:
    3. Masz całkowicie źle napisaną obsługę przerwania RX. Wyświetlasz coś, liczysz CRC i nadajesz długie ciągi bajtów w przerwaniu - takich rzeczy nie wolno robić.


    Czyli w jaki sposób powinienem to poprawić zeby było dobrze?
  • #7 12011872
    BlueDraco
    Specjalista - Mikrokontrolery
    Nie wyświetlać, nie liczyć CRC i nie nadawać ciągu bajtów przez UART w obsłudze przerwania Rx UART. Tzn, CRC ew. można liczyć, ale po każdym bajcie. Wyświetlać nie można wcale, a nadawać można jeśli użyjesz przerwania Tx i bufora cyklicznego na dane, a w przerwaniu Rx będziesz je tylko wstawiał do bufora,
  • #8 12019012
    _Robak_
    Poziom 33  
    https://www.elektroda.pl/rtvforum/topic1327746.html#6598326
    Tutaj masz odbieranie danych z uarta właśnie na zasadzie bufora cyklicznego. Program już może ma swoje lata ale wiesz że przetestowany;)
    Nadawanie przez rzerwanie zrobisz na bazie odbioru - działa równie dobrze ale akurat nie umiem znaleźć kodu;)

    Edit: Zmieniłem linka bo chyba był mylący
  • #9 12019506
    BlueDraco
    Specjalista - Mikrokontrolery
    _Robak_: Ten kod (odbiornika) nie wygląda na testowany ani działający (błędna reakcja, a raczej brak obsługi przepelnienia bufora), a kodu nadajnika tam nie zauważyłem wcale. :)
  • REKLAMA
  • #11 12020807
    BlueDraco
    Specjalista - Mikrokontrolery
    Raczej chiński oryginał. Podróbka to mogłaby być np. amerykańska... :)
  • #12 12020843
    _Robak_
    Poziom 33  
    BlueDraco napisał:
    _Robak_: Ten kod (odbiornika) nie wygląda na testowany ani działający (błędna reakcja, a raczej brak obsługi przepelnienia bufora), a kodu nadajnika tam nie zauważyłem wcale. :)


    Rozumiem że nie zajrzałeś dalej jak na pierwszy post?
  • #13 12021431
    BlueDraco
    Specjalista - Mikrokontrolery
    Akurat przejrzałem wszystkie posty i kodu obsługi nadawania na przerwaniach nie zauważyłem. Może to i lepiej. ;)
  • REKLAMA
  • #14 12021955
    _Robak_
    Poziom 33  
    BlueDraco napisał:
    Akurat przejrzałem wszystkie posty i kodu obsługi nadawania na przerwaniach nie zauważyłem. Może to i lepiej. ;)


    W takim razie z chęcią się dowiem dlaczego ten kod nie ma prawa działać.
  • #15 12022331
    BlueDraco
    Specjalista - Mikrokontrolery
    Już napisałem - zgłupieje przy przepelnieniu bufora, a powinien wtedy ignorować kolejne znaki.
    Ponadto - i to już poważniejsza sprawa - uart_get() nie blokuje przerwań podczas dekrementacji rx_counter - kryminał, bo jeśli po odczycie z pamięci, a przed zapisem zinkrementowanej wartości przyjdzie przerwanie odbiornika, to mamy duuuży kłopocik.

    No i ciekawostka - co robi uart_get kiedy bufor jest pusty? Przecież to nie ma prawa działać.
  • #16 12023278
    _Robak_
    Poziom 33  
    Cytat:

    Już napisałem - zgłupieje przy przepelnieniu bufora, a powinien wtedy ignorować kolejne znaki.

    Tak? O kurczę a ja myślałem że właśnie nie o to mi chodziło. Chyba powinienem się Ciebie wtedy spytać co chcę zrobić.

    Cytat:

    Ponadto - i to już poważniejsza sprawa - uart_get() nie blokuje przerwań podczas dekrementacji rx_counter - kryminał

    W zasadzie można by to dodać, być może w późniejszej wersji to było. Ale napisanie żeby do tej funkcji dodać kłóciłoby się z charakterem kolegi żeby tylko się "popisać" na forum. W moim przypadku nie było takiej potrzeby.
    Cytat:

    No i ciekawostka - co robi uart_get kiedy bufor jest pusty? Przecież to nie ma prawa działać.

    Nie ma prawa! A jednak działa:( Kolega zamiast się spytać czemu działa woli stać przy swoim i udawać najmądrzejszego.


    Wracając do tematu. Kolega Daniel jest na forum duużo dłużej niż Ty, więc zakładam że nie trzeba mu dać rozwiązania na tacy tylko pomocy którą wykorzysta we właściwy sposób. Dałem koledze przykład (dobry i sprawdzony) jaki ja wykorzystałem do moich potrzeb i tylko człowiek mocno ograniczony wykorzysta takie zasoby bez namysłu.
  • #17 12023529
    BlueDraco
    Specjalista - Mikrokontrolery
    No to podsumujmy:

    - uart_getc() zwraca znak z bufora, dekrementuje licznik znaków i przesuwa wskaźnik w buforze nawet wtedy, gdy bufor jest pusty.

    - W przypadku przepełnienia bufora nowe znaki będą przyjmowane, a licznik będzie inkrementowany. Przy buforze na 4 bajty po nadaniu ciągu "123456" odbiorca odbierze "345634".

    - Od czasu do czasu nastąpi zgubienie znaku poprzez jego niezliczenie, rx_count będzie miał wartość 0, a znak będzie w buforze i przy wywołaniiu uart_getc() ten znak zostanie zwrócony, bo uart_getc zawsze coś zwraca, nawet kiedy bufor jest pusty. Gdyby konsument przed wywołaniem uart_getc sprawdzał licznik znaków - nie dowie się, że w buforze jest znak. Kiedy odbierzemy następny znak, kolejne wywołanie uart_getc zwróci poprzedni znak, nowy będzie w buforze, a licznik znaków będzie wyzerowany. Co jakiś czas liczba znaków w buforze, które pozostaną niezauważone, będzie rosła.

    - Gdyby kod uzupełnić o sensowną reakcję na przepełnienie, to i tak czasem znaki będą gubione poprzez zamazanie najstarszego znaku w buforze wskutek błędnej kolejności akcji w uart_getc().

    Kod, który pokazałeś, nie jest więc ani dobry, ani sprawdzony. Losowo gubi znaki, zamazuje znaki, zwraca nieprawidłowe znaki, a zmienna rx_counter nie daje żadnej wiarygodnej informacji o tym, czy w buforze są jakieś znaki i ile ich jest.

    Kiedyś popłeniłem kod obsługi UART, który miał tylko jeden z tych błędów, które opisuję powyżej. Błąd pojawiał się raz na kilkadziesiąt minut działania urządzenia przy średnim strumieniu danych rzędu 300 bajtów na minutę.

    Być może rzeczywiście jedynym problemem jest mój paskudny charakter, bo przecież będą takie sytuacje, kiedy ten kod będzie działał. W końcu urządzenie nie musi działać cały czas dobrze.- Weźmy np. takie hamulce w samochodzie. Jak zadziałają 9 razy na 10, to można powiedzieć, że działają i nie ma się co czepiać - dla początkującego kierowcy powinny wystarczyć... ;)
  • #18 12023758
    _Robak_
    Poziom 33  
    Cytat:


    - uart_getc() zwraca znak z bufora, dekrementuje licznik znaków i przesuwa wskaźnik w buforze nawet wtedy, gdy bufor jest pusty.

    Dokładnie tak. Dlatego przed odebraniem znaku należy sprawdzić czy jest znak do odbioru.

    Cytat:

    - W przypadku przepełnienia bufora nowe znaki będą przyjmowane, a licznik będzie inkrementowany. Przy buforze na 4 bajty po nadaniu ciągu "123456" odbiorca odbierze "345634".

    Zgadzam się w stu procent, program działa zgodnie z wolą autora. Jeśli nie z Twoją wolą to już nie mój problem:)

    Cytat:

    Kiedyś popłeniłem kod obsługi UART, który miał tylko jeden z tych błędów, które opisuję powyżej. Błąd pojawiał się raz na kilkadziesiąt minut działania urządzenia przy średnim strumieniu danych rzędu 300 bajtów na minutę.


    No widzisz a "fatalny" kod który ja popełniłem działał niezawodnie przez kilka tysięcy godzin. Bez ani jednej wpadki że urządzenie poszło w maliny. A to Ci rewelacja. Oczywiście stosowne zabezpieczenia były w dalszej części programu. Jeśli chcesz o nich porozmawiać zapraszam na priv.

    Cytat:

    Weźmy np. takie hamulce w samochodzie. Jak zadziałają 9 razy na 10, to można powiedzieć, że działają i nie ma się co czepiać - dla początkującego kierowcy powinny wystarczyć... ;)

    Rozumiem że nie posiadasz większej wiedzy o walidacji softu w Automotive stąd to głupie stwierdzenie?

    Nie ma sensu aby przedłużać tą dyskusję. Nie dałem uniwersalnego kody ready to use tylko przykład który można powiększać o dodatkowe featury. Jedyne co można należy dodać niezależnie od wszystkiego to blokadę przerwań podczas odbierania znaku.
  • #19 12024044
    BlueDraco
    Specjalista - Mikrokontrolery
    No prawie dobrze, tylko:

    - rx_counter może mieć wartość 0 kiedy w buforze są dane, nie można więc na jego podstawie decydować o czymkolwiek.

    - Jeśli błąd może się zdarzyć, to kiedyś się zdarzy. Nieważne, przez ile godzin programowi udało się pracować bez błędu. Nawet jeśli protokół transmisji gwarantuje, że bufor się nie przepełni, nic nie gwarantuje, że rx_counter zawiera poprawną wartość - to w ogólnym przypadku nie działa, a czasem udaje się, że zadziała.

    - Przez ile godzin testuje się programy samochodowe, żeby stwierdzić, że działają poprawnie? Czy program, w którym przy analizie kodu łatwo można wskazać możliwość błędu bez wystąpienia jakichś mało prawdopodobnych okoliczności zewnętrznych, czyli przy typowym scenariuszu pracy, uznaje się w "testach automotive" za poprawny, jeśli błąd nie wystąpił w wielogodzinnym teście? Jako biegły w tym zakresie na pewno możesz mnie oświecić, żebym nie wstawiał więcej "głupich uwag" o weryfikacji poprawności.

    Nie dałeś "przykładu do ewentualnej rozbudowy". Dałeś program źle skonstruowany, z masą błędów widocznych na pierwszy rzut oka i z komentarzem, że jest poprawny.
    Wykazałem, że program nie jest poprawny nawet w przypadku, gdy nie występują okoliczności nietypowe (jak możliwość przepełnienia bufora), a przy przepełnieniu głupieje całkiem.

    Nie wiem, jak możesz zabezpieczyć się w Twoim programie przed błędną wartością rx_counter oraz przed błędną wartością wskaźnika bufora, który np. w przypadku, gdy w buforze jest jeden bajt, wskazuje inny bajt niż ten, który ma być czytany z bufora.
    Można oczywiście resetować mikrokontroler co kilka minut, a może sekund, wiedząc, że co jakiś czas program będzie na pewno szedł w maliny, ale to chyba nie jest poważne rozwiązanie.

    Niestety, są w tym programie jeszcze dwa inne błędy, o których nie napisałem, więc samo zablokowanie przerwań na czas modyfikacji rx_counter nie pomoże, chociaż przy braku sytuacji nietypowych takie rozwiązanie czasem z grubsza zadziała.

    Dawno temu przejechałem się sam na takich samych błędach w obsłudze transmisji, jakie masz w tym programie. Od tamtej pory m.in. przestałem używać licznika bajtów w buforze, bo więcej z tego kłopotu, niż pożytku.
  • #20 12024346
    _Robak_
    Poziom 33  
    Tak jak pisałem PW, proszę wkleić jedyny słuszny kod i resztę możemy omówić na PW.
  • #21 12024925
    BlueDraco
    Specjalista - Mikrokontrolery
    Chcesz - to masz. Wbrew temu, co piszesz, kod nie jest "jedynie słuszny" - znam jeszcze słuszniejszą wersję, a można napisać parę konkurencyjnych również z licznikiem bajtów - ale na oko nie ma oczywistych błędów i nie wymaga blokowania przerwań.

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