Dekoder kodu RC5

Firma Philips jako pierwsza opracowała, lub zaadaptowała, standard RC5 dla swoich nadajników – odbiorników podczerwieni do zastosowań w sprzęcie domowego użytku. Stosowano w nim stały czas trwania i liczbę bitów. Za każdym razem, gdy użytkownik naciska przycisk w nadajniku zdalnego sterowania, pracującym zgodnie ze specyfikacją Philips, wysyła on ciąg 14 bitów o czasie trwania 1,728 ms każdy. Jeśli klawisz pozostaje naciśnięty, to cała transmisja powtarzana jest, co 130 ms. W artykule opisano sposób budowy odbiornika transmisji kodowanej zgodnie z RC5 za pomocą mikrokontrolera 8051.

Kodowanie transmisji

Wysyłane słowo kodowane jest zgodnie ze standardem kodowania Manchester. Oznacza to, że każdy bit transmitowany jest w postaci dwóch stanów logicznych, tzw. półbitów, a w środku czasu przeznaczonego na przesłanie pojedynczego bitu następuje zmiana, to jest opadające lub narastające zbocze sygnału. I tak zmianie z „0” na „1” odpowiada przesyłany bit o wartości „1”, natomiast zmianie z „1” na „0” odpowiada przysyłany bit o wartości „0”. Ponieważ czas na przesłanie pojedynczego bitu został przez twórcę standardu określony na 1,728ms, to zmiana następuje po połowie tego czasu, czyli 0,864ms. Dodatkowo zbocze występujące w środku bitu umożliwia synchronizację odbiornika z nadajnikiem. Często można się spotkać z określeniem, że sygnał przesyłany przy pomocy kodowania Manchester jest samosynchronizujący. Sposób kodowania bitów ilustruje rysunek 1.

Rysunek 1. Kodowanie bitów podczas transmisji w systemie Manchester.

Wyjście układu kodującego stan przycisków w nadajniku podłączone jest do wejścia modulatora nadajnika podczerwieni. Częstotliwość nośna używana przez nadajnik to 37 kHz. W związku z tym, że w nadajnikach firmy Philips stan wysoki reprezentowany jest przez załączenie nośnej a stan niski przez jej wyłączenie, uwzględniając okres nośnej modulatora oraz sposób kodowania Manchester (każdy bit podzielony jest na 2 części, z których jedna jest „0” a druga „1”) można wywnioskować, że:
- w czasie trwania pojedynczego bitu danych (a ściślej półbitu), do odbiornika dotrą 32 impulsy nośnej (0,864 ms / 27 μs = 32 impulsy),
-
każda przesyłane słowo ma długość 14 bitów i w związku z tym do odbiornika dotrze 14 x 32 = 448 impulsów nośnej nadajnika.
Na szczęście produkowane są układy sprzętowych demodulatorów i dzięki temu odbiornik nie musi zajmować się detekcją fali nośnej – może się skupić wyłącznie na rozpoznaniu odbieranego na wyjściu demodulatora ciągu bitów.
Pierwsze 2 bity nazywane są bitami kalibracji. Dzięki nim możliwe jest rozpoznanie początku transmisji i jej synchronizacja. Dodatkowo służą one do ustalenie poziomu wzmocnienia w układzie odbiorczym, ale to już leży niejako poza zainteresowaniami aplikacji dekodera. Bity te mają wartość logiczną „0”, co oznacza przesłanie ciągu 1 à0 à1 à0, gdzie czasy trwania półbitów są sobie równe, to jest 1 = 0 = 0,864ms. Kodowanie bitu zgodne ze specyfikacją firmy Philips ilustruje rysunek 2.

Rysunek 2. Kodowanie bitu w systemie Manchester zgodne ze specyfikacją firmy Philips dla nadajników – odbiorników kodu RC5 do sterowania urządzeń w podczerwieni.

Bit 3 nosi nazwę „CHECK BIT”. Na początku transmisji, tj. na przykład po wciśnięciu klawisza „3” w nadajniku podczerwieni, ma on wartość logiczną „1”. Jeśli klawisz nadajnika zdalnego sterowania pozostanie wciśnięty, to każde słowo docierające do odbiornika słowo danych będzie miało ten bit zanegowany. Jako, że jest to książka o programowaniu w języku C, więc dla ilustracji i zgodnie z notacją języka C można zapisać, że: while (klawisz = ‘3’) CHECK_BIT = ~CHECK_BIT. Bit informuje odbiornik, że klawisz nadajnika pozostaje naciśnięty i należy go interpretować jako pojedyncze wciśnięcie „3” a nie jako „33”, czy „333”.
Następne 5 bitów (od 4 do 8) zawierają adres systemowy urządzenia, do którego kierowana jest transmisja. Myślę, że staje się to oczywiste, jeśli uwzględnimy fakt, że w odbiorniki podczerwieni wyposażane są różne urządzenia: magnetowidy, wzmacniacze, telewizory i inne. Zestawienie adresów systemowych według materiałów firmy Philips zawiera tabela 1. Bity adresu przesyłane są od najbardziej do najmniej znaczącego.
Za bitami adresu następuje 6 bitów (o numerach od 9 do 14) służących do identyfikacji przesyłanej komendy przez urządzenie odbiorcze. Oczywiście powinno ją zrealizować wyłączenie urządzenie, do którego adresowana jest transmisja. Zestawienie komend, ponownie według specyfikacji firmy Philips, zawiera tabela 2. Podobnie jak bity adresu, bity komendy przesyłane są od najbardziej do najmniej znaczącego.
Po tym skróconym opisie standardu RC5, który jak mam nadzieję, pozwoli zrozumieć sposób funkcjonowania aplikacji, czas przejść do przykładu praktycznej realizacji dekodera RC5 z wykorzystaniem układu mikrokontrolera. Jakkolwiek możliwe jest użycie specjalizowanego układu dekodera (SAA3049, TDA3048 itp.), to jednak czasami zintegrowanie w jednym układzie funkcji odbiornika i sterowania jest ze wszech miar pożyteczne i wskazane.

Tabela 1. Zestawienie adresów systemowych urządzeń według standardu przyjętego przez firmę Philips.
Adres systemowy Rodzaj urządzenia

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24...25
26
27...31

Odbiornik telewizyjny numer 1
Odbiornik telewizyjny numer 2
Dekoder teletekstu
Układy rozszerzeń dla odbiorników telewizyjnych numer 1 i 2
Odtwarzacz laserowy płyt wizyjnych (teraz: DVD)
Urządzenie numer 1 do zapisu obrazu
Urządzenie numer 2 do zapisu obrazu
Zarezerwowany
Odbiornik satelitarny numer 1
Układy rozszerzeń dla urządzeń numer 1 i 2 do zapisu obrazu
Odbiornik satelitarny numer 2
Zarezerwowany
Odtwarzacz płyt wideo CD
Zarezerwowany
Odtwarzacz płyt „CD photo”
Zarezerwowany
Przedwzmacniacz audio numer 1
Odbiornik radiowy
Magnetofon (taśmowy lub kasetowy)
Przedwzmacniacz audio numer 2
Odtwarzacz płyt CD
Zestaw audio typu „wieża”
Odbiornik satelitarny audio
Magnetofon cyfrowy
Zarezerwowany
Urządzenie do zapisu płyt CD
Zarezerwowany

 

Tabela 2. Zestawienie komend przesyłanych według materiałów firmy Philips.
Kod komendy Nazwa komendy

0 .. 9
12
13
14
16
17
18
19
20
21
22
23
24
25
26
27
48
50
52
53
54
55
63
71
77
78
80
81
82
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
98
99
100
101
102
103
118
119
123
124

Klawisze numeryczne „0” do „9”
Standby (przejście do stanu czuwania)
Mute (wyciszenie)
Presets (nastawy)
Volume up (zwiększanie siły głosu)
Volume down (zmniejszanie siły głosu)
Brightness up (zwiększanie jaskrawości obrazu)
Brightness down (zmniejszanie jaskrawości obrazu)
Color saturation up (zwiększanie nasycenia barw)
Color saturation down (zmniejszanie nasycenia barw)
Bass up (regulacja barwy głosu – zwiększanie ilości tonów niskich)
Bass down (regulacja barwy głosu – zmniejszanie ilości tonów niskich)
Treble up (regulacja barwy głosu – zwiększanie ilości tonów wysokich)
Treble down (regulacja barwy głosu – zmniejszanie ilości tonów wysokich)
Balance right (balans audi w prawo)
Balance left (balans audio w lewo)
Pause (pauza)
Fast reverse (przewijanie w tył)
Fast forward (przewijanie w przód)
Play (odtwarzanie)
Stop (stop)
Record (zapis)
System select (wybór systemu kodowania)
Dim local display
Linear function up
Linear function down
Step up (jeden krok w górę)
Step down (jeden krok w dół)
Menu on (załączenie menu)
Menu off (wyłączenie menu)
Display A/V system status (wyświetlenie statusu zestawu A/V)
Step left (krok w lewo)
Step right (krok w prawo)
Acknowledge (potwierdzenie wyboru)
Picture-in-Picture on/off (załączenie funkcji PIP)
Picture-in-Picture shift
Picture-in-Picture main swap (zamiana obrazu głównego z wyświetlanym w oknie podglądu)
Strobe on/off
Multi strobe
Main frozen
3/9 Multi scan
Picture-in-Picture select
Mosaic multi Picture-in-Picture
Picture DNR
Main stored
Picture-in-Picture strobe
Recall main picture
Picture-in-Picture freeze
Picture-in-Picture step up
Picture-in-Picture step up
Sub mode
Options bus mode
Connect
Disconnect

 

Opis sprzętowej realizacji odbiornika

Na rysunku 3 przedstawiono rozwiązania sprzętowego aplikacji odbiornika. Wykorzystuje ona odbiornik LT1059ND oraz mikrokontroler AT89C2051 pracujący z rezonatorem kwarcowym 12MHz. W tym przykładzie mikrokontroler nie realizuje żadnej funkcji sterowania, wyprowadzając odebraną komendę przez port P1.

Rysunek 3.    Schemat elektryczny układu odbiornika podczerwieni z dekoderem zbudowanym w oparciu AT89C2051.

Opis programu dekodera

Na listingu 1 przedstawiono program do odbioru i dekodowania kodu RC5. Przystosowany jest do wymogów standardu zdefiniowanego przez firmę Philips, jednak łatwo może być dostosowany do dowolnego nadajnika o ile nie będzie z nim współpracować od razu.
Program wykorzystuje dwa przerwania: jedno zewnętrzne od opadającego zbocza sygnału na INT0 do sygnalizacji faktu pojawienia się transmisji, drugie wewnętrzne od przepełnienia Timer’a 0 do odmierzania czasu do próbkowania stanu wejścia danych z odbiornika podczerwieni. Odebrany kod urządzenia oraz komenda wyprowadzane są przez port P1 synchronicznie z opadającym zboczem sygnału pojawiającym się na P3.7. Jako pierwszy wyprowadzany jest adres, jako drugi komenda. Oczywiście zamiast wyprowadzania danych, układ może realizować jakąś funkcję sterującą. Szczerze mówiąc marnotrawstwem wydaje mi się użycie mikrokontrolera tylko do wyprowadzania adresu i komendy.
Początek programu zawiera definicje dwóch wartości: RELOAD i FIRST_RELOAD. Zdefiniowane są liczby ujemne, co oznacza, że wartość zapisywana do rejestrów (bo do tego wykorzystywane są te liczby) będzie wyliczana jako: 65536 - <deklaracja>, czyli dla liczby –440 będzie to 65536 – 440 = 65096. Wartości z definicji należy dobrać do użytego rezonatora kwarcowego i nadajnika podczerwieni. Należy dobrać je tak, aby:
-
wartość bezwzględna z RELOAD pomnożona przez cykl maszynowy dawała czas o długości 3/4 czasu trwania bitu, to jest dla standardu zdefiniowanego przez firmę Philips 1,296 ms,
-
wartość bezwzględna z FIRST_RELOAD pomnożona przez cykl maszynowy dawała czas o długości 1/2  czasu trwania bitu, to jest przy założeniach jak wyżej 0,864 ms.
Opadające zbocze sygnału powoduje uruchomienie Timer’a 0 oraz zablokowanie przerwań INT0. Od tego momentu sygnał na wejściu przerwania nie uruchamia go, ale jest próbkowany w przerwaniu od Timer’a 0. Próbki zapamiętywane są w zmiennej shiftreg, skąd później pobiera je funkcja rozpoznająca komendę i adres urządzenia odbiorczego. Każdy bit reprezentowany jest przez parę bitów – zgodnie z zasadą kodowania Manchester – o przeciwstawnych stanach logicznych. W związku z tym, że pierwszy bit jest „tracony”, program musi odebrać 14 takich par – 1. Daje to łącznie 26 par bitów do odebrania. Jednak w programie zaimplementowano również możliwość odbioru komend tzw. rozszerzonych o długości 7 bitów. Po uwzględnieniu tej funkcji daje to łącznie 27 par bitów do odebrania.
W związku z tym, że parze następujących po sobie bitów 1 – 0 odpowiada logiczna „1”, a parze 0 – 1 logiczne „0”, prosta operacja iloczynu bitowego umożliwia wykrycie, z jakim odebranym bitem mamy do czynienia oraz czy nie wystąpił błąd transmisji.

b = shiftreg.b.b0 & 0x03;                 //maskowanie bitów nieznaczących
if(b == 0x02) command |= 0x40;            //czy sekwencja 0 -> 1? jeśli tak, to logiczna 1
    else if(b == 0x01) command &= ~0x40;  //czy sekwencja 1 -> 0? jeśli tak, to logiczne 0
        else return(0);                   //błąd, gdy żadna z powyższych

Zmienna b jest typu unsigned char. W programie nadano temu typowi nazwę BYTE. Zapamiętywana jest w niej wartość dwóch sąsiednich bitów pobrana z bufora odbioru shiftreg przemnożona przez stałą, którą można nazwać maską - 0x03. W związku z tym, zmienna b przyjmuje wartość zależną wyłącznie od stanu bitów na pozycjach 0 i 1. Tak, więc sąsiadujące ze sobą bity o wartościach 0 – 1 reprezentują odebraną zmianę sygnału 0 à1, co odpowiada odebranemu „0”, a sąsiadujące 1 – 0 odpowiadają zmianie 1 à0 i odebranej „1”. Inne stany są zabronione i powoduję, że funkcja kończy pracę z komunikatem o błędzie.

Jacek Bogusz
j.bogusz@easy-soft.net.pl

 

Listing 1.Program odbiornika kodu RC5.

/**********************************************************
Dekoder kodu RC5 odbieranego z toru podczerwieni
na podstawie materiałów zamieszczonych na stronie:
http://www.ustr.net/infrared/infrared1.shtml
----------
UWAGI n/t wykonania:
Wejście odbiornika podczerwieni podłączone jest do wejścia
przerwania INT0 (P3.2). Dekoder używa Timer'a 0 do pomiaru
czasu trwania bitów. Aplikacja wykonana była w oparciu o
mikrokontroler AT89C2051 z rezonatorem kwarcowym 12MHz.
***********************************************************/

#include  <reg51.h>
#define IE0_VECTOR 1           //numer wektora przerwania INT0
#define TF0_VECTOR 2           //numer wektora przerwania Timer'a 0
#define BYTE unsigned char 
#define WORD unsigned int
#define ENABLE 1
#define DISABLE 0
#define HighB(value) ((value >> 8) & 0xFF)
#define LowB(value)  (value & 0xFF)

//cykl maszynowy dla kwarcu 12MHz wynosi 1us, czas RELOAD ustawiony jest na
//3/4 długości bitu, czas FIRST_RELOAD ustawiony jest na 1 długość bitu
#define RELOAD        -1296    //czasy RELOAD i FIRST_RELOAD dobrane dla specyfikacji
#define FIRST_RELOAD  -864     //czasów PHILIPS i rezonatora kwarcowego 12 MHZ
#define _TOGGLE      0x80      //wartość do ustawienia / wyzerowania bitu numer 7
#define _START2      0x40      //  - / / - bitu numer 6
#define _START1      0x20      //  - / / - bitu numer 5

typedef struct _BYTE
{
    BYTE b3;                   //bardziej znaczący bajt
    BYTE b2;
    BYTE b1;
    BYTE b0;                   //mniej znaczący bajt
}BYTES;

typedef union _LONGINT
{
    unsigned long l;           //unia umożliwiająca szybką konwersję
    BYTES  b;                  //zmiennej typu longint na pojedyncze
}LONGUNION;                    //bajty i odwrotnie (bajty na longint)

//zmienne globalne
bit  bRC5valid;                //bit znacznika ustawiany po odebraniu 1-go kodu RC5
BYTE  command;                 //odebrana komenda
BYTE  subaddress;              //odebrany adres urządzenia
BYTE slopecount;               //pomocniczy licznik zboczy sygnału
LONGUNION shiftreg;            //rejestr przesuwny dla odebranego słowa RC5

//Obsługa przerwania od odbiornika RC5. Rozpoczyna ona
//pomiary odbieranego sygnału przez Timer 0
void RC5_StartIrq(void) interrupt IE0_VECTOR
{
    EX0 = DISABLE;             //wyłączenie przerwań od INT0
    slopecount = 27;           //odbierane jest 27 próbek
    TH0 = HighB(RELOAD);       //nastawa Timer'a 0
    TL0 = LowB(RELOAD);
    TR0 = ENABLE;              //uruchomienie Timer'a 0 w celu pomiaru
    TF0 = 0;                   //czasu trwania bitu
    ET0 = ENABLE;              //uruchomienie obsługi przerwania Timer'a 0
}

//Obsługa przerwania Timer'a 0. Po odebraniu 27 próbek rejestr
//przesuwny zawiera wartość RC5 a stan bitu bRC5Valid zmieniany
//jest na "1"
void TimingIrq(void) interrupt TF0_VECTOR using 1
{
    bit bLevel;
    bLevel = P3^2;             //testowanie stanu wejścia P3.2
    while (slopecount--)       //do odebrania 27 próbek
    {
        TR0 = DISABLE;         //zatrzymanie Timer'a 0
        TH0 = HighB(FIRST_RELOAD);     //załadowanie nowej wartości dla reload
        TL0 = LowB (FIRST_RELOAD);
        TR0 = ENABLE;          //uruchomienie Timer'a 0
        if (bLevel)            //dodanie odczytanego poziomu do wartości
        {                      //rejestru przesuwnego
            shiftreg.b.b0 = shiftreg.b.b0 | 1;
        }
        shiftreg.l = shiftreg.l << 1;
        return;
     }
     TR0 = DISABLE;            //zatrzymanie Timer'a 0
     ET0 = DISABLE;            //wyłączenie przerwań od Timer'a 0
     bRC5valid = 1;            //ustawienie bitu sygnalizacji, że
                               //bufor zawiera odebraną transmisję RC5
}

//Dekodowanie odebranej wartości (wydzielenie adresu i
//komendy). Funkcja zwraca "1" jeśli dekodowanie przebiegło
//bezbłędnie, inaczej zwracane jest "0"
bit DecodeRC5Code(void)
{
    BYTE i, b;
    command = subaddress = 0;  //zerowanie adresu urządzenia i kodu komendy
    shiftreg.l = shiftreg.l >> 1;
    for (i=0; i < 6; i++)      //najpierw dekodowanie 6 bitów komendy
    {
        b = shiftreg.b.b0 & 0x03;
        if(b == 0x02) command |= 0x40;
            else if(b == 0x01) command &= ~0x40;
                else return(0);
        command = command >> 1;
        shiftreg.l = shiftreg.l >> 2;
    }
    for (i=0; i < 5; i++)          //następnie dekodowanie 5 bitów adresu
    {
        b = shiftreg.b.b0 & 0x03;
        if(b == 0x02)subaddress = subaddress | 0x20;
            else if(b == 0x01) subaddress &= ~0x20;
                else return(0);
        subaddress = subaddress >> 1;
        shiftreg.l = shiftreg.l >> 2;
    }
    b = shiftreg.b.b0 & 0x03;
    if(b == 0x02)command |= _TOGGLE;
        else if(b == 0x01)command &= ~_TOGGLE;
            else return(0);
    shiftreg.l = shiftreg.l >> 2;
    b = shiftreg.b.b0 & 0x03;         //bit synchronizacji numer 2 inwersja
    if(b==0x02) command &= ~_START2;  //dla 7-bitowych komend (extended RC5)
        else if(b == 0x01) command |= _START2;
            else return(0);
    shiftreg.l = shiftreg.l >> 2;
    b=shiftreg.b.b0 & 0x03;           //bit synchronizacji numer 1
    if(b == 0x02) subaddress |= _START1;
        else if(b==0x01) subaddress = subaddress & ~_START1;
            else return(0); 
    return(1);                        //sygnalizacja, że odbiór poprawny
}

/*******************************************************
Program główny jako przykład aplikacji wysyłającej
odebraną komendę i adres przez port P0
*******************************************************/
sbit clockline = P3^7;                //linia zegara zapisu do układów zewnętrznych

//impuls zapisujacy dane w układzie zewnętrznym
//(opadające zbocze sygnału)
void Clock()
{
    clockline = 0;                    //opadające zbocze zegara zapisu do układów zewnętrznych
    clockline = 0;                    //wydłużenie czasu trwania stanu niskiego
    clockline = 1;
}

void main(void)
{
    clockline = 1;                    //stan spoczynkowy sygnału zegarowego
    TMOD = 0x11;                      //nastawa trybu pracy Timer'ów 0 i 1
                                      //oba pracują w trybie Timer 16-bitwy
    EX0 = ENABLE;                     //załączenie przerwań INT0 wyzywalanych
    IE0 = 0;                          //opadającym zboczem sygnału
    IT0 = ENABLE;
    shiftreg.l = 0x02;                //inicjowanie wartości bufora odbioru
    EA = ENABLE;                      //załączenie przerwań
    while (1)
    {
        if (bRC5valid)                //jeśli odebrano poprawną transmisję RC5
        {
            bRC5valid=0;
              if (DecodeRC5Code())    //testowanie bufora odbioru, dekodowanie
              {                       //adresu i komendy
                  P1 = subaddress;    //wyprowadzenie adresu
                  Clock();
                  P1 = command;       //wyprowadzenie komendy
                  Clock();
              }
              shiftreg.l=0x02;//restart dekodera
              IE0 = 0;
              EX0 = ENABLE;       
          }
     }
}

http://www.tomaszbogusz.blox.pl/

Dodaj nowy komentarz

Zawartość pola nie będzie udostępniana publicznie.