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

Jak zwiększyć szybkość transmisji RS232 w Bascom na ATmega16 16MHz?

MES Mariusz 21 Maj 2007 19:29 3345 5
REKLAMA
  • #1 3907304
    MES Mariusz
    Poziom 36  
    Posty: 5452
    Pomógł: 8
    Ocena: 222
    Witam!

    Buduję urządzenie komunikujące się z PC poprzez port RS232. Zależy mi na jak najszybszej transmisji.

    Aplikacja PC wysyła rozkaz TX do urządzenia, urządzenie odsyła zmierzone wartości w postaci ciągu:

    dana1:dana2:dana3:dana4:dana5:dana6:dana7:dana8

    za pomocą Bascomowej instrukcji Print.

    Maksymalna szybkość jaką udaje mi się osiągnąć przy Atega16 i kwarcu 16MHz to około 5Hz. Aplikacja posiada suwak, którą mogę ustawić szybkość pobierania danych z urządzenia. Urządzenie wysyła komendę TX w interwale jaki ustawiam za pomocą suwaka, a następnie szybko odczytuje bufor RS232 i przekazuje dane do zmiennych.

    W aplikacji zrobiłem okienko logowania dzięki któremu mogę obserwować cały odbierany string (dana1:dana2:dana3:dana4:dana5:dana6:dana7:dana8)

    I widzę, że przy zwiększaniu szybkości powyżej 5Hz string urywa się po 4 czy piątej danej.

    Widać - urządzenie nie zdążyło jeszcze wysłać wszystkich danych.

    Kompiluję sobie program w Bascom AVR dla różnych wartości rezonatora kwarcowego, i obserwuję wartość BAUD error w raporcie pokompilacyjnym.

    Kwarc 16MHz:

    $baud = 38400 -> BAUD error: 0,16%
    $baud = 57600 -> BAUD error: 2,08%
    $baud = 115200 -> BAUD error: 3,55%
    $baud = 128000 -> BAUD error: 2,34%
    $baud = 256000 -> BAUD error: 2,34%

    Widzę, że przy Atmega 16 taktowanego 16MHz nie wycisnę więcej niż 5Hz dla stringu zawierającego 8 danych.

    Z ciekawości, wybrałem

    $baud = 128000 i zacząłem zwiększać wartość rezonatora:

    32MHz -> BAUD error: 2,34%
    64MHz -> BAUD error: 0,8% (to już chyba nie najgorszy wynik?)
    96MHz -> BAUD error: 0,27%

    Niestety Atmega16 można taktować do 16MHz (trochę mało)

    Czy ktoś ma pomysł na to, jak wydusić z Atmega16 większą transmisję, niż 38400 baud ?
  • REKLAMA
  • #2 3907912
    crazy_phisic
    VIP Zasłużony dla elektroda
    Posty: 2244
    Pomógł: 278
    Ocena: 130
    Nota katalogowa -> zakładka USART -> Examples of Baud Rate Setting i juz wszystko jasne ;)
  • REKLAMA
  • #3 3909943
    szymtro
    Poziom 30  
    Posty: 1421
    Pomógł: 101
    Ocena: 59
    Coś nie mogę za bardzo uwierzyć w te 5hz - może 50hz?
    19200 to w przybliżeniu 1500 znaków na sekundę. Jak zrobisz z danych postać hex to mi wychodzi 23znaki w wiadomości (no może 25 bo crlf).
    Jakby nie patrzeć taka ramkę można powtórzyć szybciej niż 60hz.

    Masz coś źle z samym algorytmem na pc albo coś nie tak z tym programem w bascomie.

    Zaraz się pewnie okaże że używasz komendy input do wykrycia znaku specjalnego tx z pc.
  • REKLAMA
  • #4 3912528
    MES Mariusz
    Poziom 36  
    Posty: 5452
    Pomógł: 8
    Ocena: 222
    szymtro napisał:
    Coś nie mogę za bardzo uwierzyć w te 5hz - może 50hz?
    19200 to w przybliżeniu 1500 znaków na sekundę. Jak zrobisz z danych postać hex to mi wychodzi 23znaki w wiadomości (no może 25 bo crlf).
    Jakby nie patrzeć taka ramkę można powtórzyć szybciej niż 60hz.


    To jest przykładowy string wysłany od urządzenia do PC:

    514:512:512:512:514:515:512:516

    łącznie 32 znaki, wysłane za pomocą komendy print
    a dokładniej kodu:

    
    Print Zmienna1 ;
    Print ":" ;
    Print Zmienna2 ;
    Print ":" ;
    Print Zmienna3 ;
    Print ":" ;
    Print Zmienna4 ;
    Print ":" ;
    Print Zmienna5 ;
    Print ":" ;
    Print Zmienna6 ;
    Print ":" ;
    Print Zmienna7 ;
    Print ":" ;
    Print Zmienna8 ;
    


    Ot cały skomplikowany algorytm.

    Najpierw urządzenie czeka na komendę (Input Komenda) a po odebraniu właściwej komendy wysyła printami 8 danych. I tyle.


    szymtro napisał:
    Masz coś źle z samym algorytmem na pc albo coś nie tak z tym programem w bascomie.

    Zaraz się pewnie okaże że używasz komendy input do wykrycia znaku specjalnego tx z pc.

    W rzeczy samej. Instrukcją Input czekam na string dwu znakowy TX.

    A dlaczego nie?

    Film, na którym widać (ostatnie sekundy) opisywany problem zamieszczam w załączniku oraz pod adresem: http://rapidshare.com/files/32895888/clip0010.avi.html

    Widać - urządzenie nie zdąża wysłać wszystkich danych.
    Załączniki:
    • clip0010.avi (1.88 MB) Musisz być zalogowany, aby pobrać ten załącznik.
  • REKLAMA
  • Pomocny post
    #5 3913293
    szymtro
    Poziom 30  
    Posty: 1421
    Pomógł: 101
    Ocena: 59
    No to zaczynamy po raz kolejny.

    Coś takiego jak stworzyłeś to niestety za szybko nie będzie działać. Mega z kwarcem rs 14 z groszami działa naprawdę szybko i można zrobić bardzo dużo w jedna sekundę.
    Do odbierania i wysyłania danych można sobie napisać własną procedurę - nawet w bascomie i jest ona sporo szybsza i działa rewelacyjnie.
    Deklarujemy przerwania od rs'a:
    On Urxc Rs_rx_ok
    On Utxc Rs_tx_ok

    Deklarujemy zmienne:
    Dim Rs_rx_bufor As Byte
    
    Dim Rs_tx_bufor(30) As Byte 'na wszelki wiecej
    Dim Rs_tx_licznik As Byte
    Dim Rs_tx_ograniczenie As Byte

    Przerwanie od rx:
    Rs_rx_ok:
       If Udr = "i" Then
          Rs_tx_licznik = 2 : Rs_tx_ograniczenie = 25           'ustaw poczatek w stringu do wyslania
          Reset Ucr.4
          Udr = Rs_tx_bufor(1)                                  'poczatek wiadomosci
       Else
          Rs_rx_bufor = Udr
       End If
    Return

    Przerwanie od tx:
    Rs_tx_ok:
       If Rs_tx_licznik > Rs_tx_ograniczenie Then
          Rs_tx_licznik = 1
          Set Ucr.4
       Else
          Udr = Rs_tx_bufor(rs_tx_licznik) : Incr Rs_tx_licznik
       End If
    Return

    Deklarujemy sobie jakieś napisy początkowe(przed pętlą główną):
       Rs_tx_bufor(1) = "0"
    Rs_tx_bufor(2) = "0"
    Rs_tx_bufor(3) = ":"
    Rs_tx_bufor(4) = "0"
    Rs_tx_bufor(5) = "0"
    Rs_tx_bufor(6) = ":"
    Rs_tx_bufor(7) = "0"
    Rs_tx_bufor(8) = "0"
    Rs_tx_bufor(9) = ":"
    Rs_tx_bufor(10) = "0"
    Rs_tx_bufor(11) = "0"
    Rs_tx_bufor(12) = ":"
    Rs_tx_bufor(13) = "0"
    Rs_tx_bufor(14) = "0"
    Rs_tx_bufor(15) = ":"
    Rs_tx_bufor(16) = "0"
    Rs_tx_bufor(17) = "0"
    Rs_tx_bufor(18) = ":"
    Rs_tx_bufor(19) = "0"
    Rs_tx_bufor(20) = "0"
    Rs_tx_bufor(21) = ":"
    Rs_tx_bufor(22) = "0"
    Rs_tx_bufor(23) = "0"
    Rs_tx_bufor(24) = &h0A 'CR
    Rs_tx_bufor(25) = &h0d 'LF

    Przykład z pliku napisanego dla tiny2313 - dlatego takie nazwy rejestrów. Konfiguracje prędkości i ustawienia wysyłania, załączenia przerwań podpatrz w załączonym pliku.

    Dobrze ci idzie ale poanalizuj jeszcze trochę datasheet do twojego uC.

    Dodano po 5 [minuty]:

    Do moderatora: wiem że złamałem regulamin (wysyłanie post pod postem) ale tak chyba będzie bardziej czytelne - inaczej wychodzi straszny tasiemiec.
    --------------------------------------------------------------------------------------
    Programik działa tak ze normalnie w pętli coś tam może sobie robić (najpewniej analizować zmienne, przerabiać je na hex i wstawiać w odpowiednie miejsca do bufora(tam gdzie w przykładzie są zera).

    W momencie nadejścia literki "i" ustawia sobie odpowiednio liczniki i ograniczenia liczników i wysyła jeden znak(pierwszy). W momencie jak wyśle wystąpi przerwanie nadania (nadawania), zwiększy licznik, sprawdzi czy już ma być koniec (ograniczenie) i albo zakończy albo wyśle kolejny znak z bufora.

    Tak to działa i działa bardzo dobrze.
    Załączniki:
    • Kopia 2313_rs_05.bas.txt (4.27 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #6 3916151
    MES Mariusz
    Poziom 36  
    Posty: 5452
    Pomógł: 8
    Ocena: 222
    Zanim przystąpiłem do prób z zaproponowaną procedurą do obsługi UARTu, przeprowadziłem testy siłowe za pomocą kodu:

    
    $regfile = "m16def.dat"
    $crystal = 16000000
    $baud = 38400
    
    Dim Licznik As Integer
    Dim Rozkaz As String * 2
    
    Licznik = 0
    
    Do                                                     
       Incr Licznik
       Print Licznik ; " : 1023:1023:1023:1023:1023:1023:1023:1023"
    
       If Licznik > 1000 Then
        Do
         Input Rozkaz
         If Rozkaz = "TX" Then
          Licznik = 0
          Exit Do
         End If
        Loop
       End If
    
    Loop                                                   
    
    End
    


    Efekt jest taki, że 1000 takich stringów jest wysyłany do terminala na PC w ciągu 12 sekund, co daje maksymalną prędkość około 80 stringów (po ok. 40 znaków) na jedną sekundę.

    Dlaczego więc aplikacja odczytuje pełny string bufora jeśli przesyłane jest nie więcej niż ok. 5 stringów na sekundę?

    Zrobiłem kolejny test.

    Ustawiłem $baud na 128000 baud (pozwoliłem sobie na baud error na poziomie 2%).

    Jaki efekt? Aplikacja prawidłowo działa przy dwukrotnie większym interwale! (10Hz). Tym razem urządzenie spokojnie wyrabia się w przesłaniu 10 pełnych stringów po 40 znaków w ciągu sekundy! Przejrzałem listę odebranych danych i widzę, że ten błąd 2% nie robi mi problemu (żadna dana nie została przekłamana).

    Ciekawe tylko, skąd takie duże zapotrzebowanie na prędkość transmisji, skoro przy prędkośc 38400, 1000 takich 40 znakowych stringów jest wysyłane do terminala na PC w ciągu 12 sekund, czyli około 80 stringów (po ok. 40 znaków) na jedną sekundę?

    Oto jest pytanie...
REKLAMA