Artykuł pochodzi ze strony XYZ HOBBY ROBOT (
xyz.isgreat.org
)
Kurs AVR-GCC Dekoder protokołu RC5
3.06.11 ABXYZ
Artykuł jest dodatkiem poszerzającym tematykę publikowanego na
tej stronie kursu AVR-GCC
Pilot na podczerwień to tani i prosty sposób na bezprzewodowe
sterowanie urządzeniami z bliskiej odległości. W tym artykule
opisałem jak wykonać odbiornik współpracujący ze standardowym
pilotem RC5. Funkcję dekodera protokołu RC5 będzie oczywiście
pełnił mikrokontroler- napiszemy taki programik w języku C.
Odbiornik można wykorzystać do budowy różnych urządzeń
sterowanych pilotem.
Scalony odbiornik podczerwieni SFH5110-36
Obok pilota RC5 i mikrokontrolera AVR ATMEGA będzie potrzebny
scalony odbiornik podczerwieni SFH5110-36, układ ten jest łatwo
dostępny i kosztuje ok 3zł.
Fot. 1. SFH5110-36 Scalony odbiornik/demodulator podczerwieni
Rys.1. Podłączenie układu SFH5110-36
Rysunek poniżej wyjaśnia sposób działania układu SFH5110-36.
Odbiornik SFH5110-36 posiada trzy wyprowadzenia: 1-wyjście
cyfrowe, 2-masa, 3-zasilanie(5V) . Normalnie na wyjściu odbiornika
SFH5110-36 jest wysoki stan napięcia, gdy odbiornik zostanie
oświetlony pilotem, na wyjściu pojawi się stan niski. Pilot świeci
diodami IR impulsowo, z częstotliwością ok 36kHz, gdyż odbiornik
SFH5110-36 reaguje tylko na oświetlenie impulsowe o
częstotliwości 36kHz, eliminuje to wpływ zakłóceń z innych źródeł
światła.
1 z 7
Rys. 2. Zasada działania i sposób użycia odbiornika podczerwieni SFH5110-36.
Scalony odbiornik podczerwieni podobny do SFH5110-36 można
wyciągnąć ze zużytego TV lub innego sprzętu. Przed wylutowaniem
trzeba tylko rozeznać do których wyprowadzeń przyłączone jest
zasilanie, a które jest wyjściem danych.
Pilot RC5
Chociaż w każdym porządnym domu znajdzie się kilka pilotów na
podczerwień, to jest całkiem prawdopodobne, że żaden nie działa
zgodnie z protokołem Philips RC5. Ale to żaden problem.
Nowiutkiego pilota RC5 kupisz na allegro w cenie ok 5..7zł. Ja
posłużę tu się pilotem od starego telewizora, fotka poniżej, pilot ten
ma w środku układ scalony SAA3010P.
Fot. 2. Klasyczny pilot, pozostał mi po wymianie starego TV, w środku ma układ scalony
SAA3010P
Protokół zdalnego sterowania RC5
Wciśnięcie przycisku w pilocie RC5 skutkuje wysłaniem ramki
danych, która składa się z czternastu bitów danych. Najpierw idą
dwa bity startowe, oba zawsze mają wartości 1. Następny jest bit
kontrolny toggle, bit ten zmienia swoją wartość na przeciwną, za
każdym razem, kiedy naciśnięty jest któryś przycisk w pilocie.
Kolejne pięć bitów sys5..sys0 to adres systemu (urządzenia), dla TV
adres ma wartość 0. Pozostałe sześć bitów cmd4..cmd0, zawierają
numer przycisku.
2 z 7
Rys.3. Ramka danych protokołu sterowania RC5 składa się z 14 bitów.
W protokole RC5 wykorzystuje się kodowanie bitów Manchaster. Bit
o wartości 1 kodowany jest jako przejście poziomu sygnału z
niskiego na wysoki, a bit o wartości 0, jako przejście z poziomu
wysokiego na niski. W obu przypadkach zmiana poziomu sygnału
następuje w połowie czasu trwania bitu. Czas trwania każdego bitu
wynosi ok 1.8 milisekundy.
Rys.4. Kodowanie bitów Manchester
Pilot RC5 przesyła kolejne ramki danych w odstępie czasu nie
mniejszym niż okres trwania 50 bitów.
Rys.5. Odstęp pomiędzy kolejnymi ramkami danych równa się czasowi trwania 50 bitów.
Przykładowy program dekodera RC5
Program będzie dekodował komendy pilota RC5 i prezentował wynik
na siedmiu diodach LED. Sześć diod pokaże numer przycisku, a
siódma - toggle bit. Toggle bit zmienia swój stan przy każdym
wciśnięciu przycisku. Siedem diod LED przyłączyłem do portu D
AVRa, a odbiornik podczerwieni SFH5110-36 do PB0.
W programie wykorzystano przerwanie wywoływane przepełnieniem
timera0 - "Timer0 Overflow". Timer0 skonfigurowany jest tak, że
przerwania występują co 32 mikrosekundy. Z każdym wystąpieniem
przerwania inkrementowana jest globalna zmienna "timerL", a co
256 wystąpień przerwania, inkrementowana jest globalna zmienna
"timerH". Zmienne "timerL" i "timerH" tworzą zegary, które
użyjemy w programie do mierzenia czasu trwania impulsów i do
wymierzania odcinków czasu.
Wykrywaniem i dekodowaniem komend rc5 zajmuje się funkcja
"detect". Funkcja "detect" uruchamiana jest w głównej pętli
programu, zwraca 12-bitowy kod komendy RC5, albo wartość -1,
jeśli w okresie 131ms nie wykryje komendy lub wystąpi błąd.
3 z 7
Na początku funkcji "detect" program odczytuje w pętli stań wejścia
uC, do którego podłączono odbiornik podczerwieni SFH5110-36,
oczekując okresu ciszy trwającego co najmniej 3.5ms - cisza to stan
wysoki napięcia na wyjściu SFH5110-36. Przypominam, że
normalnie na wyjściu odbiornika SFH5110-36 jest wysoki stan
napięcia, a gdy odbiornik oświetlany jest pilotem, to na wyjściu
pojawia się stan niski. Jeśli w ciągu 131ms nie wystąpił okres ciszy
trwający 3.5ms, to funkcja kończy działanie zwracając kod -1,
oznaczający brak komendy. Następnie program oczekuje
opadającego zbocza sygnału w połowie pierwszego bitu startowego
Po wykryciu bitu startowego mierzony jest czas trwania niskiego
poziomu sygnału. Jeśli nie wykryto pierwszego bitu startowego w
okresie 131ms, albo mierzony czas trwania poziomu niskie sygnału
w pierwszym bicie startowym okazał się dłuższy niż 1.1ms, to
funkcja kończy działanie zwracając kod oznaczający brak komendy.
Dalej program oczekuje opadającego zbocza w środku drugiego bitu
startowego. Funkcja wykorzystuje opadające lub rosnące zbocze
sygnału w połowie każdego bitu do synchronizacji. Odczyt wartości
kolejnego bitu ramki dokonuje się po okresie 3/4 czasu trwania bitu
od momentu wykrycia zbocza w środku poprzedniego bitu.
Odczytana wartość bitu zachowywana jest w zmiennej. Dalej, jeśli
odczytano wartość bitu 1, to program oczekuje wystąpienia zbocza
opadającego w środku bitu, a jeśli odczytano wartość bitu 0, zbocza
narastającego. W momencie wykrycia krawędzi w środku bitu
następuje wyzerowanie timera i cała akcja jest powtarzana dla
kolejnego bitu. Jeśli program nie wykryje odpowiedniego zbocza w
okresie 5/4 czasu trwania bitu od momentu poprzedniej
synchronizacji, to funkcja kończy działanie z błędem.
Rys. 6. Próbkujemy po 3/4 czasu trwania bitu od momentu wykrycia zbocza sygnału w
połowie poprzedniego bitu.
A oto nasz programik, całość w jednym pliku.
//---------------------------------------------------------------
// Plik "main.c"
//
// KURS AVR-GCC (abxyz.bplaced.net)
//
// Dekoder RC5
//
// (schemat i opis działania w artykule)
// testowanie na atmega8 (8MHz)
//---------------------------------------------------------------
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
4 z 7
// Odbiornik podczerwieni SFH5110 przyłączona do portu PB0
#define RC5_IN (PINB & (1<<0))
//
typedef
unsigned
char
u8;
;
;
;
typedef
unsigned
int
uint;
;
;
;
// Zmienne globalne pełnią rolę programowych zegarów
// napędzanych przerwaniem TIMER0_OVF
volatile
u8 timerL;
;
;
;
volatile
u8 timerH;
;
;
;
//---------------------------------------------------------------
// Funkcja konfiguruje i uruchamia Timer0
// oraz włącza przerwanie od przepełnienia timera,
// przerwanie powinno występować co 32us.
//---------------------------------------------------------------
void
init_rc5()
()
()
()
{
{
{
{
//atmega8
TCCR0 =
=
=
= (
(
(
(
1
<<
<<
<<
<<CS00);
);
);
);
// włącza Timer0
TIMSK =
=
=
= (
(
(
(
1
<<
<<
<<
<<TOIE0);
);
);
);
// włącza przerwanie "Timer0 Overflow"
/*
//atmega88
TCCR0B = (1<<CS00);
TIMSK0 = (1<<TOIE0);
*/
// Zezwala na przerwania
sei();
();
();
();
}
}
}
}
//---------------------------------------------------------------
// Procedura obsługi przerwania Timer0 Overflow"
//---------------------------------------------------------------
ISR(
(
(
(TIMER0_OVF_vect)
)
)
)
{
{
{
{
volatile
static
u8 inttemp;
;
;
;
// zmienna timerL zwiększa się co 32us
timerL++;
++;
++;
++;
// zmienna timerH zwiększa się co 8.192ms (32us*256)
inttemp++;
++;
++;
++;
if
(!
(!
(!
(!inttemp )
)
)
) timerH++;
++;
++;
++;
}
}
}
}
//---------------------------------------------------------------
// Funkcja wykrywa i dekoduje komendę pilota RC5
//---------------------------------------------------------------
uint detect()
()
()
()
{
{
{
{
u8 temp;
;
;
;
u8 ref1;
;
;
;
u8 ref2;
;
;
;
u8 bitcnt;
;
;
;
uint command;
;
;
;
timerH =
=
=
=
0
;
;
;
;
timerL =
=
=
=
0
;
;
;
;
// Czeka na okres ciszy na linii wejścia uC trwający 3.5ms
// Jeśli nie wykryje takiego okresu ciszy w ciągu 131ms,
// to kończy działanie funkcji z błędem
while
(
(
(
( timerL<
<
<
<
110
)
)
)
)
{
{
{
{
if
(
(
(
(timerH>=
>=
>=
>=
16
)
)
)
)
return
command =
=
=
= -
-
-
-
1
;
;
;
;
if
(!
(!
(!
(!RC5_IN)
)
)
) timerL =
=
=
=
0
;
;
;
;
}
}
}
}
// Czeka na pierwszy bit startowy.
// Jeśli nie wykryje bitu startowego w ciągu 131ms,
// to kończy działanie funkcji z błędem
while
(
(
(
(RC5_IN)
)
)
)
if
(
(
(
(timerH>=
>=
>=
>=
16
)
)
)
)
return
command =
=
=
= -
-
-
-
1
;
;
;
;
// Pomiar czasu trwani niskiego poziom syganłu
// w pierwszym bicie startowym.
// Jeśli nie wykryje rosnącego zbocza sygnału w ciągu
5 z 7
// 1ms, to kończy działanie funkcji z błędem
timerL =
=
=
=
0
;
;
;
;
while
(!
(!
(!
(!RC5_IN)
)
)
)
if
(
(
(
(timerL>
>
>
>
34
)
)
)
)
return
command =
=
=
= -
-
-
-
1
;
;
;
;
//
temp =
=
=
= timerL;
;
;
;
timerL =
=
=
=
0
;
;
;
;
// ref1 - oblicza 3/4 czasu trwania bitu
ref1 =
=
=
=temp+(
+(
+(
+(temp>>
>>
>>
>>
1
);
);
);
);
// ref2 - oblicza 5/4 czasu trwania bitu
ref2 =(
=(
=(
=(temp<<
<<
<<
<<
1
)+(
)+(
)+(
)+(temp>>
>>
>>
>>
1
);
);
);
);
// Oczekuje na zbocze opadające sygnału w środku drugiego
// bitu startowego.
// Jeśli nie wykryje zbocza w ciągu 3/4 czasu trwania
// bitu, to kończy działanie funkcji z błędem
while
(
(
(
(RC5_IN)
)
)
)
if
(
(
(
(timerL >
>
>
> ref1)
)
)
)
return
command =
=
=
= -
-
-
-
1
;
;
;
;
// W momencie wykrycia zbocza sygnału, synchronizuje
// zmieną timerL dla próbkowania bitu toggle
timerL =
=
=
=
0
;
;
;
;
// Odczytuje dekoduje pozostałe 12 bitów polecenia rc5
for
(
(
(
(bitcnt=
=
=
=
0
,
,
,
, command =
=
=
=
0
;
;
;
; bitcnt <
<
<
<
12
;
;
;
; bitcnt++)
++)
++)
++)
{
{
{
{
// Czeka 3/4 czasu trwania bitu od momentu wykrycia
// zbocza sygnału w połowie poprzedniego bitu
while
(
(
(
(timerL <
<
<
< ref1)
)
)
) {};
{};
{};
{};
// Próbkuje - odczytuje port we uC
if
(!
(!
(!
(!RC5_IN)
)
)
)
{
{
{
{
// Jeśli odczytano 0, zapamiętuje w zmiennej
// "command" bit o wartości 0
command <<=
<<=
<<=
<<=
1
;
;
;
;
// Oczekuje na zbocze rosnące sygnału w środku bitu.
// Jeśli nie wykryje zbocza w ciągu 5/4 czasu trwania
// bitu, to kończy działanie funkcji z błędem
while
(!
(!
(!
(!RC5_IN)
)
)
)
if
(
(
(
(timerL >
>
>
> ref2)
)
)
)
return
command =
=
=
= -
-
-
-
1
;
;
;
;
}
}
}
}
else
{
{
{
{
// Jeśli odczytano 1, zapamiętuje w zmiennej
// "command" bit o wartości 1
command =
=
=
= (
(
(
(command <<
<<
<<
<<
1
)
)
)
) |
|
|
|
0x01
;
;
;
;
// Oczekuje na zbocze opadające sygnału w środku bitu.
// Jeśli nie wykryje zbocza w ciągu 5/4 czasu trwania
// bitu, to kończy działanie funkcji z błędem
while
(
(
(
(RC5_IN)
)
)
)
if
(
(
(
(timerL >
>
>
> ref2)
)
)
)
return
command =
=
=
= -
-
-
-
1
;
;
;
;
}
}
}
}
// W momencie wykrycia zbocza sygnału, synchronizuje
// zmieną timerL dla próbkowania kolejnego bitu
timerL =
=
=
=
0
;
;
;
;
}
}
}
}
// Zwraca kod polecenia rc5
// bity 0..5 numer przycisku
// bity 6..10 kod systemu(urządzenia)
// bit 11 toggle bit
return
command;
;
;
;
}
}
}
}
//---------------------------------------------------------------
// GLÓWNA FUNKCJA PROGRAMU
//---------------------------------------------------------------
int
main(
(
(
(
void
)
)
)
)
{
{
{
{
//
uint cmd;
;
;
;
u8 out;
;
;
;
6 z 7
// Porty PD0..PD6 wyjściami - diody LED
DDRD =
=
=
=
0x7f
;
;
;
;
PORTD =
=
=
=
0x00
;
;
;
;
// uruchamia Timer0 i przerwanie
init_rc5();
();
();
();
while
(
(
(
(
1
)
)
)
)
{
{
{
{
// Wykrywa i dekoduje polecenie pilota RC5
cmd =
=
=
= detect();
();
();
();
// Jeśli odebrano komendę
if
(
(
(
(cmd !=
!=
!=
!= -
-
-
-
1
)
)
)
)
{
{
{
{
// Na sześciu diodach LED pokaże numer polecenia rc5,
// a na siódmej LED - toggle bit
out =
=
=
= (
(
(
(cmd &
&
&
& (
(
(
(
1
<<
<<
<<
<<
11
))
))
))
)) >>
>>
>>
>>
5
;
;
;
;
out |=
|=
|=
|= cmd &
&
&
&
0x3f
;
;
;
;
PORTD =
=
=
= (
(
(
(out);
);
);
);
}
}
}
}
}
}
}
}
return
0
;
;
;
;
}
}
}
}
Listing 1 Program dekodera RC5
Ważne! Program przeznaczony jest dla uC atmega8 taktowanego
zegarem 8MHz. W przypadku, gdy mikrokontroler ma pracować
z częstotliwością inną niż 8MHz, to program będzie wymagał
drobnego dopasowania. Jeśli masz z tym problem, pytaj na forum.
Katalog z plikami projektu można pobrać klikając w link
dekoder_rc5.zip
. Kod wynikowy programu ma wielkość 400 bajtów.
Pisząc niniejszy artykuł opierałem się na atmelowskiej nocie
aplikacyjnej AVR410
doc1473.pdf
.
3.06.11 ABXYZ
Copyright © 2009-2011 ABXYZ - Wszelkie prawa zastrzeżone
7 z 7