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



Teraz jest 1 gru 2024, o 13:17


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 4 ] 
Autor Wiadomość
PostNapisane: 13 cze 2012, o 15:08 
Offline
Nowy
Avatar użytkownika

Dołączył(a): 06 maja 2012
Posty: 13
Pomógł: 0

Chciałbym wam przedstawić bardzo ciekawy sposób komunikacji z naszymi mikrokontrolerami, a mianowicie sterowanie za pomocą własnych komunikatów. Na wstępie informuję iż przedstawioną bibliotekę pisałem na zajęciach z programowania ARM w C wg specyfikacji laboratorium. Służyła ona do sterowania serwomechanizmem poprzez interfejs RS232, jednak jej zastosowanie może być zgoła inne. Jako że piszę obecnie pracę mgr na temat bezprzewodowego systemu pomiarowego w oparciu o moduły RFM12B i mikrokontrolery ATmega88, pomyślałem że fajnie byłoby wysyłać komendy sterujące do modułu nadrzędnego przez UART. Przerobiłem bibliotekę na rzekomy AVR i chciałbym się tym z wami podzielić, aby każdy mógł z łatwością dogadywać się z mikrokontrolerem za pomocą własnych komend ASCII. Należy jeszcze tutaj wspomnieć o obsłudze interfejsu UART. Wszelkie dane wysłane przez UART są w postaci łańcuchów znakowych. Stworzone są dwa oddzielne bufory: dla nadajnika i odbiornika. Znaki odbierane są do momentu napotkania znaku terminatora, czyli Enter '\r', na końcu dodawany jest NULL. Całość oparta na przerwaniach. A więc do dzieła :)


Komunikaty(komendy):
Komunikaty mają postać łańcuchów znakowych zakończonych znakiem NULL (ang. Null terminated string) i składają się z jednego bądź więcej tokenów. Tokeny to sekwencje znaków oddzielone jednym lub wieloma delimiterami. Funkcję delimitera pełnić będzie znak spacji ‘\s’ (20h, 32).
Przykład komunikatu pokazano poniżej:
„Ola ma jeża”.
Składa się on z trzech tokenów rozdzielonych dwoma delimiterami.

Dekodowanie:
Dekodowanie komunikatu polega na policzeniu ilości wykrytych tokenów, oraz ich zdekodowaniu. Zdekodowanie tokenu to określenie jego typu i wartości a następnie zapamiętanie ich w odpowiedniej strukturze danych.

Typ tokenu:
Będziemy rozróżniali trzy typy tokenów: KEYWORD, NUMBER i STRING.
Token zostanie rozpoznany jako KEYWORD jeżeli będzie należał do listy słów kluczowych. W takim przypadku wartość tokenu stanowić będzie typ wyliczeniowy enum.

Przykład: Załóżmy, że zadeklarowano następującą listę słów kluczowych:

Keyword (enum)----------odpowiadający jej łańcuch znakowy (char[])
LD-----------------------“load”
ST ----------------------“store”
RST----------------------“reset”

Wtedy tokeny “store” i „reset” zostaną zdekodowane w sposób następujący
token -------------- typ-----------wartość (enum)
„reset” -------------KEYWORD------RST
“store”--------------KEYWORD------ST

Token zostanie rozpoznany jako NUMBER jeżeli będzie spełniał format liczby zapisanej w kodzie heksadecymalnie. W takim przypadku wartość tokenu stanowić będzie wartość liczby.

Przykład:
token----------typ-----------wartość (unsigned int )
„0x10”--------- NUMBER------ 16 (decymalnie)
„0x0A”---------NUMBER ------10 (decymalnie)

Token zostanie rozpoznany jako STRING jeżeli nie zostanie rozpoznany jako KEYWORD ani jako NUMBER. Wartość tokenu typu STRING stanowi wskaźnik na ten token.

Przykład:
token---------typ----------wartość (char *)
„add”---------STRING------Wskaźnik na „add”
“subtract”----STRING------ Wskaźnik na “subtract”

Typ tokenu jest przechowywany w zmiennej wyliczeniowej zdefiniowanej jak poniżej:
Kod:
typedef enum TokenType {KEYWORD, NUMBER, STRING};


Wartość tokenu:
Ponieważ typ tokenu może być różny (typ wyliczeniowy, liczba, łaocuch znakowy) dlatego jego wartość nie może być przechowywana w zmiennej jednego typu. Z tego względu do przechowywania wartości tokenu została wykorzystana unia zmiennych zdefiniowana jak poniżej:
Kod:
typedef enum KeywordCode { LD, ST, RST};
typedef union TokenValue
{
enum KeywordCode eKeyword; // jezeli KEYWORD
unsigned int uiNumber; // jezeli NUMBER
char * pcString; // jezeli STRING
};


Tablica tokenów:

Typ i wartośc tokenu są przechowywane w jednej strukturze zdefiniowanej jak poniżej:
Kod:
typedef enum TokenType { KEYWORD, NUMBER, STRING};
typedef struct Token
{
enum TokenType eType; // KEYWORD, NUMBER, STRING
union TokenValue uValue; // enum, unsigned int, char*
}

Ponieważ w pojedynczym komunikacie mamy najczęściej do czynienia więcej niż z jednym tokenem wiec wynik dekodowania jest przechowywany w tablicy tokenów zdefiniowanej jak poniżej:
Kod:
#define MAX_TOKEN_NR 3 //maksymalna dopuszczalna ilość tokenów
struct Token asToken[MAX_TOKEN_NR]


Ilośc tokenów:
Oprócz wypełnienia tablicy tokenów wynikiem dekodowania będzie również liczba odebranych tokenów zapamiętana w zmiennej:
Kod:
unsigned char ucTokenNr;

Dekodowanie komunikatu polega na wypełnieniu tablicy sToken na podstawie odebranego łaocucha znakowego.

Przykład: Wynik rozkodowania komunikatu: „load 0x20 immediately”.
token Type Value
“load” ----------KEYWORD------ LD
„0x20”----------NUMBER-------- 32 (decymalnie)
„immediately”--- STRING-------- wskaznik na „immediately”

Lista słów kluczowych:
Do sprawdzenia czy token jest typu KEYWORD musi istnieć lista łańcuchów znakowych rozpoznawanych jako słowo kluczowe. Elementem listy jest struktura składająca się z dwóch elementów – typu słowa kluczowego oraz związanego z nim łańcucha znakowego.
Kod:
#define MAX_KEYWORD_STRING_LTH 10 // mksymalna dlugosc komendy
typedef enum KeywordCode { LD, ST, RST};
typedef struct Keyword
{
enum KeywordCode eCode;
char cString[MAX_KEYWORD_STRING_LTH + 1];
};

Deklaracja listy poprawnych słów kluczowych wygląda następująco, to właśnie w tym miejscu definiujemy własne słowa kluczowe(oraz w samym enum KeywordCode):
Kod:
#define MAX_KEYWORD_NR 3
struct Keyword asKeywordList[MAX_KEYWORD_NR]=
{
{RST,"reset"},
{LD, "load" },
{ST, "store"}
};

Zmienne globalne:
Kod:
asKeywordList[] // uzywana przez bStringToCommand
asToken[] // wypelniana przez DecodeMsg
ucTokenNr // liczba tokenów w zdekodowanym komunikacie

Funkcje:
Do dekodowania potrzebne są następujące funkcje:

ucFindTokensInString (char *String)
Argumentem funkcji jest wskaźnik na początek dekodowanego komunikatu, funkcja zwraca ilość znalezionych tokenów w komunikacie. Zadaniem funkcji jest wypełnianie pola uValue tablicy asToken wskaźnikami na początki znalezionych tokenów w łańcuchu String.
Implementacja funkcji ma postać automatu, ponadto funkcja jest odporna na:
- pusty łańcuch, tj. Łańcuch składający się z samych delimiterów
- delimiter przed pierwszym tokenem
- więcej niż jeden delimiter miedzy dwoma tokenami

eSringToKeyword (char cStr[],enum eKeywordType *peKeyword)
Zadaniem funkcji jest zamienić łańcuch znakowy na komendę na podstawie listy komend.
W przypadku powodzenia funkcja zwraca wartość OK.
W przypadku niepowodzenia funkcja zwraca wartości ERROR.

DecodeTokens(void)

Zadaniem funkcji jest zdekodować wszystkie tokeny tj. dla każdego tokenu ustalić jego typ i wartość i wpisać je do tablicy asToken.
Funkcja korzysta ze wskaźników początków tokenów znajdujacych się w asToken[0..ucTokenNr].uValue.pcString (patrz funkcja ucFindTokensInString).

DecodeMsg(char *String)

Na podstawie String-a i asCommandList funkcja wypełnia tablice sToken i ustawia zmienna ucTokenNr.
W tym celu:
- indeksuje początki tokenów
- zamienia wszystkie delmitery na nulle
- dekoduje poszczególne tokeny.

Ponadto do dekodowania wykorzystywane są jeszcze inne funkcje służące do pracy na łańcuchach:

void ReplaceCharactersInString(char cString[], char cOldChar, char cNewChar);
Funkcja służy do podmiany znaku cOldChar na znak cNewChar w łańcuch cString.

enum CompResult eCompareString(char cStr1[], char cStr2[]);
Funnkcja służy do porównywania dwóch stringów, jeżeli śa takie same funkcja zwraca EQUAL jeżeli nie są takie same zwraca NOTEQUAL

void AppendUIntToString (unsigned int uiValue, char cDestinationStr[]);
Funkcja służy do dodania liczby uiValue do końca łańcucha cDestinationStr, liczba zamieniana jest na string w postaci hexadecymalnej.

Result eHexStringToUInt(char cStr[], unsigned int *puiValue);
Funkcja zamienia string w postaci liczby hexadecymalnej cStr na jej wartość i umieszcza jak pod wskaźniekiem puiValue.

Chwili wyjaśnienia wymaga program główny w pętli while. Otóż w pętli sprawdzany jest status odbiornika UART, jeśli pojawił się jakiś komunikat status odbiornika zmienia się na READY. Następnie komunikat jest dekodowany i w zależności od wysłanej komendy ustawiane są flagi, jest to tzw. „producent”. Jeżeli „producent” ustawi którąś z flag, oraz nadajnik jest w stanie bezczynności (FREE) to UART zajmie się „konsumpcją” „wyprodukowanej” flagi.

Po wgraniu programu do AVR i wpisaniu w polu terminala np. komunikatu „calc 0x0002„
Mikrokontroler natychmiast odeśle nam odpowiedź w postaci wartości odebranej pomnożonej przez 2 , czyli „calc 0x0004„.

W taki prosty, nieblokujący sposób można rozkazywać naszemu prockowi. ;)

Załączam kompletną bibliotekę pod ATmege88,


Załączniki:

Aby zobaczyć załączniki musisz się zalogować. Tylko zalogowani użytkownicy mogą oglądać i pobierać załączniki.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 13 cze 2012, o 15:19 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 04 paź 2011
Posty: 8587
Pomógł: 337

No brawo kolego , przydatna zabaweczka i oczywiście ładnie napisana :)
Tak przy okazji to połamania na obronie ...

_________________
Zbuduj swój system [url=https://helion.pl/ksiazki/w-labiryncie-iot-budowanie-urzadzen-z-wykorzystaniem-ukladow-esp8266-i-esp32-andrzej-gromczynski,wlablo.htm#format/d]IOT[/url]



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 13 cze 2012, o 15:39 
Offline
Moderator
Avatar użytkownika

Dołączył(a): 03 paź 2011
Posty: 27315
Lokalizacja: Szczecin
Pomógł: 1041

SunRiver udałoby ci się ten wątek przenieść do działu "Projekty programistyczne" ? bo zasługuje na to żeby tam się pojawić ;)

_________________
zapraszam na blog: http://www.mirekk36.blogspot.com (mój nick Skype: mirekk36 ) [ obejrzyj Kurs EAGLE ] [ mój kanał YT TV www.youtube.com/mirekk36 ]



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 13 cze 2012, o 15:46 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 04 paź 2011
Posty: 8587
Pomógł: 337

Mówisz masz !!
Proszę bardzo SZEFUŃCIU :P

_________________
Zbuduj swój system [url=https://helion.pl/ksiazki/w-labiryncie-iot-budowanie-urzadzen-z-wykorzystaniem-ukladow-esp8266-i-esp32-andrzej-gromczynski,wlablo.htm#format/d]IOT[/url]



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: 4 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

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


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