Detekcja zera i odczyt kodów RC5
Witam
Dziś chciałbym się z wami podzielić bardzo ciekawym tematem, a mianowicie odczyt kodów NEC RC5 przez procesor Atmega.
Standart RC5 został opracowany przez firmę Philips jakiś czas temu, nie będę się tu zbyt wgłębiał w jego opis, nie mniej podstawy nam będą potrzebne aby umieć odczytaćgo.
Tak więc zaczynając od początku. Bity kodowane są w standardzie Manchester:
logiczne “1” skłąda się ze stanu wysokiego trwającego 560us oraz 1.56ms stanu nieskiego. Długość 1 to 2.25ms
logiczne “0” składa się ze stanu wysokiego trwającego 560us oraz 560us stanu nieskiego. Długośc 0 to 1.125ms
Na początku transmisji pilot nadaje stan wysoki przez 9ms następnie stan niski /cisza/ przez 4,5ms, jest to tak zwanę AGC, i służy do synchronizacji odbiornika. po AGC nadawane jest 8bitów adresu i 8bitów adresu zanegowanego, oraz 8bitów danych i kolejno 8bitów zanegowanych danych.
Bity nadawane są w kolejności młodszy (LSB) a następnie starszy (MSB), swoją drogą zawsze mam problem zapamiętać te skróty :). Po bitach wysyłany jest znacznik końca transmisji (który jest wręcz niezbędny, jeśli chcemy napisać procedurę odczytu na przerwaniach).
Cała transmisja trwa zawsze tyle samo dzięki wysyłaniu negacji kodów, czyli około (1.25+2.25)*16+9+4.5 + 0,56= 70.06ms. Po okolo 39.96ms, jeśli klawisz pilota nadal jest nienaciśnięty zostaje wysłany kod powtórzenia czyli 560us stan wysoki, 2,25ms stan niski oraz 560us stan wysoki znacznik końca transmisji.
Moją procedurę odczytu kodów NEC RC5 oparłem na przerwaniu, gdyż wstrzymywanie pracy procesora na czas 110ms to marnowanie mocy obliczeniowej AVR-ka.
Przerwanie INT0 generowane jest w czasie opadającego zbocza, ponieważ jako odbiornik zastosowałem TSOP1836, który wisi na pinie z puulup-em, czyli odbiór logicznej “1” to tak naprawdę ściągnięcie pinu do masy. a tym samym opadające zbocze generuje nam przerwanie.
Kolejną rzeczą jaka będziemy potrzebować to jakiś licznik, użyłem do tego celu TIMER1, działającego z częstotliwością 20kHz, przerwanie generowanie jest więc co 50us, taki interwał w zupełności wystarczy do zmierzenia czasów, przyda on nam się także do innych rzeczy, ale to w innym cyklu.
Po zgłoszeniu pierwszego przerwania INT0, sprawdzam w jakim stanie odczytu kodu jestem. Cała procedura przerwania jest uzależniona od tego w jakiej fazie aktualnie się znajdujemy.
faza 0 – wznoszącego zbocze AGC, zerujemy licznik, ustawiamy parametry itp.
faza 1 – jesteśmy tuż przed pierwszym bitem danych, ale aby się o tym przekonać musimy sprawdzić czy czas jaki minął od fazy 0 to 13,5ms. Jeśli tak faktycznie jest to zmieniamy stan na 2. natomiast jeśli ten czas waha się w granicach 39.96ms lub 110ms to znaczy że pilot wysyła kod powtórki, informujemy odebranie kodu i przechodzimy do fazy 0.
faza 2 – odczyt bitów, tu sprawa jest prosta bo jeśli odczytany interwał jest w granicach 1.25ms to mamy 0, jeśli 2,25ms to mamy 1, dodajemy odczytany bit na koniec słowa przesuwamy je i sprawdzamy czy już nastąpiły 33 impulsy, jeśli tak to odczytaliśmy wszystkie 32 bity . Zapamiętujemy sobie te dane, ponieważ podczas powtórki musimy ich ponownie użyć.
Ale dlaczego 33 impulsy?? tu właśnie przychodzi nam z pomocą wysyłany ostatni impuls na końcu transmisji, który pozwala nam zmierzyć długość ostatniego bitu. Wydaje się proste, nie mniej jednak najwięcej problemów napotkamy z interwałami czasowym. Ja przyjąłem zasadę, po zmierzeniu kilku pilotów, że dobrym rozwiązaniem będzie mierzenie czasu od-do, co zresztą się sprawdziło.
Środowisko testowe stanowiła płytka EVB 4.3 z procesorem ATMEGA32 z kwarcem 16MHz natomiast układ wykonawczy został wykonany na płytce stykowej.
Poniżej test detekcji zera przy pomocy EVB4.3
Efekt widoczny jest na poniższym filmie:
Na filmie widzimy jak atmega daje sobię radę z odczytaniem kodu pilota, jednocześnie wysyłając go przez RS232, a także z jednoczesną detekcją zera i generowaniem impulsu wyzwalającego dla triaka.
Niebieska linia to 12V mierzone zaraz za mostkiem Gretza, natomiast żółta linia to sygnał wyzwalający dla triaka. Widoczne jest przesuwanie się pików względem sygnału sinusoidalnego.
kawałek kodu przerwania timera
1 ISR(TIMER0_COMP_vect)2 {
3 timerIR++;
4 if( timerIR>2000 && rcStatus!=0)5 rcStatus=0;6 return;7 }
8
01 02 ISR(INT0_vect)03 {
04 cli();05 switch(rcStatus)06 {
07 case 0:08 rcStatus=1;09 break;10 11 case 1: //pulse AGC12 {
13 if(timerIR>=265 && timerIR< =275)14 {
15 tmpData = 0;16 rcData=0;17 rcStatus = 2;18 rcBits = 0;19 }
20 else
21 {
22 if((timerIR>220 && timerIR<230)||(timerIR>=1910 && timerIR< =1920))23 {
24 rcReady=1;25 }
26 else
27 {
28 rcReady=0;29 }
30 rcStatus=0;31 }
32 }
33 break;34 35 case 2:36 {
37 if(timerIR>42 && timerIR<46)38 {
39 tmpData |= 0x8000;40 }
41 else
42 {
43 if(timerIR<20 && timerIR>25)44 {
45 rcReady=0;46 rcStatus=0;47 break;48 }
49 }
50 51 if(++rcBits==16)52 {
53 rcData |= (tmpData & 0x00ff);54 }
55 else
56 {
57 if(rcBits==32)58 {
59 rcData < <=8;60 rcData |= (tmpData & 0x00ff);61 rcStatus=0;62 }
63 }
64 tmpData >>=1;65 } break;66 }
67 timerIR=0;68 sei();69 return;70 }
71