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.
Adres systemowy | Rodzaj urządzenia |
0 |
Odbiornik telewizyjny numer 1 |
Kod komendy | Nazwa komendy |
0 .. 9 |
Klawisze numeryczne „0” do „9” |
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;
}
}
}
Dodaj nowy komentarz