Dekodowanie protokołu RC-5 na AVR ATmega

Protokół RC-5, jest jednym z wielu protokołów służących do przesyłania komend pomiędzy pilotem, a urządzeniem RTV. Został zaprojektowany przez Philipsa, ale korzystają z niego również inni producenci.

W artykule opiszę jak w prosty sposób, przy pomocy mikrokontrolera ATmega, dekodować informacje przesyłane przez pilot zgodny ze standardem RC-5. Przy niewielkim nakładzie pracy, będziemy w stanie zbudować zdalnie sterowane urządzenie, w tym przypadku będziemy sterować zapalaniem i gaszeniem dwóch diod LED.

Kompletowanie komponentów

Aby móc zabrać się do roboty, potrzebujemy:

  1. Pilot zgodny ze standardem RC-5. Wbrew pozorom może być ciężko, większość producentów stosuje własne protokoły. U mnie w mieszkaniu, na 5 pilotów, tylko jeden z nich był zgodny – pilot Philipsa ;). Należy celować raczej albo w urządzenia Philipsa, albo w piloty starszej daty.
  2. Układ TSOP4836, posłuży nam do odbierania sygnałów.
  3. Mikrokontroler ;).
  4. Inne:
    1. Kondensator >= 47µF – zalecany, u mnie bez tego strasznie świrował.
    2. Rezystor >=10 kΩ – niekoniecznie.
    3. Rezystor 100 Ω – niekoniecznie.

TSOP4836 to układ reagujący na oświetlanie go światłem podczerwonym o częstotliwości 36 kHz, dzięki czemu jest odporny na zakłócenia ze strony innych źródeł światła. Jest bardzo czuły, zasięg w dużej mierze zależy od mocy diody nadawczej, zwykły pilot jest „łapany” z odległości kilku metrów, a pewnie i nawet więcej. Dokładny opis jak i sposób podłączenia układu TSOP4836 można znaleźć w nocie katalogowej.

Protokół RC-5

Protokół bardzo dobrze opisuje artykuł na tej stronie: http://www.sbprojects.com/knowledge/ir/rc5.php, dlatego będę się nim posiłkował. Na blogu dostępny jest również post, w którym przy pomocy analizatora stanów logicznych, pokazuję jak dokładnie wygląda przesył danych przy pomocy protokołu RC-5. Warto zaglądnąć.

Każda ramka danych składa się z 14 bitów:

  • b[1:2] – Dwa bity startowe, zawsze 1
  • b[3] – Bit „toggle”. Jego wartość zmienia się za każdym naciśnięciem przycisku, tzn. jeżeli przytrzymamy przycisk, wszystkie ramki wysłane w trakcie tego przytrzymania, będą miały taki sam bit toggle, dzięki temu urządzenie wie, czy naciśnięcie klawisza zostało powtórzone przez nasz palec (kolejna ramka ma inny bit toggle), czy wynikło to np. z zasłonięcia kontrolera (bit jest taki sam jak poprzednio).
  • b[4:8] – Adres urządzenia. Mówi o tym, do jakiego typu urządzenia kierowana jest komenda – TV, wzmacniacz, odtwarzacz itd. Na stronie podanej wcześniej, znajduje się tabelka z informacją o adresach urządzeń.
  • b[9:14] – Komenda. Czyli co chcemy zrobić.

Protokół RC-5 do wysyłania danych wykorzystuje kodowanie Manchester (nie United). Polega to na tym, że 0 kodowane jest jako przejście ze stanu wysokiego na stan niski, a 1 – przejście ze stanu niskiego na wysoki. Ta zmiana odbywa się w jednym takcie i odbywa się w jego połowie.

Czyli, jeżeli w protokole RC-5, jeden bit „trwa” 1,778ms i chcielibyśmy wysłać „1”, musimy przez 889µs nadawać „0”, po czym przez kolejne 889µs transmitować „1”. Żeby wysłać „0” należy zrobić na odwrót. Dekodowanie tego nie jest takie trudne, gdy poprawnie posłużymy się timerami ATmegi.

Układ TSOP4836 ma to do siebie, że jeżeli jest nieoświetlony, czyli pilot nadaje „0”, on puszcza na wyjście „1”, i na odwrót. Musimy to uwzględnić w funkcji dekodującej.

Opis wykonania

Do odbioru sygnałów z TSOP4836, wykorzystamy port z przerwaniem INT0. Ustawimy go tak, żeby reagował na pojawienie się stanu niskiego. W procedurze przerwania umieścimy cały kod odpowiedzialny za dekodowanie ramki danych.

Do prawidłowej synchronizacji z protokołem, użyjemy 16-bitowego timera, ustawionego na tryb CTC, z częstotliwością 562,4296963 Hz. Z czego wynika ta brzydka liczba? Gdy ustawimy zegar na taką częstotliwość, jeden okres sygnału wynosi dokładnie 1,778ms. Dodatkowo, zegar jest w trybie CTC, czyli żeby wytworzyć jeden okres, licznik musi przepełnić się 2 razy, a jedno przepełnienie będzie trwało wtedy 889µs. Ponieważ moim zdaniem jeden rysunek wyraża więcej niż tysiąc słów, oto rysunek:

grafika

Niebieska linia odwzorowuje wartość licznika timera, natomiast czerwona przedstawia wygenerowany przez timer przebieg prostokątny dla częstotliwości 562,4296963 Hz. Każde przepełnienie licznika powoduje zmianę sygnału na przeciwny, stąd są potrzebne 2, aby wytworzyć pełny okres.

Programujemy

Nasz program będzie działał na prostej zasadzie – kontrolowanie 2 diod LED za pomocą pilota. Do tego celu wykorzystamy 2 przyciski, dla każdej diody oddzielny, przytrzymanie przycisku przez około sekundę zapali diodę przypisaną do tego przycisku.

Jeżeli nie wiemy jakie kody wysyła pilot, można posłużyć się albo tabelami zawartymi na stronie Wikipedii, albo wyświetlić je na wyświetlaczu 7-segmentowym, ekranie LCD, czy – tak jak ja – wysłać przez USART do komputera. Zwykle jednak przyciski takie jak kontrola głośności, stand-by, czy te do zmiany utworu, są takie, jak podaje tabela.

Przyciski jakich użyję:

  • „Poprzedni utwór” (kod: 33), kontrola lewej diody
  • „Następny utwór” (kod: 32), kontrola prawej diody

Inicjalizacja – czyli wszystko musi mieć swój początek

Na początku programu ustawimy sobie wszystkie potrzebne nam przerwania i kierunki portów.

Należy oczywiście wziąć pod uwagę, że ustawienia zegara są dobrane pod taktowanie 8 MHz, jeżeli macie inaczej, trzeba obliczyć właściwą wartość do umieszczenia w rejestrze OCR1A. Można ją wyliczyć z tego wzoru:

\(OCR1A=\frac{F}{562,4296963\cdot2N}-1\)

Gdzie:

  • F – Taktowanie procesora
  • N – Możliwe wartości prescalera – 1, 8, 64, 256, 1024

Może się zdarzyć, że nie uzyskamy wartości całkowitej, nic nie szkodzi, należy wybrać tą, która jest do niej jak najbardziej zbliżona.

Obsługa przerwania

To, co będzie wykonywane w funkcji obsługującej przerwanie, jest tak naprawdę sercem naszego programu, a to serce musi bić wyjątkowo szybko, dlatego wszystko co tu umieścimy, nie może zawierać redundantnych operacji.

Pomimo, że w protokole RC-5 czasy są mikrosekundowe, co dla nas wydaje się wartością niewyobrażalnie małą, to jednak z perspektywy procesora, który wykonuje jedną operację w ciągu 125 nanosekund (8 MHz), jest to dość spora ilość czasu, dlatego aż tak optymalizować nie musimy. Jednakże, dobrze jest wyrobić sobie nawyk niezaśmiecania funkcji obsługi przerwań.

Chyba jestem wam winien wyjaśnienie co tu się dzieje ;). Funkcja reset_timer służy do zerowania licznika timera i flagi informującej o przepełnieniu. Jednolinijkowe pętle while („czekacze” ;)) sprawdzają, czy w rejestrze TIFR została ustawiona flaga OCF1A – przepełnienia licznika, co oznaczałoby upłynięcie czasu 889µs, jeżeli tak, to program wykonuje się dalej.

W pętli na początku przeczekujemy pierwszą połówkę bitu, nie jest ona dla nas istotna, wartość bitu można odczytać na podstawie drugiej połówki, co czynimy sprawdzając stan na wejściu. Sprawdzamy wartość zanegowaną, ponieważ TSOP4836 wysyła odwrotnie niż odbiera.

Po tym wszystkim czekamy do końca drugiej połówki bitu i powtarzamy proces.

Funkcję kończymy przesuwając zmienną frame jeszcze 2 bity w lewo, dzięki czemu nie będziemy mieć dwóch zer na początku. Tak przygotowana ramka wędruje do funkcji odpowiedzialnej za jej odpowiednie wykorzystanie.

Świecimy

Założenie było takie, że przytrzymanie przycisku powoduje zapalenie lub zgaszenie się diody. Wykorzystamy do tego celu bit toggle. Każde wywołanie funkcji będzie zwiększało licznik tylko wtedy, gdy bit toggle jest taki tam, jak poprzednio, czyli gdy przycisk jest trzymany; zmiana bitu spowoduje wyzerowanie licznika. Po osiągnięciu przez licznik wartości 10 (co zajmie około sekundy), zapalana (lub gaszona) będzie dioda adekwatna do trzymanego przycisku.

Tu chyba nie ma co wyjaśniać, może tylko początek: wyłuskiwanie poszczególnych części ramki.

Prezentacja

A teraz dowód na to, że nie ściemniałem ;).

Kod

 

[guest@itachi.pl:~]$

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *