Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Moduły do transmisji bezprzewodowej przez UART

20 Mar 2009 14:54 5807 23
  • Poziom 9  
    Witam!

    Od pewnego czasu bawię się układami do transmisji bezprzewodowej komunikujące się z uC poprzez port UART. Konkretnie mam na myśli HM-R868S i HM-T868S ze sklepu TME .
    Mam pytanie: czy ktoś może próbował kiedyś wprowadzać jakąkolwiek ochronę przed błędami/przekłamaniami w takiej transmisji przez UART?
    Ja wymyśłiłem kilka algorytmów dzielących bajt na dwie części i przesyłających w każdej ramce tylko jedną część bajtu, CRC, oraz numer ramki (0 lub 1 w zalezności czy to młodsza czy starsza część bajtu). NIestety zabiegi tego typu nie przynoszą poprawy transmisji a raczej znacznie ją pogarszają wprowadzając jakieś losowe liczby.
  • Poziom 22  
    Witam!
    No to mamy podobny problem, cierpie od kilku dni i nic nie mogę zdziałać :/ moduły są super proste w obsłudze, tylko że odbiornik łapie ciągle śmieci, nawet gdy nadajnik milczy... Szukam metody żeby je jakoś z synchronizować. Wysyłając kilka bajtów w paczce trzeba mieć niesamowite szczęście żeby odebrać je w całości, zawsze kawałek paczki jest obcięty.
  • Poziom 43  
    Najlepiej to raz zsynchronizować ramkę i potem odebrać całą, a nie synchronizować każdy bajt tak jak ma to miejsce w UART-cie.

    Wtedy dane nie będą obcięte czy jak kto to tam nazywa, lecz co najwyżej zmienione.
    Ale zawsze każdy bajt będzie na swoim miejscu, i każdy bit na swoim miejscu.
    Oczywiście takie przesyłanie wymaga porządnej zgodności częstotliwości taktowania obydwu układów (nadajnika i odbiornika strumienia bitów).
    O ile RS (UART) przy 8-miu bitach dopuszcza powiedzmy błąd do 4%, to przesłanie powiedzmy 16B czyli 128b wymaga błędu poniżej 0,25%.

    Na szczęście nawet zwykłe rezonatory kwarcowe są na tyle dokładne żeby spokojnie przesłać strumień 10000..20000b.
    Wniosek po prostu taki, że procesor wysyłający i odbierający muszą być taktowane z generatora na rezonatorze kwarcowym a nie z wewnętrznego generatora RC.

    Mój patent jest taki, żeby najpierw przesłać kilka zboczy w dużych odstępach czasu (służący do synchronizowania) a potem szybki strumień właściwych bitów danych.
    Odbiornik musi się zsynchronizować z tym początkowym powolnym strumieniem (co mu przyjdzie łatwo przy odpowienim algorytmie) po czym odebrać strumień bitów.

    Oczywiście strumień bitów trzeba zakodować nadmiarowo.

    Zastosowanie TurboKodera i takiego patentu pozwala na poprawną transmisję nawet jak co drugi bit jest przekłamany.
  • Poziom 9  
    Fajnie, że ktoś ma podobne problemy :)

    Podoba mi się pomysł Atoma. Mam jednak pytanie:
    atom1477 napisał:
    Odbiornik musi się zsynchronizować z tym początkowym powolnym strumieniem (co mu przyjdzie łatwo przy odpowienim algorytmie) po czym odebrać strumień bitów.

    W jaki sposób miałaby się dokonać ta synchronizacja? Skąd będzie wiadomo, że udało się ją już uzyskać? Powiedzmy, że będę wysyłał jakąś liczbę co 100 ms. Będzie to znana mi liczba. Gdy do odbiornika zacznie ta liczba docierać w poprawnej formie to wtedy mam założyć, że synchronizacja się udała? Przecież nie mam żadnego wpływu na pracę UARTa - ustawienie takiego samego boudrate odbiornika i nadajnika, oraz takiej samej ramki danych jest w zasadzie wszystkim co mogę zrobić w kwestii synchronizacji.
  • Poziom 43  
    No rzecz w tym że wtedy nie wykorzystuje się UARTa. A w zasadzie to tak, ale nie ten sprzętowy.
    Wiem że to trochę nie na temat, ale sam się zdziwiłem jak wiele może dać taki sposób pracy.
    Taki patent ma taką wadę, że wymaga albo 100% mocy obliczeniowej procesora (bez jakichkolwiek przerwań) albo pracy na Timerach ale wtedy to małą prędkość transmisji się osiągnie.

    Ja mam prościej, bo układ żąda odesłania danych a więc wie kiedy układ podrzędny zacznie wysyłać fragment synchronizujący.
    U Ciebie jest transmisja jednostronna tak?

    Żądanie nadawania idzie na małej prędkości, jakieś 1500baud i prawie nie ma błędów transmisji, a układ podrzędny za 10ms odsyła ramkę synchronizującą i potem bardzo szybki strumień 150000baud.
    Co ciekawe wcześniej miałem problemy z przesłaniem nawet 15kbaud (UATRem) a teraz spokojnie idzie 150kbaud.
    Niestety po pierwsze to się sprawdza przy przesyłaniu dużej ilości danych na raz, dlatego że fragment synchronizujący musi być długi a więc nie opłaca się potem wysyłać mało danych.
    Po drugie nie dopracowałem jeszcze dekodowania strumienia. Widzę że przekłamane jest maksymalnie 10…30% bitów, a to spokojnie dało by się rozkodować ale mój dekoder Viterbiego ma jakąś pluskwę chyba bo nie działa jak ilość błędów jest powyżej 5% (mimo że mam kod nadmiarowy o sprawności ½, czyli przesyłam dwa razy więcej danych. Powinno się teoretycznie dać zdekodować strumień o zaszumieniu 50%, w praktyce dużo mniej ale nie aż tak mało jak 5%).

    To strasznie nie na temat, ale może się Wam przyda.
    Na przesyłanie danych UARTem też by się znalazła rada.
    Zależy jakie chcecie osiągnąć prędkości i ile bajtów jednorazowo przesłać.
    Myślę że zamiast dzielenia ramki na dwie części z CRC lepiej zakodować to kodem Hamminga to przynajmniej da się usuwać jakieś małe błędy. CRC pozwala na usuwanie ale ma znikomą sprawność.
    A puki co to chyba nawet nie wykorzystujesz możliwości naprawiania, a tylko wybierasz te ramki gdzie CRC jest dobre.

    Przy małych wymaganiach na prędkość jedyną prosta drogą jest zmniejszenie prędkości UARTa tak aby ilość błędów była mała, powiedzmy poniżej 5% i wtedy kodować i dekodować to kodem Hamminga.

    Dodano po 40 [minuty]:

    Na początek to może trzeba wyłączyć bit parzystości i ustawić 2 bity stopu. A wysyłane bajty porozdzielać przerwAMI powiedzmy o czasie trwania 30…50% czasu trwania wysyłania jednego bajtu. Przy czym odbiornik po odebraniu każdego bajtu misi być wyłączany na czas 25…45%. Takie coś powinno trochę pomóc.
  • Poziom 22  
    Ja mam już chyba problem rozwiązany :) Nadajnik wysyła paczkę (jakieś 150b) odbiornik zaś odbiera paczkę większą (np. 200b) następnie szukam id nadajnika (powiedzmy 4b) w pierwszych 50b paczki, jeżeli id się tam znajduje to następne 146b musi być poprawne (w środku nadawania raczej nie występują błędy). Testowałem przy baud 9600, odległość nie duża ale dwa piętra i po przekątnej domu, więc trochę przeszkód jest, 0 błędów. Problem polega tylko na tym że paczkę trzeba wysyłać w pętli jakieś 5s żeby było pewne że dotarła, a odbiornik musi systematycznie szukać id w odbieranych śmieciach. U mnie to nie przeszkadza bo z transmisji będę korzystał raz na kilka dni, ale metoda odpada kiedy ktoś chce szybszej reakcji odbiornika i przesyła duże ilości danych.
  • Poziom 43  
    a_noob napisał:
    Ja mam już chyba problem rozwiązany :) Nadajnik wysyła paczkę (jakieś 150b) odbiornik zaś odbiera paczkę większą (np. 200b) następnie szukam id nadajnika (powiedzmy 4b) w pierwszych 50b paczki, jeżeli id się tam znajduje to następne 146b musi być poprawne (w środku nadawania raczej nie występują błędy).


    Nie no, myślałem że przy klasycznej transmisji UART takie coś to podstawa i że już to masz więc nawet nie wspominałem.
  • Poziom 22  
    Trochę wolno myślę ;) a tak serio to musiałem trochę bałaganu zrobić w programach bo odbiornik kożysta z danych po 13b i wysłanie kilkunastu takich paczek tą metodą baaardzo przedłuża transmisję.

    Pytanie tylko co u Włodara?
  • Poziom 43  
    To bardzo proste. Odbiornik łączy dwie paczki w jedną.
    Wystarczy że pomiędzy dwoma dobrymi paczkami pojawią sie dwie złe i zostaną zignorowane.
    Więc odbiornik połączy dwie nieodpowiednie ramki.
    Prosty przykład:

    Wysyłamy 55 i 66:

    5l__5h__6l__6h

    Dojdą:

    5l__5h__6l__6h

    Te pogrubione doszły. Pozostałe załóżmy że nie doszły. Chociaż równie dobrze może być złe CRC i wyjdzie na to samo.

    Układ ma 5l i 6h, czyli w sumie młodszą i starsza połówkę bajtu. Połączy to i wyjdzie 56.
    I stąd losowe liczby.

    Jest na to prosta rada:
    Odbiornik musi łączyć tylko dwie ramki które przyszły w małych odstępach czasu.
    Jeżeli po przyjściu młodszej połówki bajtu w ciągu czasu trwania jednej serii wysyłania nie dojdzie starsza połówka to układ musi się resetować i znowu czekać na młodsza połówkę, bo inaczej czekając na starsza połówkę doczeka się jedynie starszej połówki z nowej serii czyli z nie tej serii co trzeba.
  • Poziom 9  
    atom1477 napisał:

    Prosty przykład:

    Wysyłamy 55 i 66:

    5l__5h__6l__6h

    Dojdą:

    5l__5h__6l__6h

    Te pogrubione doszły. Pozostałe załóżmy że nie doszły. Chociaż równie dobrze może być złe CRC i wyjdzie na to samo.

    Układ ma 5l i 6h, czyli w sumie młodszą i starsza połówkę bajtu. Połączy to i wyjdzie 56.
    I stąd losowe liczby.

    Jest na to prosta rada:
    Odbiornik musi łączyć tylko dwie ramki które przyszły w małych odstępach czasu.
    Jeżeli po przyjściu młodszej połówki bajtu w ciągu czasu trwania jednej serii wysyłania nie dojdzie starsza połówka to układ musi się resetować i znowu czekać na młodsza połówkę, bo inaczej czekając na starsza połówkę doczeka się jedynie starszej połówki z nowej serii czyli z nie tej serii co trzeba.

    Oto jestem :)
    Przedstawię algorytmy, które przetestowałem korzystając ze sprzętowego UARTa:
    Ramka danych 8-bitowa, 1 bit stopu, bit parzystości

    1. 8-bitowa liczba z przetwornika A/C zostaje podzielona na dwie części - starszą i młodszą.
    Dla każdej z części jest obliczana suma CRC.
    Tworzone są dwie liczby 8-bitowe:
    L1 = 0ZZZYYYY
    L2 = 1QQQXXXX
    gdzie: XXXXYYYY stanowi naszą liczbę z przetwornika A/C, Y-ki są częścią młodszą a X-y częścią starszą
    Z-ty to CRC dla części młodszej, Q to CRC dla części starszej. 0 oznacza, że jest to liczba zawierająca część młodszą bajtu (czyli y-ki) natomiast 1 oznacza, że jest to liczba zawierająca część starszą bajtu.
    Następnie w pętli mającej 10 iteracji wysyłane są L1 i L2 na przemian.
    Odbiornik odczytuje dane i umieszcza je w buforze zawierającym 3 elementy.
    Gdy bufor zostanie zapełniony wówczas sprawdza się najstarszy bit każdej spośród trzech liczb. Jeżeli pierwsza liczba zawiera 0 na tej pozycji a druga jeden to przyjmuje się, że pierwsza jest L1 a druga L2. Jeżeli druga liczba zawiera zero a trzecia 1 to przyjmuje się, że druga to L1 a trzecia to L2. Jeżeli zaden z warunków nie jest spełniony to procedura pobierania danych do bufora jest powtarzana.
    Następnie algorytm sprawdza czy CRC przesłane jest zgodne z obliczonym - jeśli tak to składa liczbę w calość i zwraca ją, jeśli nie to nastepuje powrót do czytania danych z odbiornika.

    2. Jest podobny z ta róznicą, że CRC nie jest obliczane dla 4-bitowego kawałka 8-bitowej liczby ale dla całej liczby 8-bitowej. W moim zamyśle tego typu zmiana miała dodatkowo stanowić upewnienie, że fragment algorytmu odpowiedzialny za składanie liczby z 4-bitowych kawałków nie popełnia błedu. Sprawdzano zatem całą liczbę już po złożeniu a nie kazdy z kawałkow jeszcze zanim zapadła decyzja o tym w jaki sposób nalezy je połączyć

    3. Tworzone są dwie liczby 8-bitowe:
    L1 = XXXXYYYY
    L2 = CCCC0000
    Przy czym L1 jest to po prostu liczba z przetwornika A/C natomiast L2 jest sumą kontrolną CRC wyliczoną z L1 i umieszcozną na czterech starszych bitach, podczas gdy cztery młodsze bity to zera. Format liczby L2 jest taki, ponieważ po stroni eodbiornika algorytm musi jakoś wykrywać, która liczba jest wynikiem pomiaru a która to CRC. CRC rozpoznawane jest po tym, że 4 młodsze bity są zerami. Założyłem, że w pomiarze nigdy nie będzie sytuacji w której przetwornik zwróciłby 0, ponieważ mój projekt upoważnia mnie do takiego założenia (jest mierzone napiecie jakiejś tam baterii)
    Dzięki temu te zera oznaczają właśnie liczbę zawierającą jedynie CRC.

    Niestety kazdy z tych trzech algorytmów generuje pewne losowe liczby....
    Natomiast co ciekawe: Połączenie mikrokontrolerów przewodem zamiast radia i zastsowoanie każdego spośród trzech algorytmów daje doskonałe rezultaty. Dokonałem takiego eksperymentu, żeby mieć pewność, że nie rypnąłem się gdzieś w kodzie lub w koncepcji.

    Dodano po 5 [minuty]:

    Musze powiedzieć, że myślałem, iż te moje algorytmy są całkowicie nie do ruszenia i wszystko przewidują... a tutaj LIPA (żeby nie powiedzieć D_PA) :D:D:D:D:D
    Podoba mi się pomysł Atoma wykorzystujący UART "niesprzętowy".
  • Poziom 43  
    Wiesz, w tym przypadku może wystarczy zmniejszyć kilka razy prędkość UARTa zamiast wysyłać kilka razy to samo.

    Myślę że aż takie kombinowanie jak ja robię tutaj nie ma sensu.
    Ja przesyłam obraz Video na żywo!
    A Ty jeden pomiar a ADC, liczbę 8-mio bitową.

    Zmniejszenie prędkości UARTa przyniesie rezultaty, ale tylko w przypadku gdy odbiornika nie odbiera śmieci a jedynie przekłamuje bity.

    U mnie błędy pojawiają sie jedynie gdy nadaję dane.
    Gdy wystawię stan 0 albo 1 to odbiornik nie odbiera śmieci.
    A u Ciebie może tak. Od usunięta tego problemu trzeba zacząć.
    Jeżeli się nie da to trzeba zobaczyć czy chociaż ilość 0 i 1 w tych śmieciach jest zbliżona. Jeżeli tak, to znaczy że jest to standardowy szum i wystarczy filtr na wejściu UARTa. Śmieci zostaną uśrednione. Wprawdzie wartość napięcia będzie oscylowała w okolicach 0,5VCC co spowoduje odbieranie śmiecie, ale podczas nadawania sygnał będzie polepszony, bo nie będzie zawierał krótkich szpilek.
    Ludzie unikają zmniejszania prędkości UATRa bo nie przynosi to rezultatów. A nie przynosi bo brak filtru. Rezultaty będą jak poza zmniejszeniem prędkości doda się filtr, choćby obwód RC.

    Włączając nadajnik pojawi się przebieg. W końcu to nadajnik FSK. Ja bym przed nadawaniem na chwilę wystawił stan 0, żeby odbiornik przestał odbierać ewentualne śmieci. Dopiero po ustaleniu się 0 zaczął nadawać. Dzieki temu odbiornik poprawnie odbierze 1 bajt danych.
    Najlepiej to było by w ogóle nie wyłączać nadajnika, żeby ciągle wystawiał nośną a więc odkłócał eter. Ale jeżeli ze względu na pobór mocy czy coś tam innego to niemożliwe lub chociaż niewskazane to włączenie nadajnika na czas 1…3 bajtów przed nadawaniem jest bardzo dobrym pomysłem.
  • Poziom 22  
    Nie wiem... może znowu wolno myślę, ale czy nie można by np. wysłac paczuszki kilku bajtów zawierających odczyt z adc i po odebraniu porównac bajty, jeżeli będą powiedzmy 4 identyczne to uznac że to dana poprawna, a nie śmiec?
  • Pomocny post
    Poziom 43  
    Może i tak.
    Ale na moje oko i tak kombinujecie.

    Ja od początków jak stosuję przesyłanie danych przez UARTa to stosuję jeden algorytm który wymyśliłem jak tylko zacząłem się zajmować programowaniem, i okazał się na tyle skuteczny że korzystam z niego od kilku lat i nie zmieniłem od tamtej pory w nim nic.

    Wysyłam:
    23, Dana, Dana, Dana, Dana, ..., Dana, CRC-8-CCITT

    Odbiornik czeka na w tym przypadku dajmy na to na 8 bajtów.
    Gdy już tyle ma to sprawdza czy pierwszy to 23.
    Jak nie to przesuwa bufor o jedne bajt (kasuje pierwszy bajt).
    I znowu czeka na 8 bajtów (bo po przesunięciu zostało tylko 7)
    Gdy w końcu pierwszy bajt to 23 to liczy CRC i jak sie zgadza to uznaje ramkę za dobrą i całkowicie czyści bufor (bo w końcu cały jest dobry).
    Ale jak pierwszy bajt to 23 ale CRC się nie zgadza to także przesuwa bufor o jeden bajt i znowu czeka na 23.
    Algorytm dość prosty i nic w nim odkrywczego, ale takie coś samo się synchronizuje, wymaga bufora o długości zaledwie o długości ramki i dość szybko działa.

    A Wy coś kombinujecie, i jak widzę to wszyscy inni też. Czekanie na ramkę może nic nie dać bo układ może pogubić dane.
    Odbieranie ciągu bajtów i przeszukiwanie w celu znalezienia ID już lepsze ale po co przeszukiwać jak można od razu sprawdzać.

    Dodano po 9 [minuty]:

    Generalnie chodzi mi o to że w przypadku złego CRC nie należy od razu usuwać całej ramki z bufora, ale przesunąć bufor o jedne bajt.
    Jak jakaś dana w ramce będzie miała taką samą wartość jak ID ramki, w przypadku gdy układ natrafi na taką daną i uzna ją na ID to CRC mu się najczęściej nie zgodzi. Więc usunie ramkę. Odbiera kolejną (choć w zasadzie jest to końcówka n-tej ramki i początek n+1 ramki) i znowu to samo.
    Albo po prostu złe ID (gdy nie ma wyszukiwania ID a jedynie sprawdzanie czy ID = ileśtam) i usuwanie całej ramki jak ID złe. Tak też robi wiele osób z tego co widzę. A przecież tak jak wcześniej, układ może odebrać ramkę przesuniętą i już zawsze mu wyjdzie że ramki są złe.

    Dodano po 5 [minuty]:

    Powiedzcie w i na co czym piszecie.
    Ja mogę rzucić kodem mojego algorytmu w BASCOMie.
    O ile przerobienie tego na przykład na C będzie łatwe, to na procesor inny niż AVR już nie bo tam jest trochę rzeczy w assemblerze. Miałem jeszcze pierwotną wersję na ’51 ale nie wiem czy znajdę.
  • Poziom 9  
    Korzystam z wewnętrznego generatora RC zamiast z kwarcu - zapewne to jest pierwszym wielkim błędem.
    W moich algorytmach założyłem po prostu, że niezmiernie rzadko zdarza się taka sytuacja, iż kolejno nadawane przez UART ramki nie gubią się gdzieś po drodze innymi slowy:
    UART nadaje: ramka0 ramka1 ramka2 ramka3....
    drugi UART odbiera: ramka0 ramka2 ramka5....
    Z tego względu obłożyłem każdą ramkę z osobna aż takimi zabezpieczeniami, które jak widać są w sumie zbyteczne.
    Czytając wypowiedzi Atoma poparte jego eksperymentami muszę przyznać, że chyba zjadł mnie ten mój pesymizm.... Spróbuję teraz napisać program, który będzie działał w taki właśnie sposób jak radzi Atom. Zobaczymy co z tego wyjdzie. Najgorsze jest to, że dziś sobota i chyba nie kupię nigdzie kwarców :(

    Dodano po 2 [minuty]:

    Ja piszę w języku C na mikrokontroler ATmega8
  • Poziom 43  
    Nadajnik:
    Code:

    Const Crc8_polynominal = &B10001101                         'CRC-8-CCITT

    Do
        Buff(1) = 23
        Buff(2) = ADCL
        Buff(3) = ADCH

        ldi R20, 3
        Loadadr Buff(1) , X
        Gosub Calculate_crc   

        PrintBin Buff(1)
        PrintBin Buff(2)
        PrintBin Buff(3)
        PrintBin Crc_obliczone

        Waitms 100
    Loop
    '--------------------------------------------------------
    Calculate_crc:                                              'Reverse CRC        R20 - licznik bajtów
      ser R16


      !Crc8_Loop:
        ld R17, X+

        ldi R18, 8
        !Crc8_Loop_Byte:
          bst R16, 7
          bld R19, 0
          eor R19, R17

          rol R16

          cbr R16, 1

          lsr R17

          ror R19
          brcc CRC8_No_XOR
            ldi R19, CRC8_polynominal
            eor R16, R19
          !Crc8_No_XOR:

          dec R18
        brne CRC8_Loop_Byte
      dec R20
      brne CRC8_Loop


      com R16
      sts {Crc_obliczone}, R16
    Return
    '--------------------------------------------------------



    Odbiornik:
    Code:

    Const Crc8_polynominal = &B10001101                         'CRC-8-CCITT



    In_pos = 1            'W BASCOMie tablice indeksuje się od 1, stąd takie udziwnienia.


    Do
      Inputbin Dana

      Buffer_in(in_pos) = Dana

      Incr In_pos

      If In_pos = 5 Then                          'Jak są 4 bajty w buforze                                 
          If Buffer_in(1) = 23 Then                           
              Ldi R20, 3
              Loadadr Buffer_in(1) , X
              Gosub Calculate_crc

              If Crc_obliczone = Buffer_in(4) Then           
                  Servo(1) = Buffer_in(2)
                  Servo(2) = Buffer_in(3)



                  In_pos = 1
              Else
                  In_pos = 4                             

                  For I = 1 To 3                               
                    J = I + 1

                    Buffer_in(i) = Buffer_in(j)
                  Next
              End If
          Else                                                 
              In_pos = 4                                 

              For I = 1 To 3                                   
                J = I + 1

                Buffer_in(i) = Buffer_in(j)
              Next
          End If
      End If
    Loop
    '--------------------------------------------------------
    Calculate_crc:                                              'Reverse CRC        R20 - licznik bajtów
      ser R16


      !Crc8_Loop:
        ld R17, X+

        ldi R18, 8
        !Crc8_Loop_Byte:
          bst R16, 7
          bld R19, 0
          eor R19, R17

          rol R16

          cbr R16, 1

          lsr R17

          ror R19
          brcc CRC8_No_XOR
            ldi R19, CRC8_polynominal
            eor R16, R19
          !Crc8_No_XOR:

          dec R18
        brne CRC8_Loop_Byte
      dec R20
      brne CRC8_Loop


      com R16
      sts {Crc_obliczone}, R16
    Return
    '--------------------------------------------------------
  • Poziom 9  
    W oparciu o algorytm Atoma napisałem program w języku C. Muszę przyznać, że daje znakomite efekty! Zaobserwowałem w prawdzie inne problemy ale są one związane z obsługą przetwornika A/C a nie z transmisją. Jeżeli zaś chodzi o samą pransmisję to nigdy nie udalo się uzyskac równie dobrych rezultatów. Poniżej wklejam kod całego nadajnika i odbiornika. Najwazniejsze są funkcje Nadaj_bajt i Odbierz_bajt resztę można pominąć jeśłi kogos nie obchodzi przetwornik A/C lub ten konkretny mikrokontroler (ATmega8) i jego konfiguracja. Układy działają całkiem niźle nawet bez kwarców. Jutro dokupię rezonatory i zobaczę czy to znaczaco wpłynie na transmisję. Dodam tylko - dla zrozumienia programu - że te dziwne instrukcje na początku funkcji main w odbiorniku:
    Code:

    DDRC=0xff;
    PORTC=0xff;

    PORTC=0x00;
    _delay_ms(a);
    PORTC=0x01;
    _delay_ms(a);
    PORTC=0x00;
    _delay_ms(a);
    PORTC=0x01;

    To tylko taki element praktycznej obserwacji - mój odbiornik ma nóżkę "Enable" doświadczenie pokazuje, że ustawienie jej w stan wysoki "na sztywno" nie przynosi bardzo dobrych rezultatów - lepiej jest podczas uruchamiania układu wrzucić na nią kilka impulsów.

    No dobra nie będę już przynudzał - oto kod:

    Nadajnik:
    Code:

    // NADAJNIK

    #define F_CPU 1000000UL
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #define UART_BAUD   9600         //prędkość transmisji
    #define UART_CONST   (F_CPU/(16ul*UART_BAUD)-1)
    #define ID_poczatek 44 //liczba oznaczająca początek transmisji danych


    unsigned char ObliczCRC (unsigned char a)
    {
    unsigned char i = 0;
       if (a & 0b00000001)
          i++;
       if (a & 0b00000010)
          i++;
       if (a & 0b00000100)
          i++;
       if (a & 0b00001000)
          i++;   
       if (a & 0b00010000)
          i++;
       if (a & 0b00100000)
          i++;   
       if (a & 0b01000000)
          i++;   
       if (a & 0b10000000)
          i++;   

    return (i);
    }

    void USART_Transmit( unsigned char data )
    {
       while ( !( UCSRA & (1<<UDRE)) );   /* Wait for empty transmit buffer */
       UDR = data;                  /* Put data into buffer, sends the data */
    }

    unsigned char USART_Receive( void )
    {
       while ( !(UCSRA & (1<<RXC)) );            /* Wait for data to be received */
       return UDR;                           /* Get and return received data from buffer */
    }

    void USART_Init( unsigned int ubrr )
    {
       UBRRH = (unsigned char)(ubrr>>8);         /* Set baud rate */
       UBRRL = (unsigned char)ubrr;   
       UCSRB = (1<<RXEN)|(1<<TXEN);      /* Enable Receiver and Transmitter */   
       UCSRC = _BV(URSEL)|_BV(UPM1)|_BV(UCSZ0)|_BV(UCSZ1);/* ramka danych: 8 bitow danych, 1 bit stopu, bit parzystosci */
       
    }

    void Nadaj_bajt (unsigned char bajt)
    {
    unsigned char i,crc;

       crc = ObliczCRC(bajt);

       for (i=0; i<10; i++)
          {
             USART_Transmit(ID_poczatek);
             USART_Transmit(crc);
             USART_Transmit(bajt);
          }
       
       _delay_ms(10);
    /* Struktura ramki:
          ID_poczatek | crc | pomiar
    */
    }

    void ADC_Init(void)
    {
       ADMUX = _BV(ADLAR);   //wartosc wpisz "w lewo"
          ADCSR = _BV(ADEN)|_BV(ADIE)|_BV(ADFR)|_BV(ADSC)|_BV(ADPS0)|_BV(ADPS1);
                              // włącz przetwornik i uruchom generowanie przerwań
                              // częstotilwość taktowania F_ADC=F_CPU/8

          sei();                // włącz obsługę przerwań
    }

    ISR(ADC_vect)       // obsługa przerwania od ADC
    {
       unsigned char liczba;
       liczba = ADCH;
       Nadaj_bajt(liczba);
    }

    int main(void)
    {
    int a = 10;

       USART_Init(UART_CONST);
       ADC_Init();

       while(1)
       {

          USART_Transmit(0);
          
       }
    }



    Odbiornik:
    Code:

    // ODBIORNIK

    #define F_CPU 1000000UL
    #include <avr/io.h>
    #include <util/delay.h>
    #define UART_BAUD   9600         //prędkość transmisji
    #define UART_CONST   (F_CPU/(16ul*UART_BAUD)-1)
    #define ID_poczatek 44
    unsigned char x=0;

    unsigned char bin8toBCD (unsigned char a)
    {
       unsigned char dziesiatki;
       unsigned char jednosci;
       unsigned char wynik;
       jednosci = a%10; //jednosci sa reszta z dzielenia liczby a przez 10
       dziesiatki = a/10; //dzisiatki sa wynikiem dzielenia przez 10
       dziesiatki = dziesiatki << 4;
       wynik = jednosci | dziesiatki;
       return (wynik);
    }

    void USART_Transmit( unsigned char data )
    {
       while ( !( UCSRA & (1<<UDRE)) );   /* Wait for empty transmit buffer */
       UDR = data;                  /* Put data into buffer, sends the data */
    }

    unsigned char USART_Receive( void )
    {
       while ( !(UCSRA & (1<<RXC)) );            /* Wait for data to be received */
       return UDR;                           /* Get and return received data from buffer */
    }

    void USART_Init( unsigned int ubrr )
    {
       UBRRH = (unsigned char)(ubrr>>8);         /* Set baud rate */
       UBRRL = (unsigned char)ubrr;   
       UCSRB = (1<<RXEN)|(1<<TXEN);      /* Enable Receiver and Transmitter */   
       UCSRC = _BV(URSEL)|_BV(UPM1)|_BV(UCSZ0)|_BV(UCSZ1);   /* Set frame format: 8data, 1stop bit, bit parzystosci */
       
    }

    unsigned char ObliczCRC (unsigned char a)
    {
    unsigned char i = 0;
       if (a & 0b00000001)
          i++;
       if (a & 0b00000010)
          i++;
       if (a & 0b00000100)
          i++;
       if (a & 0b00001000)
          i++;   
       if (a & 0b00010000)
          i++;
       if (a & 0b00100000)
          i++;   
       if (a & 0b01000000)
          i++;   
       if (a & 0b10000000)
          i++;      
    return (i);
    }


    unsigned char Odbierz_bajt(void)
    {
    unsigned char Bufor[21];
    unsigned char Indeksy[21];
    unsigned char crc;
    unsigned char dane = 0; //dane
    unsigned char i,k,l,m; // liczniki petli
    unsigned char a; //marker

    while(1)
       {
          l = 0;
          a = 0;

          for (i=0; i<21; i++)
             Bufor[i] = USART_Receive(); //Pobieranie danych z UART do bufora
          
          for (k=0; k<21; k++)
             {
             if (Bufor[k] == ID_poczatek)
                {
             Indeksy[l] = k; //Do tablicy trafiają indeksy elementów Bufora, ktore sa znacznikiem poczatku ramki danych
             l++;
                }
             }
          for (m=0; m<=l; m++)
             {
             if((ObliczCRC(Bufor[(Indeksy[m])+2]))==(Bufor[(Indeksy[m])+1]))
                {
                dane = Bufor[(Indeksy[m])+2];
                a = 1;
                break; //wyjście z petli for
                }
             }
       if(a)
       break; //wyjście z petli while
       }
    return(dane);
    }

    int main(void)
    {
    unsigned char a = 100;

    DDRB=0xff; //wyjscia
    PORTB=0xff; //normalnie jedynki

    USART_Init(UART_CONST);
    //int a = 500;

    DDRC=0xff;
    PORTC=0xff;

    PORTC=0x00;
    _delay_ms(a);
    PORTC=0x01;
    _delay_ms(a);
    PORTC=0x00;
    _delay_ms(a);
    PORTC=0x01;
       
       while(1)
       {
          x = Odbierz_bajt();
          x = bin8toBCD(x);
          PORTB = x;
       }
    }
  • Specjalista - oświetlenie sceniczne
    Nie wiem na co wam takie czary. Ja od wieków wysyłam kilka stałych bajtów rozpoczynajacych transmisje, potem zawartość, a na koniec zwykłą sume wszystkich bajtów, działa bezbłednie. Jeśli suma odebranych bajtów nie zgadza sie z sumą która została wysłana to cała transmisja idzie w kosz. Dodam że całość wysyłam w ASCI, wieć nie ma problemu że jakies dane zostaną odczytane jako np początek ramki


    ---> Atom, jesteś w blędzie twierdząc że jak przy jednym bajcie dopuszcza się np 4% błędu, to przy dwóch już 0,25%. UART ZAWSZE synchronizuje sie dla jednego znaku bez względu na to ile ich wysyłasz
  • Poziom 43  
    bolek napisał:

    ---> Atom, jesteś w blędzie twierdząc że jak przy jednym bajcie dopuszcza się np 4% błędu, to przy dwóch już 0,25%. UART ZAWSZE synchronizuje sie dla jednego znaku bez względu na to ile ich wysyłasz


    To na początek pokaż mi gdzie napisałem że przy 2 bajtach trzeba 0.25%.
    Od razu mówię że nie zedytowałem postu ;)
  • Specjalista - oświetlenie sceniczne
    no fakt, mój błąd pomyliłem B z b
    Nie mniej jednak. UART synchronizuje się na początku każdego przesłanego bajta. Nie ma znaczenia ile ich sobie wyślesz
  • Poziom 43  
    Ale ja tylko czekałem na Twoją odpowiedz. Żeby Ci teraz pojechać ;)

    Otóż nie doczytałeś kolego.

    Ja mówię o UARCie z określoną ilością bitów. A nie o UARCie 8-mio bitowym (bajtowym). A więc ma znaczenie ile bitów czy bajtów wyślę.
    Ja mówię o UARCie który wysyła wszystkie bajty na raz. Powiedzmy 1 bit startu, 10000bitów danych i 2 bity stopu. Już rozumiesz?
  • Specjalista - oświetlenie sceniczne
    atom1477 napisał:
    Ale ja tylko czekałem na Twoją odpowiedz. Żeby Ci teraz pojechać ;)

    Otóż nie doczytałeś kolego.

    Ja mówię o UARCie z określoną ilością bitów. A nie o UARCie 8-mio bitowym (bajtowym). A więc ma znaczenie ile bitów czy bajtów wyślę.
    Ja mówię nie UARCie który wysyła wszystkie bajty na raz. Powiedzmy 1 bit startu, 10000bitów danych i 2 bity stopu. Już rozumiesz?



    hmm no dobra, pojechałeś ale pieron wie gdzie.

    Opisz dokładniej jaki to wg ciebie UART z "określoną liczbą bitów".
    Cytat:

    Ja mówię nie UARCie który wysyła wszystkie bajty na raz. Powiedzmy 1 bit startu, 10000bitów danych i 2 bity stopu. Już rozumiesz?



    Trochę pokręcone to zdanie, wiem że głupi jestem, ale jeszcze nie widziałem UARTa który w jednym znaku wysyłał bit startu, 10 000 bitów danych i dwa bity topu
  • Poziom 43  
    No trochę nie po polsku napisałem. Już poprawiłem post.
    No to mało widziałeś skoro takiego nie widziałeś. Przecież za 5,6,7,8,9,10-cio bitowe, więc i 16 czy 32 bitowy też się znajdzie. Oczywiście nie mówię że są popularne.
    A do tego ja napisałem wyraźnie że taki przesył jest realizowany programowo. Podałem tylko analogię do UARTa, który to przy 8-miu bitach wymaga dokładności zegara 4%, żeby był jakiś punkt zaczepienia. Wiedząc że UART przy 8-miu bitach wymaga dokładności 4%, łatwo policzyć że przy 16b będzie to 2%, a więc przy 128b 0.25%.

    Głupi na pewno nie jesteś. Po prostu założyłeś że chodzi o UART sprzętowy, bo o taki generalnie chodzi w tym temacie. To ja skręciłem z tematu.

    Dodano po 14 [minuty]:

    Teraz wypowiem się na temat klasycznej komunikacji klasycznym interfejsem UART 8-mio bitowym ;)
    bolek napisał:
    Nie wiem na co wam takie czary. Ja od wieków wysyłam kilka stałych bajtów rozpoczynajacych transmisje, potem zawartość, a na koniec zwykłą sume wszystkich bajtów, działa bezbłednie. Jeśli suma odebranych bajtów nie zgadza sie z sumą która została wysłana to cała transmisja idzie w kosz. Dodam że całość wysyłam w ASCI, wieć nie ma problemu że jakies dane zostaną odczytane jako np początek ramki


    No widzisz, bo wysyłasz długie ID. Wtedy bardzo trudno jest żeby jakieś dane czy śmieci podszyły się pod ID.
    Ale taki sposób ma taką wadę że wymaga długiego ID po prostu.
    I wymaga przeszukiwania ciągu. To nie jest trudne, ale i takie coś nie pasuje mi jakoś.
    Mój sposób za to ma krótkie ID. I z tego powodu częściej się zdarza że jakieś dane podszywają się pod ID. I dlatego zastosowane jest CRC oraz w przypadku niezgodności czegoś tam bufor nie jest całkowicie czyszczony z ramki, lecz ramka jest przesuwana o jeden bajt.
    Krótkie ID pozwala na większy transfer.
    Do tego algorytm działa w biegu i nie wymaga zbierania danych. Ale stosowałem i jego odmianę zbierającą dłuższy bufor i potem dekodujący kilka ramek jednocześnie. Ale na temat algorytmu nie będę się wypowiadał (chodzi mi o to czy dekodować w biegu czy co jakiś czas większa ilość danych.). To każdy zrobi jak będzie chciał a efekty dekodowania ramek będę identyczne.
    Ja jednak stosuję dekodowanie w biegu bo w 99% dane które przesyłam są natychmiast do czegoś potrzebne (sterowanie serwami i silnikami w jakimś pojeździe w jedną stronę. Przesyłanie obrazu czy informacji o jakichś tam parametrach w drugą stronę). W tym przypadku jakakolwiek zwłoka jest niedopuszczalna. A nawet jak dane zostaną zagubione to już nic nie pomoże. Dlatego nie stosuję żadnego algorytmu dopytującego się o ramki które nie doszły.
  • Poziom 10  
    mam pytanie odnoścnie ramki danych.

    czy dobrze rozumiem ze takim zapisem
    UDR = 11;
    wysyłamy 2 bity danych w jednej ramce, a np tak:
    UDR=10101010;
    wysyłamy jedną ramką 8 bitów.

    ile bitów możemy maksymalnie wysłać w jednej ramce danych podczas transmisji przez UART ?
  • VIP Zasłużony dla elektroda
    Jednocześnie można wysłać od 5 do 9 bitów w ramce, zależnie od ustawień rejestrów sterujących w AVR. Szczegóły jak zwykle w nocie katalogowej. Hint : "UCSZ"