[BASCOM][M16]Przesylanie wielu zmiennych WORD via UART.

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
Awatar użytkownika
mictronic
-
Posty: 81
Rejestracja: 04 paź 2006, 19:28
Lokalizacja: Bydgoszcz
Kontakt:

[BASCOM][M16]Przesylanie wielu zmiennych WORD via UART.

Post autor: mictronic » 21 cze 2009, 20:59

Witam,złożyłem sobie pewne urządzenie które świetnie działa ale nie umiem go teraz oprogramować :p Problem jest następujący :
Potrzebuje wysłać kilka danych z przetwornika ADC poprzez UART do drugiej części kontrolera tj zmienne typu WORD.Wszystko jest niby ok kiedy wysyłam jedną zmienna, czyli rozbijam ją na bajty potem wrzucam na UTXC następnie odbieram łącze znowu w WORD i wyświetlam.Problem pojawia się kiedy robię to z dwoma zmiennymi-są kompletne przekłamania.Domyśliłem się że brakuje synchronizacji, tzn kiedy nadchodzi który bajtNiestety nie potrafię jej zrealizować gdyż nie wiem jak odróżnić znak "synchronizacji" od danych.Załóżmy że tym znakiem będzie $ jego kod to 036-i właśnie jak odróżnić że kod 36 nie jest daną tylko znakiem $??

Proszę chociaż o jakieś teoretyczne nakierowanie, jak to napisać.

Pozdrawiam Mictronic!

Awatar użytkownika
gwozdex
Użytkownik
Posty: 879
Rejestracja: 24 lut 2006, 10:04
Lokalizacja: Czechowice-Dziedzice
Kontakt:

Post autor: gwozdex » 21 cze 2009, 21:02

Najprościej będzie nam pomóc Tobie Jeśli załączysz odpowiedni kawałek kodu.

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 21 cze 2009, 21:49

Generalnie przesyłanie i tak się odbywa po jednym znaku przez uart (8, 16 czy 32bit zmiennych) stad z rozpoznaniem $ nie powinieneś mieć problemu.

Awatar użytkownika
mictronic
-
Posty: 81
Rejestracja: 04 paź 2006, 19:28
Lokalizacja: Bydgoszcz
Kontakt:

Post autor: mictronic » 21 cze 2009, 22:03

No niewiem np tak ... :

Odbiornik:

Kod: Zaznacz cały

$regfile = "m16def.dat"
$crystal = 12000000
$baud = 19200
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Disconnect , Compare B Pwm = Clear Down , Prescale = 1
Pwm1b = 100

Enable Interrupts
Enable Urxc
On Urxc Uartrx

Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
Config Lcd = 20 * 4

'Open "comd.7:9600,7,E,1" For Input As #1
Cls
Cursor Off
Dim A(4) As Byte
Dim A2(2) As Word
Dim Licznik As Byte
Licznik = 1

   Do
   A2(1) = Makeint(a(2) , A(1))
   A2(2) = Makeint(a(4) , A(3))
   Locate 1 , 1
   Lcd A2(1)
   Locate 2 , 1
   Lcd A2(2)
   Loop

 Uartrx:
 Incr Licznik
 Udr = A(licznik)
 If Licznik = 4 Then Licnzik = 1
 Return
Nadajnik:

Kod: Zaznacz cały

$regfile = "m16def.dat"
$crystal = 7680000
$baud = 19200
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Down , Compare B Pwm = Disconnect , Prescale = 1


Config Adc = Single , Prescaler = Auto , Reference = Off
Start Adc

Enable Interrupts

Enable Utxc
Config Portd.7 = Output

Dim A As Word
Dim B As Word

Do
A = Getadc(1)
B = Getadc(2)
Udr = Low(a)
Udr = High(a)
Udr = Low(b)
Udr = High(b)
Loop
A ze uart wysyła pojedynczo znaki to wiem ale co będzie jeśli bajt ze zmiennej word będzie miał ta sama wartość co znak synchronizacji..?Moze wykrywać ilość wysłanych bitów,tylko jak?

Pozdrawiam Mictronic!

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 21 cze 2009, 22:18

Dane po UART zdaje się są wysyłane w kodzie ASCII więc raczej mało prawdopodobne że przy poprawnej transmisji otrzymasz coś innego niż wysłałeś i o ile twój program sam sobie nie wygeneruje $ przypadkowo to powinieneś nie mieć z tym problemu.

Awatar użytkownika
mictronic
-
Posty: 81
Rejestracja: 04 paź 2006, 19:28
Lokalizacja: Bydgoszcz
Kontakt:

Post autor: mictronic » 21 cze 2009, 22:29

Eh chyba się nie zrozumieliśmy.

To kolega powie jak wygląda bajt znaku specjalnego ascii
a jak wygląda bajt zwykłej liczby.

Wg mnie nie ma żadnej różnicy pomiędzy 36 a 36 bo może to zostać zinterpretowane jako zwykła liczba (w tym wypadku cześć ze zmiennej word) albo jako znak $...

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 21 cze 2009, 22:41

Przesyłając po UART liczbę "36", przesyłasz "3" i "6" - kolejne cyfry, dwa odrębne bajty. Przesyłając $ przesyłasz jeden bajt.

W każdym razie mi o to chodziło ;)

Awatar użytkownika
mictronic
-
Posty: 81
Rejestracja: 04 paź 2006, 19:28
Lokalizacja: Bydgoszcz
Kontakt:

Post autor: mictronic » 21 cze 2009, 22:48

Ahaaa ok dobra dobra pokombinujemy -nie zwróciłem na to uwagi jak testowałem.
Zaś ja ciągle myślałem ze jak wysyłam liczbę to od razu cały bajt a zakresie od 0 do 255 a nie ze poklei ,każdą cyferkę jak mówisz.

Sprawdzę to i dam później znać!

[ Dodano: 2009-06-22, 01:00 ]
Nie, jednak jest tak jak mówiłem.Gdy ładuje do rejestru UDR liczbę 123 to odbieram obrazu 123 a nie 1,2,3 :/

Wysyłam

Kod: Zaznacz cały

a=123
udr=a
wait 1
Odbieram

Kod: Zaznacz cały

a=udr
lcd a
Kto mi pomoże :( ?

MiW
Użytkownik
Posty: 226
Rejestracja: 28 sty 2007, 11:32
Lokalizacja: Kraków
Kontakt:

Post autor: MiW » 22 cze 2009, 15:25

Podejrzewam, że nie jest Ci potrzebny pełny zakres liczb (0-65535), tylko 0-1023.
Ja poradziłbym sobie z Twoim problemem tak:
-biorę siedem bitów niższego bajtu, jako ósmy (MSB) daję jeden -> wysyłam
-przesuwam bity wyższego bajtu w lewo i dorzucam na koniec "zapomniany" bit ->wysyłam

Dlaczego?
Bajty rozróżnisz po tym, czy zaczyna się od 0(wyższy) czy 1(niższy).
Mam nadzieję że zrozumiałem twój problem, a ty moje rozwiązanie :grin:

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 22 cze 2009, 15:28

Zresztą przy transmisjach w sieciach przemysłowych stosuje się odmienne znaki niż te które chce kolega wykorzystać. Z reguły EOT, STX, ETX.

Awatar użytkownika
mictronic
-
Posty: 81
Rejestracja: 04 paź 2006, 19:28
Lokalizacja: Bydgoszcz
Kontakt:

Post autor: mictronic » 22 cze 2009, 19:01

MiW pisze:Podejrzewam, że nie jest Ci potrzebny pełny zakres liczb (0-65535), tylko 0-1023.
Ja poradziłbym sobie z Twoim problemem tak:
-biorę siedem bitów niższego bajtu, jako ósmy (MSB) daję jeden -> wysyłam
-przesuwam bity wyższego bajtu w lewo i dorzucam na koniec "zapomniany" bit ->wysyłam

Dlaczego?
Bajty rozróżnisz po tym, czy zaczyna się od 0(wyższy) czy 1(niższy).
Mam nadzieję że zrozumiałem twój problem, a ty moje rozwiązanie :grin:
Pomysł fajny,ale jeszcze nie wiem jakbym to napisał,może coś prostszego.To przecież nie może być takie trudne jak inni wysyłają wiele zmiennych w swoich programach?

Spróbuje jeszcze bardziej przedstawić co próbuje osiągnąć.Mam jakieś urządzenie które mierzy:
Prad
Napięcie
Obroty silnika
Generuje PWM
Otrzymuje polecenia co jeszcze włączyć od drugiego urządzenia.

Chce wysłać:

Kod: Zaznacz cały

| PradLSB,PradMSB | NapiecieLSB,NapiecieMSB | RpmLSB,RpmMSB | Pwm(od biedy może być jeden bajt) | AdresPolecenia+Dane(2bajty) |
Tak to miało wg mnie wyglądać:

Kod: Zaznacz cały

$ PradLSB$PradMSB$NapiecieLSB$NapiecieMSB$RpmLSB$RpmMSB$PWM$
$AdresPolecenia$Dane$
W przerwaniu od UART zwiększałbym sobie licznik kiedy $ i odpowiednio pakował dane do zmiennych...
Ktoś ma pomysł jak to zrobić? :D
Moze inaczej zupełnie,bo pomysł z bitami-hmm jeszcze przemyślę.

Awatar użytkownika
Pikczu
Użytkownik
Posty: 755
Rejestracja: 18 lip 2005, 18:33
Lokalizacja: Dublin
Kontakt:

Post autor: Pikczu » 22 cze 2009, 19:42

Witam zrób to na zasadzie tablicy i użyj print bin
w tedy cała tablica jest wysyłana i bez błędów dodaj bufor do UART -ów

może pokaże na przykładzie moim

Kod: Zaznacz cały

Nadajnik:
'Sterwoanie przez port szeregowy
'ATmega 128 kwarc 16 MHZ
'by Pawel L. (pikczu)

'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'fusy nie zmieniać
$prog &HFF , &HFF , &H99 , &HFF
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

'$sim
$regfile = "M128def.dat"
$crystal = 16000000                                         'Kwarc
 $baud = 9600                                               'predkosc transmisji
'-----------konfiguracjia portów -----------------------------------------------
Config Portd = Input
Config Portb = Output
Portd = 255
Config Portf = Input
'-------------deklaracia zmiennych----------------------------------------------
Dim Flag1 As Bit
Dim Flag2 As Bit
Dim Flag3 As Bit
Dim Osy As Byte                                             'os y serwa
Dim Osx As Byte                                             'os x serwa
Dim Os_y As Byte                                            'Trymowanie Y
Dim Os_x As Byte                                            'Trymowanie X
Dim Channel As Byte                                         'Kanal ADC
Dim Przetwornik As Integer                                  'Wartosc pobrana z przetwornika
Dim Serial_tx(6) As Byte                                    'tablica do wysłania
Dim Synchro As Byte                                         'Sychronizacja tylko na poczatku programu
'-------------konfiguracjia przetwornika A/C------------------------------------
'Config Lcdpin = Pin , Db4 = Porta.4 , Db5 = Porta.5 , Db6 = Porta.6 , Db7 = Porta.7 , E = Portc.7 , Rs = Portc.6
Config Timer1 = Timer , Prescale = 256
Config Adc = Single , Prescaler = Auto , Reference = Internal

Config Serialout = Buffered , Size = 6



'-------------------- -----------------------------------------------------------
Enable Interrupts
Enable Timer1
Enable Utxc
Start Adc
Echo On
Timer1 = 3036
'*****************************-Synchro-*****************************************
Do
Lcd "czekam na synchro"
Synchro = Waitkey()                                         'czekaj na 13 ascii
Loop Until Synchro = 13
'************************-end of synchro-***************************************
Flag1 = 0
Flag2 = 0
On Timer1 Dela_y


'**********************'Main loop'**********************************************


Do

Gosub Pomiar:

Gosub Send:


Loop
'*************************'End of Main loop'************************************
'*******************************************************************************






'**************************-Sub's-**********************************************
Pomiar:

   For Channel = 0 To 1
   Przetwornik = 0
Przetwornik = Getadc(channel)                               'pierwszy  i drugi pomiar pomijamy
Przetwornik = Getadc(channel)
Przetwornik = 0
Przetwornik = Przetwornik + Getadc(channel)                 'pomiar
Przetwornik = Przetwornik + Getadc(channel)
Przetwornik = Przetwornik + Getadc(channel)



Shift Przetwornik , Right , 4

Select Case Channel

Case 0 :

   If Osy <> Przetwornik Then

          Osy = Przetwornik
          Flag1 = 1
   Serial_tx(1) , 1 = Osy

   End If

Case 1 :

    If Osx <> Przetwornik Then
            Osx = Przetwornik
             Flag2 = 1
    Serial_tx(2) , 1 = Osx

   End If

End Select

Next Channel
Return
'****************************-Send-*********************************************
Send:
   If Flag1 = 1 Or Flag2 = 1 Then
      Printbin Serial_tx(1) ; 6
      Flag1 = 0
      Flag2 = 0
   End If

Return



'-----------------------------------------------------------------------------
Dela_y:
Timer1 = 3036                                               '64286= 20ms'3036=1s
Toggle Portb.7
Return
End

dobra teraz część odbiorcza :

Kod: Zaznacz cały

'---CZĘŚĆ ODBIORCZA-------------------------------------------------------------
'Sterwoanie przez port szeregowy
'ATmega 128 kwarc 16 Mhz
'by Pawel L. (pikczu)

'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'Fusy nie zmieniac
$prog &HFF , &HFF , &H99 , &HFF
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
$regfile = "M128def.dat"
$crystal = 16000000                                         'Kwarc
$baud = 9600

'-----------konfiguracjia portu B i C jako wyjscie -----------------------------
Config Portb = Output
Config Portc = Output

'-------------deklaracia zmiennych----------------------------------------------
Dim Flag1 As Bit
Dim Flag2 As Bit

Dim Osy As Byte
Dim Osx As Byte
Dim Channel As Byte
Dim Value As Byte
Dim Serial_flag As Byte
Dim Serial_rx(6) As Byte


'-----------------konfiguracjia serv--------------------------------------------
Config Serialin = Buffered , Size = 60

Config Servos = 2 , Servo1 = Portb.7 , Servo2 = Portb.6 , Reload = 10
Config Timer1 = Timer , Prescale = 256
Enable Interrupts
Enable Timer1
Enable Urxc

Servo(1) = 40                                               'wartosc poczatkowa
Servo(2) = 40                                               'wartosc poczatkowa
Flag1 = 0
Flag2 = 0

Cursor Off
'-------------------------------------------------------------------------------
Cls
Lcd "start"                                                 'drukuj na lcd start
Wait 1                                                      'czekaj 1
Cls                                                         'czysc ekran
Lcd "servo test"                                            'drukuj na lcd
Wait 1                                                      'czekaj
Cls
Lcd "servo max"                                             'drukuj na lcd
Servo(1) = 180                                              'ustaw servo na max wartosc dobrana doswiadczalnie
Servo(2) = 180
Wait 1                                                      'czekaj
Cls
Servo(1) = 40                                               'servo na min
Servo(2) = 40
Lcd "servo MIN"
Wait 1
Cls

Lcd "sending synchro"
Wait 1
Cls
Print Chr(13);
Lcd "System on"
Wait 1

Cls
'-------------------------------------------------------------------------------
Echo On
On Timer1 Dela_y



Do
Serial_flag = Ischarwaiting()
Portb.0 = Serial_flag
If Serial_flag = 1 Then
   Inputbin Serial_rx(1) , 6
End If
Osy = Serial_rx(1) , 1
Osx = Serial_rx(2) , 1
Servo(1) = Osy
Servo(2) = Osx

If Serial_flag = 1 Then
If Flag1 = 1 Then
Cls
Lcd "osy " ; Osy
Locate 1 , 10
Lcd "osx " ; Osx
Flag1 = 0

End If
Else
Flag1 = 1
End If

Loop
End





'-------------------------------------------------------------------------------
Dela_y:
Timer1 = 3036                                               'dioda miga co 1 sek
Toggle Portb.5
Return


[ Dodano: 2009-06-22, 20:51 ]
Mój kod działa na 95% na początku jest coś na zasadzie synchronizacji która jest robiona tylko przy starcie programu. Zdarza się ze zgubi jakąś paczkę danych więc będę musiał dodać synchronizacje gdzie jeszcze w trakcje wykonywania programu ale coś mi brak weny twórczej ostatnio.

Zobacz w helpie na:
CONFIG SERIALIN | SERIALIN1 | SERIALIN2 | SERIALIN3 = BUFFERED , SIZE = size [, BYTEMATCH=ALL|BYTE|NONE] [,CTS=pin, RTS=pin , Threshold_full=num , Threshold_empty=num ]

bytematch - może cię dodatkowo zainteresować.

[ Dodano: 2009-06-22, 21:20 ]
Dodatkowo ściągnij sobie ze strony pololu http://www.pololu.com/docs/0J23 mały programik który wysyła paczki bytów idealny do testowania podczas pisania programów.
Ostatnio zmieniony 25 lip 2009, 0:10 przez Pikczu, łącznie zmieniany 1 raz.

Awatar użytkownika
Ertew
Użytkownik
Posty: 1418
Rejestracja: 03 lip 2005, 10:36
Lokalizacja: Leszno
Kontakt:

Post autor: Ertew » 22 cze 2009, 21:18

Proponuje zrobić to podobnie, jak sterowanie LCD przez magistrale 4bitową.
Przesłane po kolei 4 bajty o takich samych nagłówkach zostaną scalone w liczbę 2 bajtową i sklasyfikowane po nagłówku jako określające pierwszy parametr.
4 młodsze bity będą przenosić dane, a 4 starsze będą pokazywać, o jaką część ramki chodzi.
Oto przykład:

Kod: Zaznacz cały

0001 abcd - 1/4 danych
0001 efgh 
0001 ijkl 
0001 mnop 
-> wynik: LSB: abcdefgh  MSB: ijklmnop 
Po tym należy wysłać następną zmienną, ale nadając jej nagłówek 0010, a następnej 0011, i tak dalej...
Oczywiście zmienne 12 bitowe można przesyłać w 3 częściach, a jeśli potrzeba tylko 8 bitów, to w 2 częściach.
Po zakończeniu transmisji wszystkich zmiennych należy wysłać znak synchronizacji np. 1111 0101.


Zadaniem odbiornika było by oczekiwanie na x bajtów o wartościach pomiędzy jednym, a drugim końcem zakresu (dla 0001 xxxx był by to zakres od 16 do 31). Następnie odpowiednie ich scalenie (np. w 2 bajty).
Jeśli nie zostanie odebranych tyle bajtów, ile trzeba, to trzeba wyczyścić zmienne tymczasowe i wywołać przejście do części oczekiwania na synchronizację.

Po odebraniu wszystkich bajtów należy sprawdzić, czy żaden nie zginął, czyli czy bajt synchronizacji występuje dokładnie w tym miejscu co trzeba, a jeśli tak jest, to można przekazać te zmienne dalej programowi.

MiW
Użytkownik
Posty: 226
Rejestracja: 28 sty 2007, 11:32
Lokalizacja: Kraków
Kontakt:

Post autor: MiW » 22 cze 2009, 22:13

Dodając "smaczek" do dyskusji dodam, że zawsze można wysłać sformatowany tekst ASCII w formacie czytelnym dla ludzi np.:
'P' 'W' 'M' '=' '1' '3' 'koniec wiersza' :)

Awatar użytkownika
Pikczu
Użytkownik
Posty: 755
Rejestracja: 18 lip 2005, 18:33
Lokalizacja: Dublin
Kontakt:

Post autor: Pikczu » 23 cze 2009, 18:07

Teraz może niech się sam zainteresowany wypowie i niech powie co wymyślił
chętnie na jakieś przykłady popatrzę

ODPOWIEDZ