Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 22 lut 2026, o 11:52


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 9 ] 
Autor Wiadomość
PostNapisane: 9 kwi 2016, o 13:12 
Offline
Nowy

Dołączył(a): 05 kwi 2016
Posty: 3
Pomógł: 0

Witam,

Tworzę prosty nadajnik i odbiornik do sterowania wykorzystujący do tego dwie Atmegi8 (po jednej w każdym module). W nadajniku mam potencjometry. Sygnał jest konwertowany przez ADC i następnie wysyłany do odbiornika (przez UART), gdzie generowany jest sygnał PWM do serwomechanizmów.

Problem polega na tym żeby odbiornik rozróżniał, z którego potencjometru wysyłana jest wartość i żeby odpowiedni serwomechanizm (a nie inny) tą wartość otrzymał .

Myślałem nad jakimś sposobem adresowania każdego potencjometru i póki co najbliżej działający pomysł wygląda tak (fragment kodu):
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Generalnie pomysł polega na tym, że idzie 1 bajt "adres", następnie 1 bajt "dana". I tak w kółko. Tylko mam problem z zaimplementowaniem tego.

Sam ADC, PWM, UART itd działają OK kiedy przesyłam jedną wartość ( to jest tylko z jednego potencjometru, drugi mam zakomentowany). Kiedy mam oba, to też działa, ale ewidentnie sypią się błędy, bo jednym potencjometrem czasami steruję jednym serwem a czasami dwoma.

Za wszelką pomoc i sugestie dzięki



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 kwi 2016, o 13:57 
Offline
Użytkownik

Dołączył(a): 24 kwi 2013
Posty: 454
Pomógł: 30

Jeżeli chcesz analizować więcej niż jeden bajt, to wypadałoby zrobić buforowanie odebranych danych (rejestr kołowy).
W BB jest to dobrze opisane.
Jak już odbierzesz kompletną komendę (tak żeby program wiedział gdzie jest jej początek i koniec), to analizujesz ją np. funkcjami do porównywania stringów.
Np. serwo1=1024 analizujesz do znaku = i wybierasz serwo, później analizujesz do końca(np. do znaku nowej linni, lub końca stringa) i ustawiasz to serwo na zadaną wartość.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 kwi 2016, o 18:27 
Offline
Użytkownik

Dołączył(a): 25 lip 2015
Posty: 140
Zbananowany użytkownik

Pomógł: 18

Nie rejestr kołowy, a buffor ;-)

W tak prostym przypadku, nie używałbym stringów. Skoro odczytujesz dany kanał ADC, to znasz jego numer. Wobec tego proponuję skorzystać z takiej struktury:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Następnie wysyłasz taką strukturę przez usart. Odbiornik odbiera dwa bajty, z których pierwszy jest numerem kanału ADC, a drugi wartością.
Problemem w takim podejściu może być odpowiednia synchronizacja, bo jeśli z jakiegoś powodu, jeden bajt się straci, to wartości zostaną zamienione ze sobą. A więc należy obudować te dane w bajt lub bajty określające początek i koniec transmisji.

Może jeszcze odbiornik odpytywać pierwszy układ o dane z przetwornika. A jeżeli rolą nadajnika jest tylko pomiar, to może warto go zastąpić cyfrowym przetwornikiem A/C.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 kwi 2016, o 18:57 
Offline
Użytkownik

Dołączył(a): 19 paź 2014
Posty: 357
Lokalizacja: stolyca pyrlandii :)
Pomógł: 18

Właśnie kończę jeden temat w którym po raz pierwszy w życiu wykorzystywałem UART'a.
Mi bardzo pomogły poradniki video Mirka "WIFI232 - programowanie - Part ". Tytuł wskazywałby na moduły wifi, ale na zwykłym kablowym połączeniu działa to identycznie.
Tak na szybko podpowiadając w Twoim przypadku najwygodniej byłoby wykorzystać tokeny, które również są omawiane w tych poradnikach.
Serdecznie polecam te kilka poradników, tylko dzięki nim ja zrealizowałem swój układ.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 kwi 2016, o 19:00 
Offline
Użytkownik

Dołączył(a): 26 lip 2012
Posty: 291
Lokalizacja: okolice Opola
Pomógł: 20

Najlepszy sposób o ile nie mamy jakiś mega szybkości gdzie każdy bajt się liczy, to przesyłanie wartości tekstem z znacznikiem początku ramki (jakiś znak który na pewno nie będzie użyty w transmisji, np dwukropek) oraz CRC lub jakąś inna sumą kontrolną na końcu. Ramki kończymy wtedy znakiem końca linii lub pilnujemy ścisłych timingów pomiędzy bajtami i mamy piękną i bezproblemową transmisję. W dodatku odpadają wszelkie inne problemy typu little/big endian.

_________________
sig off ;(



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 kwi 2016, o 19:57 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 11 mar 2014
Posty: 1475
Pomógł: 167

Stosowanie znaków końca linii jest dobra przy komunikacji z wykorzystaniem liter i cyfr. Lecz jak my przesyłane dowolnych wartości bajtów, to już takie coś nie przejdzie :( Dlatego w poważniejszych rozwiązaniach takie dane się ramkuje wysyłając ramkę typowo w postaci:
._______ ______ _____ ______
| START | DANE | CRC | STOP |
| ______|______|_____|_____|
gdzie:
START - wybrany znak oznaczający początek ramki (np. znak ASCII STX)
STOP - wybrany znak oznaczający koniec ramki (np. znak ASCII ETX)
CRC - suma kontrolna liczona według wybranego algorytmu (może być więcej niż jeden bajt, ale jej długość jest stała i ustalona)
DANE - przesyłane dane (dowolna, zmienna liczba bajtów)

Aby można było przesłać wartości w danych pokrywające się wartością ze znakami START, STOP wykonuje się tzw. ESCejpowanie. Polega to na tym, że aby wysłać w polu DATA znak o wartości START, wysyła się znak ESC i następnie zanegowany znak START. Tak samo zamiast STOP wysyła się znak ESC i zanegowany znak STOP. Dodatkowo trzeba zrobić jeszcze jedno ESCejpowanie. Aby wysłać znak ESC wysyłamy ESC i zanegowany znak ESC.
Dzięki takiej operacji mamy zawsze łatwą synchronizację początku ramki (odebranie znaku START oznacza początek ramki). Wiemy także kiedy jest koniec ramki (odebranie znaku STOP). Oraz możemy przesłać dowolną wartość binarną w polu DATA.
A w kodzie odbiorczym wystarczy dodać jedno proste sprawdzenie. Jeżeli otrzymaliśmy znak ESC, to nie dodajemy go do bufora odbiorczego, tylko ustawiamy dodatkowy znacznik. Przy odbiorze bajtu jeżeli mamy znacznik ustawiony to taki bajt dodawany jest do bufora jako zanegowany (wysłany był jako zanegowany, więc podwójna negacja da właściwy znak). I tyle :) Nic więcej nie trzeba dodawać.

Jako sumę kontrolną warto stosować sumę, która ma pewną dodatkową właściwość. Chodzi o to by suma wyliczona na bajtach DATA i bajtach samej sumy (pole CRC) dawała zero. Dzięki temu licząc ją na bieżąco przy kolejnym bajcie, jak dojdziemy do znaku STOP, to gdy suma kontrolna jest poprawna, to mamy wartość 0 :) Taką właściwość ma np. bardzo popularny algorytm wyliczający sumę kontrolną CRC16.

--
Pozdrawiam,
Robert



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 14 kwi 2016, o 12:18 
Offline
Nowy

Dołączył(a): 05 kwi 2016
Posty: 3
Pomógł: 0

Witam.

Zdecydowałem się na wykorzystanie tokenów. Z pomocą BB i GB wyszło coś takiego:

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Z nadajnika wysyłam coś takiego (narazie stałe wartości w ramach testowania, później będą to odczyty z ADC):

Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Problem polega na tym, że funkcja odbiorcza nie rozróżnia mi (nie wiem czemu) poszczególnych, powiedzmy adresów.
To jest:

Wysyłam z nadajnika tylko ramkę dla "silnik0". Odbiornik odbiera, ale nie przypisuje tego "silnikowi0", a pierwszemu napotkanemu (w funkcji analizuj_dane_rs232), czyli "silnik2". Reszta komend w nadajniku jest zakomentowana.

Z kolei kiedy wyślę tylko komendy dla diody1 i diody2 (lecz komendy dla silników i serwa są zakomentowane) to odbiornik już rozróżnia prawidłowo. Kiedy jednak dodam do tego jeszcze komendę dla np. serwa to już się sypie i serwo dostaje jakiś misz masz.

Suma sumarum wydaję mi się, że błąd polega po stronie odbiorczej. Coś chyba nie tak ze wskaźnikiem. No chyba, że nadajnik też miesza bajty, choć mało prawdopodobne.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 17 kwi 2016, o 17:50 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 12 maja 2014
Posty: 1089
Pomógł: 34

rskup napisał(a):
Stosowanie znaków końca linii jest dobra przy komunikacji z wykorzystaniem liter i cyfr. Lecz jak my przesyłane dowolnych wartości bajtów, to już takie coś nie przejdzie :( Dlatego w poważniejszych rozwiązaniach takie dane się ramkuje wysyłając ramkę typowo w postaci:
._______ ______ _____ ______
| START | DANE | CRC | STOP |
| ______|______|_____|_____|
gdzie:
START - wybrany znak oznaczający początek ramki (np. znak ASCII STX)
STOP - wybrany znak oznaczający koniec ramki (np. znak ASCII ETX)
CRC - suma kontrolna liczona według wybranego algorytmu (może być więcej niż jeden bajt, ale jej długość jest stała i ustalona)
DANE - przesyłane dane (dowolna, zmienna liczba bajtów)

Aby można było przesłać wartości w danych pokrywające się wartością ze znakami START, STOP wykonuje się tzw. ESCejpowanie. Polega to na tym, że aby wysłać w polu DATA znak o wartości START, wysyła się znak ESC i następnie zanegowany znak START. Tak samo zamiast STOP wysyła się znak ESC i zanegowany znak STOP. Dodatkowo trzeba zrobić jeszcze jedno ESCejpowanie. Aby wysłać znak ESC wysyłamy ESC i zanegowany znak ESC.
Dzięki takiej operacji mamy zawsze łatwą synchronizację początku ramki (odebranie znaku START oznacza początek ramki). Wiemy także kiedy jest koniec ramki (odebranie znaku STOP). Oraz możemy przesłać dowolną wartość binarną w polu DATA.
A w kodzie odbiorczym wystarczy dodać jedno proste sprawdzenie. Jeżeli otrzymaliśmy znak ESC, to nie dodajemy go do bufora odbiorczego, tylko ustawiamy dodatkowy znacznik. Przy odbiorze bajtu jeżeli mamy znacznik ustawiony to taki bajt dodawany jest do bufora jako zanegowany (wysłany był jako zanegowany, więc podwójna negacja da właściwy znak). I tyle :) Nic więcej nie trzeba dodawać.

Jako sumę kontrolną warto stosować sumę, która ma pewną dodatkową właściwość. Chodzi o to by suma wyliczona na bajtach DATA i bajtach samej sumy (pole CRC) dawała zero. Dzięki temu licząc ją na bieżąco przy kolejnym bajcie, jak dojdziemy do znaku STOP, to gdy suma kontrolna jest poprawna, to mamy wartość 0 :) Taką właściwość ma np. bardzo popularny algorytm wyliczający sumę kontrolną CRC16.

--
Pozdrawiam,
Robert

Fajnie opisane podejście - a masz może do tego juz opracowany kod którym mógłbyś się podzielić ?

Sent from my GT-I9506 using Tapatalk

_________________
sig off ;(



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 18 kwi 2016, o 21:41 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 11 mar 2014
Posty: 1475
Pomógł: 167

Niestety kod używany mam w komercyjnych programach i musiałbym wybebeszyć go by móc go udostępnić. Nie wiem czy nie prościej byłoby od początku to napisać. Jak znajdę czas to może coś podrzucę. Ale nie obiecuję :(

--
Pozdrawiam,
Robert



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 9 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników i 1 gość


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO