<?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=4160&amp;mode" />

<title>ATNEL tech-forum</title>
<link href="https://forum.atnel.pl/index.php" />
<updated>2013-09-12T22:57:22+01:00</updated>

<author><name><![CDATA[ATNEL tech-forum]]></name></author>
<id>https://forum.atnel.pl/feed.php?f=23&amp;t=4160&amp;mode</id>
<entry>
<author><name><![CDATA[marekg]]></name></author>
<updated>2013-09-12T22:57:22+01:00</updated>
<published>2013-09-12T22:57:22+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=4160&amp;p=49385#p49385</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=4160&amp;p=49385#p49385"/>
<title type="html"><![CDATA[Obsługa RC5 w przerwaniu timera 8 bit]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=4160&amp;p=49385#p49385"><![CDATA[
Witam<br /><br />Jako nowy użytkownik chciałbym się przywitać i jednocześnie podzielić swoim sposobem na obsługę pilota nadającego w kodzie RC5. W sieci, również tutaj, opisywanych jest wiele implementacji tego zagadnienia, jednak żadna nie pasowała do moich potrzeb. Pokusiłem się więc o opracowanie własnego kodu.<br />W moim projekcie zajęte są zasoby sprzętowe używane zazwyczaj do tego celu, a mianowicie timer 16 bitowy i jego przerwanie ICP oraz wszystkie przerwania zewnętrzne - INTx.<br /><br />Założenia są następujące:<br />- Należy wykorzystać przerwanie 8 bitowego timera (które przy okazji może również prowadzić inne &quot;czasówki&quot;)<br />- Odbieranie kodów RC5 nie może blokować pracy procesora ani zbytnio go obciążać.<br /><br />Wykorzystałem algorytm opisany w nocie Atmela &quot;AVR410: RC5 IR Remote Control Receiver&quot;<br />Algorytm ten (z małą zmianą) zaimplementowałem jednak w postaci maszyny stanu pracującej w funkcji przerwania timera wywoływanej co 0.1ms. W przerwaniu tym próbkowany jest stan wyjścia odbiornika podczerwieni podłączonego do dowolnego pinu jednego z portów procesora.<br /><br />Proponowana przeze mnie implementacja działa bardzo pewnie. Nie stwierdziłem błędnie odebranych ani odrzuconych ramek RC5. <br /><br />Poniżej przedstawiam kod i dalej opis działania.<br />[syntax=c]//definicja preprocesora<br /><br />#define IRP   xxxxx // tu należy zdefiniować sobie pin do którego podpięty jest odbiornik podczerwieni <br /><br />// definicje zmiennych globalnych wykorzystywanych do obslugi rc5<br /><br />volatile unsigned char stanIR=0, bcIR, timIR, flagIR, refIR34, refIR54, old_IRP, new_IRP; <br />volatile unsigned int cmdIR;<br /><br />//poniższy kod należy wkleić do funkcji obsługi przerwania wywoływanej co 0.1ms<br /><br />new_IRP=IRP;<br />switch(stanIR)<br />{<br />  case 0:      // stan -0 - czekanie na obsługe ostatnio odebranego kodu RC5 przez aplikacje<br /><br />     if (flagIR==0)<br />       {stanIR=1;<br />        timIR=0;}<br /><br />  break;<br />  <br />  case 1:  // stan -1- czekanie na 25,4ms podczerwonej &quot;ciszy&quot;<br /><br />     if (new_IRP) <br />       {timIR++;<br />         if (timIR&gt;254)<br />           {stanIR=2;<br />             bcIR=0; timIR=0; refIR=0; refIR34=0; refIR54=0; cmdIR=0; toggleIR=0;}<br />        }<br />     else<br />        timIR=0;<br /><br />  break;<br /><br />  case 2: // stan -2- oczekiwanie na pierwszy bit startu<br /><br />    if ((old_IRP)&amp;&amp;(!new_IRP)) stanIR=3;<br /><br />  break;<br /><br />  case 3: // stan -3- oczekiwanie na drugi bit startu, pomiar referencyjnego czasu trwania transmisji jednego bitu<br /><br />     timIR++;<br />     if (timIR&gt;22) {stanIR=1; timIR=0;}<br />     if ((old_IRP)&amp;&amp;(!new_IRP))<br />        if (timIR&lt;13)  <br />          {stanIR=1; timIR=0;}<br />        else <br />          {refIR34=((timIR*3)/4); refIR54=((timIR*5)/4); timIR=0; stanIR=4;}   <br />  break;<br /><br />  case 4: // stan - 4 - odbiór pozostałych 12 bitów ramki RC5<br /><br />      timIR++;<br />      if (timIR==refIR34)<br />        {cmdIR=(cmdIR&lt;&lt;1)|new_IRP; bcIR++; <br />          if (bcIR==12) {flagIR=1; stanIR=0;    break;}<br />        }<br />      if ((old_IRP!=new_IRP)&amp;&amp;(timIR&gt;=refIR34)) <br />        timIR=0;  <br />     if (timIR&gt;refIR54)<br />       {stanIR=1; timIR=0;} <br />  break;<br />}<br />old_IRP=new_IRP; // zapamiętanie &quot;starego&quot; poziomu wyjscia odbiornika podczerwieni[/syntax]<br /><br />A teraz jak to działa:<br /><br />Z punktu widzenia użytkownika kodu, wystarczy wiedzieć, że po odebraniu ramki RC5 ustawiana jest flaga <em>flagIR</em>. Po wykryciu tego faktu należy obsłużyć odebraną komendę, która znajduje się w zmiennej cmdIR a następnie wyzerować flagę. W cmdIR znajduje się cała ramka RC5 łącznie z adresem urządzenia oraz <em>toggle bitem</em>, szczególnie o tym ostatnim warto pamiętac....<br /><br />Poniżej opis dla dociekliwych:<br /><br />Opis zmiennych:<br /><em>cmdIR</em> - zmienna 16 bitowa w której przechowywana jest ostatnio odebrana ramka RC5.<br /><em>flagIR</em> - flaga ustawiana po poprawnym odebraniu ramki RC5. Flaga ta powinna być wyzerowana przez aplikacje po obsłużeniu odebranego polecenia<br /><em>stanIR</em> - główna zmienna sterująca maszyny stanu.<br /><em>timIR</em> - zmienna służąca do zliczania czasu.<br /><em>new_IRP</em> - aktualny stan wyjścia odbirnika podczerwieni.<br /><em>old_IRP</em> - stan wyjścia odbiornika podczerwieni z poprzedniego cyklu (poprzedniego wywołania przerwania)<br /><em> bcIR</em> - licznik ilości odebranych bitów<br /><em>refIR34, refIR54</em> - referencyjne czasy obliczone jako  odpowiednio 3/4 i 5/4 czasu trwania transmisji jednego bitu.<br /><br />Opis kodu:<br /><br />W pierwszej linii aktualny stan wyjścia odbiornika podczerwieni zapamiętywany jest w zmiennej <em>new_IRP</em>, jest to konieczne, ponieważ zmiana stanu w trakcie wykonywania kodu, może w pewnych przypadkach powodować błędne odrzucanie ramki danych.  W ostatniej linii, wartość ta zapamiętywana jest w zmiennej <em>old_IRP</em> i służy jako wartość &quot;poprzednia&quot; w następnym wywołaniu przerwania.<br /><br />Właściwą pracę maszyny stanu rozpoczyna instrukcja <em>switch</em>. Kod opisujący działanie maszyny w poszczególnych stanach zawarty jest  pomiędzy parami instrukcji<em> case - break</em>.<br /><br /><strong>Stan 0: </strong><br /><br />W tym stanie maszyna oczekuje na wyzerowanie flagi<em> flagIR</em>, co oznacza, że ostatnio odebrana ramka została już obsłużona i można przystąpić do odbioru kolejnej. Jeśli <em>flagIR == 0</em> następuje przejście do stanu 1.<br /><br /><strong>Stan 1:</strong><br /><br />W tym stanie zmienna <em>timIR</em> wykorzystana jest od odmierzania czasu trwania stanu wysokiego na wyjściu odbiornika podczerwieni, a więc czasu trwania &quot;ciszy w eterze&quot;. Jeżeli wykryte zostanie 25.4 ms nieprzerwanej ciszy, maszyna przechodzi do stanu 2.<br /><br /><strong>Stan 2:</strong> <br /><br />W tym stanie maszyna oczekuje na zbocze opadające na wyjściu odbiornika. Może ono oznaczać środek pierwszego bitu startu. Jeśli takie zbocze zostanie wykryte, następuje wyzerowanie licznika<em> timIR</em> i przejście do stanu 3.<br /><br /><strong>stan 3:</strong> <br /><br />W tym stanie maszyna oczekuje na kolejne zbocze opadające na wyjściu odbiornika. Może ono oznaczać środek drugiego bitu startu. Jednocześnie mierzony jest czas jaki upływa od wykrycia poprzedniego zbocza. Jeśli czas ten jest dłuższy niż 2,2ms, lub jeśli oczekiwane zbocze nastąpi po czasie krótszym niż 1,3ms, uznajemy że odebrana transmisja nie jest w formacie RC5 i przechodzimy do stanu 1. <br />Jeżeli natomiast zbocze opadające zostanie wykryte w dopuszczalnym przedziale czasowym, uznajemy że odebrano właśnie drugi bit startu. Na podstawie zmierzonego czasu trwania transmisji jednego bitu obliczone zostają referencyjne czasy 3/4 i 5/4 bitu (<em>refIR34</em> i <em>refIR54</em>), wyzerowany zostaje licznik <em>timIR</em> a następnie maszyna przechodzi do stanu 4.<br /><br /><strong>stan 4:</strong><br /><br />W tym stanie odbierane są kolejne bity ramki RC5. Po odczekaniu czasu <em>refIR34</em> (a więc dokładnie w 1/4 kolejnego bitu) stan wyjścia odbiornika jest wprost wartością nadawanego bitu. Stan ten zostaje wówczas wpisany do zmiennej <em>cmdIR</em>, zwiększony zostaje również licznik ilości odebranych bitów<em> bcIR</em>. <br />Następnie maszyna oczekuje na zbocze (dowolne) na wyjściu odbiornika. Oznacza ono środek aktualnie odbieranego bitu. Jeżeli takie zbocze nie wystąpi w czasie <em>refIR54</em>, uznajemy że odbierana transmisja nie jest w formacie RC5 i maszyna powraca do stanu 1.  <br />Jeżeli jednak zbocze zostanie  wykryte w odpowiednim czasie, następuje wyzerowanie licznika <em>timIR</em>. Oznacza to synchronizacje do kolejnego bitu. Od tej chwili maszyna, ciągle znajdująca się w stanie 4, odczekuje kolejny czas <em>refIR34</em> i odczytuje kolejny bit. Po poprawnym odczytaniu 12 bitów ustawiona zostaje flaga flagIR a maszyna przechodzi do stanu 0. Odebrana ramka znajduje się w zmiennej <em>cmdIR</em>.<br /><br /><br />Warto zauważyć, że przedstawiony kod nie obciąża zbytnio procesora. Przez przeważającą część czasu maszyna znajduje się w stanie 2 w którym sprawdzany jest tylko jeden warunek.<br /><br />Mam nadzieje, że komuś się to przyda.<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=1753">marekg</a> — 12 wrz 2013, o 22:57</p><hr />
]]></content>
</entry>
</feed>