<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl-pl">
<link rel="self" type="application/atom+xml" href="https://forum.atnel.pl/feed.php?f=23&amp;t=1170&amp;mode" />

<title>ATNEL tech-forum</title>
<link href="https://forum.atnel.pl/index.php" />
<updated>2012-06-13T15:46:31+01:00</updated>

<author><name><![CDATA[ATNEL tech-forum]]></name></author>
<id>https://forum.atnel.pl/feed.php?f=23&amp;t=1170&amp;mode</id>
<entry>
<author><name><![CDATA[SunRiver]]></name></author>
<updated>2012-06-13T15:46:31+01:00</updated>
<published>2012-06-13T15:46:31+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7941#p7941</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7941#p7941"/>
<title type="html"><![CDATA[Re: Dekodowanie komunikatów - własne komendy sterujące (UART]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7941#p7941"><![CDATA[
Mówisz masz !!<br />Proszę bardzo SZEFUŃCIU <img src="https://forum.atnel.pl/images/smilies/icon_razz.gif" alt=":P" title="Pokazuje język" /><p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=58">SunRiver</a> — 13 cze 2012, o 15:46</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[mirekk36]]></name></author>
<updated>2012-06-13T15:39:42+01:00</updated>
<published>2012-06-13T15:39:42+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7940#p7940</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7940#p7940"/>
<title type="html"><![CDATA[Re: Dekodowanie komunikatów - własne komendy sterujące (UART]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7940#p7940"><![CDATA[
SunRiver udałoby ci się ten wątek przenieść do działu &quot;Projekty programistyczne&quot; ? bo zasługuje na to żeby tam się pojawić <img src="https://forum.atnel.pl/images/smilies/icon_e_wink.gif" alt=";)" title="Puszcza oko" /><p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=54">mirekk36</a> — 13 cze 2012, o 15:39</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[SunRiver]]></name></author>
<updated>2012-06-13T15:19:47+01:00</updated>
<published>2012-06-13T15:19:47+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7937#p7937</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7937#p7937"/>
<title type="html"><![CDATA[Re: Dekodowanie komunikatów - własne komendy sterujące (UART]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7937#p7937"><![CDATA[
No brawo kolego , przydatna zabaweczka  i oczywiście ładnie napisana <img src="https://forum.atnel.pl/images/smilies/icon_e_smile.gif" alt=":)" title="Szczęśliwy" /><br />Tak przy okazji to połamania na obronie ...<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=58">SunRiver</a> — 13 cze 2012, o 15:19</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[Drutłajer]]></name></author>
<updated>2012-06-13T15:08:58+01:00</updated>
<published>2012-06-13T15:08:58+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7935#p7935</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7935#p7935"/>
<title type="html"><![CDATA[Dekodowanie komunikatów - własne komendy sterujące (UART)]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=1170&amp;p=7935#p7935"><![CDATA[
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 <img src="https://forum.atnel.pl/images/smilies/icon_e_smile.gif" alt=":)" title="Szczęśliwy" /> <br /><br /><br /><strong>Komunikaty(komendy):</strong><br />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).<br />Przykład komunikatu pokazano poniżej:<br />„Ola ma jeża”.<br />Składa się on z trzech tokenów rozdzielonych dwoma delimiterami.<br /><br /><strong>Dekodowanie:</strong><br />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.<br /><br /><strong>Typ tokenu:</strong><br /> Będziemy rozróżniali trzy typy tokenów: KEYWORD, NUMBER i STRING.<br />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.<br /><br />Przykład: Załóżmy, że zadeklarowano następującą listę słów kluczowych:<br /><br />Keyword (enum)----------odpowiadający jej łańcuch znakowy (char[]) <br />LD-----------------------“load” <br />ST ----------------------“store” <br />RST----------------------“reset” <br /><br />Wtedy tokeny “store” i „reset” zostaną zdekodowane w sposób następujący<br />token -------------- typ-----------wartość (enum) <br />„reset” -------------KEYWORD------RST <br />“store”--------------KEYWORD------ST <br /><br />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.<br /><br />Przykład:<br />token----------typ-----------wartość (unsigned int ) <br />„0x10”--------- NUMBER------ 16 (decymalnie) <br />„0x0A”---------NUMBER ------10 (decymalnie) <br /><br />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.<br /><br />Przykład:<br />token---------typ----------wartość (char *) <br />„add”---------STRING------Wskaźnik na „add” <br />“subtract”----STRING------ Wskaźnik na “subtract” <br /><br />Typ tokenu jest przechowywany w zmiennej wyliczeniowej zdefiniowanej jak poniżej: <br /><div class="codetitle"><b>Code:</b></div><div class="codecontent">typedef enum TokenType {KEYWORD, NUMBER, STRING};</div><br /><br /><strong>Wartość tokenu:</strong><br />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:<br /><div class="codetitle"><b>Code:</b></div><div class="codecontent">typedef enum KeywordCode { LD, ST, RST};<br />typedef union TokenValue<br />{<br />enum KeywordCode eKeyword; // jezeli KEYWORD<br />unsigned int uiNumber; // jezeli NUMBER<br />char * pcString; // jezeli STRING<br />};</div><br /><strong><br />Tablica tokenów:</strong><br />Typ i wartośc tokenu są przechowywane w jednej strukturze zdefiniowanej jak poniżej:<br /><div class="codetitle"><b>Code:</b></div><div class="codecontent">typedef enum TokenType { KEYWORD, NUMBER, STRING};<br />typedef struct Token<br />{<br />enum TokenType eType; // KEYWORD, NUMBER, STRING<br />union TokenValue uValue; // enum, unsigned int, char*<br />}</div><br />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:<br /><div class="codetitle"><b>Code:</b></div><div class="codecontent">#define MAX_TOKEN_NR 3 //maksymalna dopuszczalna ilość tokenów<br />struct Token asToken&#91;MAX_TOKEN_NR&#93;</div><br /><br /><strong>Ilośc tokenów:</strong><br />Oprócz wypełnienia tablicy tokenów wynikiem dekodowania będzie również liczba odebranych tokenów zapamiętana w zmiennej:<br /><div class="codetitle"><b>Code:</b></div><div class="codecontent">unsigned char ucTokenNr;</div><br />Dekodowanie komunikatu polega na wypełnieniu tablicy sToken na podstawie odebranego łaocucha znakowego.<br /><br />Przykład: Wynik rozkodowania komunikatu: „load 0x20 immediately”.<br />token            Type            Value <br />“load” ----------KEYWORD------ LD <br />„0x20”----------NUMBER-------- 32 (decymalnie) <br />„immediately”--- STRING-------- wskaznik na „immediately” <br /><br /><strong>Lista słów kluczowych:</strong><br />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.<br /><div class="codetitle"><b>Code:</b></div><div class="codecontent">#define MAX_KEYWORD_STRING_LTH 10 // mksymalna dlugosc komendy<br />typedef enum KeywordCode { LD, ST, RST};<br />typedef struct Keyword<br />{<br />enum KeywordCode eCode;<br />char cString&#91;MAX_KEYWORD_STRING_LTH + 1&#93;;<br />};</div><br />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): <br /><div class="codetitle"><b>Code:</b></div><div class="codecontent">#define MAX_KEYWORD_NR 3 <br />struct Keyword asKeywordList&#91;MAX_KEYWORD_NR&#93;=<br />{ <br />{RST,&quot;reset&quot;}, <br />{LD, &quot;load&quot; }, <br />{ST, &quot;store&quot;} <br />};</div><br /><strong>Zmienne globalne:</strong> <br /><div class="codetitle"><b>Code:</b></div><div class="codecontent">asKeywordList&#91;&#93; // uzywana przez bStringToCommand <br />asToken&#91;&#93; // wypelniana przez DecodeMsg<br />ucTokenNr // liczba tokenów w zdekodowanym komunikacie</div><br /><strong>Funkcje:</strong><br />Do dekodowania potrzebne są następujące funkcje:<br /><br /><strong>ucFindTokensInString (char *String)</strong><br />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.<br />Implementacja funkcji ma postać automatu, ponadto funkcja jest odporna na:<br />- pusty łańcuch, tj. Łańcuch składający się z samych delimiterów<br />- delimiter przed pierwszym tokenem<br />- więcej niż jeden delimiter miedzy dwoma tokenami<br /><br /><strong>eSringToKeyword (char cStr[],enum eKeywordType *peKeyword)</strong><br />Zadaniem funkcji jest zamienić łańcuch znakowy na komendę na podstawie listy komend.<br />W przypadku powodzenia funkcja zwraca wartość OK.<br />W przypadku niepowodzenia funkcja zwraca wartości ERROR.<br /><strong><br />DecodeTokens(void)</strong><br />Zadaniem funkcji jest zdekodować wszystkie tokeny tj. dla każdego tokenu ustalić jego typ i wartość i wpisać je do tablicy asToken.<br />Funkcja korzysta ze wskaźników początków tokenów znajdujacych się w asToken[0..ucTokenNr].uValue.pcString (patrz funkcja ucFindTokensInString).<br /><strong><br />DecodeMsg(char *String)</strong><br />Na podstawie String-a i asCommandList funkcja wypełnia tablice sToken i ustawia zmienna ucTokenNr.<br />W tym celu:<br />- indeksuje początki tokenów<br />- zamienia wszystkie delmitery na nulle<br />- dekoduje poszczególne tokeny.<br /><br />Ponadto do dekodowania wykorzystywane są jeszcze inne funkcje służące do pracy na łańcuchach:<br /><br /><strong>void ReplaceCharactersInString(char cString[], char cOldChar, char cNewChar);</strong><br />Funkcja służy do podmiany znaku cOldChar na znak cNewChar w łańcuch cString.<br /><br /><strong>enum CompResult eCompareString(char cStr1[], char cStr2[]);</strong><br />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<br /><br /><strong>void AppendUIntToString (unsigned int uiValue, char cDestinationStr[]);</strong><br />Funkcja służy do dodania liczby uiValue do końca łańcucha cDestinationStr, liczba zamieniana jest na string w postaci hexadecymalnej.<br /><br /><strong>Result eHexStringToUInt(char cStr[], unsigned int *puiValue);</strong><br />Funkcja zamienia string w postaci liczby hexadecymalnej cStr na jej wartość i umieszcza jak pod wskaźniekiem puiValue.<br /><br />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.<br /><br />Po wgraniu programu do AVR i wpisaniu w polu terminala np. komunikatu „calc 0x0002„<br />Mikrokontroler natychmiast odeśle nam odpowiedź w postaci wartości odebranej pomnożonej przez 2 , czyli  „calc 0x0004„.<br /><br />W taki prosty, nieblokujący sposób można rozkazywać naszemu prockowi. <img src="https://forum.atnel.pl/images/smilies/icon_e_wink.gif" alt=";)" title="Puszcza oko" /> <br /><br />Załączam kompletną bibliotekę pod ATmege88,<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=357">Drutłajer</a> — 13 cze 2012, o 15:08</p><hr />
]]></content>
</entry>
</feed>