Odbiornik i piloty - szary (po lewej) i biały (po prawej) |
Wymieniony w temacie pilot kupiłem z myślą o sterowaniu radiem TEA5767. Jak dotąd do sterowania (wprowadzania danych) korzystałem z takich elementów jak przycisk, enkoder, czy całkiem wygodny joystick 5 pozycyjny (tj. z enterem). Do sterowania radiem jednak potrzebowałem czegoś bardziej wyszukanego i myślę, że taki pilot całkiem dobrze sprawdził się w tej roli. Zakupione piloty nie są tak wygodne jak te od telewizora, ale przynajmniej kompaktowe. Szary z nich dostałem z HX1838, drugi biały dokupiłem oddzielnie, gdyż wydawało mi się, że jego przyciski odpowiadają lepiej specyfice sterowania radiem. Mam na myśli to, że będzie się nim intuicyjniej sterowało.
Parametry
Poniżej podaję parametry zestawu, wyczytane ze strony sprzedawcy pilota oraz chińskiej dokumentacji HX1838.
Parametry nadajnika:
- zasilanie baterią CR2025 (dostarczona z pilotem)
- zasięg 5-8m
- standard nadawania NEC
- nośna 38kHz
Parametry odbiornika:
- napięcie zasilania od 2,7V do 5,5V
- kąt odbioru 60 stopni
- pobierany prąd 0,8-1,5mA
- LED sygnalizująca zasilanie
Odbiornik |
Schemat elektroniczny układu z odbiornikiem |
Co wysyła pilot?
Jak pisałem wcześniej sprawdzałem "biały" pilot, ale oba działają w oparciu o protokół NEC. Oto wnioski:
1) Wysyłają oczywiście kody odpowiadające wciśniętym przyciskom. Są to sześciocyfrowe liczby rozpoczynające się od 0xFF. Kolejne cyfry odpowiadają za identyfikację przycisku. Na przykład przycisk "Power" posiada kod 0xFFA25D. Precyzując, właściwy kod przycisku stanowi liczba złożona z 3 i 4-tej cyfry, czyli A2. Z kolei liczba złożona z cyfry 5 i 6-tej (5D) stanowi jej negację, czyli:
!0xA2 = 0x5D
Kody przycisków testowanego pilota |
2) Jeśli przycisk jest przytrzymany przez 108ms (i więcej), to przesyłany jest zgodnie z protokołem NEC kod powtórzenia 0xFFFFFFFF - także co 108ms aż do puszczenia przycisku. Z moich spostrzeżeń wynika, że nawet przy jednorazowym i szybkim wciśnięciu danego przycisku jest duża szansa, że zaraz po kodzie przycisku zostanie wysłany kod powtórzenia. Tak więc, w zależności od potrzeb można ignorować ten kod lub zapamiętywać ostatnio wybrany kod i wtedy jest wiadomo, jaki przycisk został powtórnie wciśnięty czy też przytrzymany.
3) Niestety wysyłają także błędne kody odpowiadające wciśniętym przyciskom, tym razem 8-mio cyfrowe i nie rozpoczynające się do 0xFF. Obrazowo mówiąc, przychodziły co pewien czas dla każdego z przycisków. Wyjątkiem był 'Previous', ale to być może mi po prostu nie udało się znaleźć takiego kodu, bo za mało go używałem. Szczęśliwie, kody te są powtarzalne, tak więc można je wykryć i obsługiwać tak samo jak standardowe kody przycisków.
Co z błędnymi kodami?
Pojawiały się przy użyciu biblioteki IRemote (ale bynajmniej nie z powodu jej użycia). Po uruchomieniu debugowania okazało się, że przy problematycznych kodach nie zostało rozpoznane dekodowanie NEC i program kończył działanie na dekodowaniu Denon, wynikiem czego był ten drugi, inny kod. Z logów generowanych przez IRemote wynikało, że dla NEC nie przechodziła walidacja przesyłanego sygnału (rozjazd w czasach pojawiania się kolejnych impulsów w sygnale niezgodny z protokołem NEC).
Postanowiłem sprawdzić przy tej okazji inną bibliotekę o nazwie IRLib. W jej przypadku dla błędnych kodów otrzymywałem po prostu zero.
Przy obsłudze kodu, można ignorować te nadmiarowe kody (jako błąd) albo traktować jak standardowy kod przycisku. Ja wybrałem to drugie rozwiązanie. Przy włączaniu radia lub zmianie kanałów ignorowanie takich kodów było by irytujące.
W przypadku drugiego z pilotów ("szarego"), tych błędnych kodów było mniej. Po zamianie baterii z pilotów, biały pilot generował zauważalnie mniej błędnych kodów. Użycie zupełnie nowej baterii także nie rozwiązało problemu. To pozwala sądzić, że przynajmniej częściowo, za błędne kody odpowiada zużyta (częściowo) bateria.
Kod obsługi pilota
Jak wspomniałem wcześniej, skorzystałem z biblioteki IRremote. Według posta Arduino: 10 common pitfalls with Infrared Remote Control (5) IRLib jest nowsza i ma większe możliwości. Nie radziła sobie jednak na dzień dobry z błędnymi kodami (tj., nie zwracała ich).
Poniżej przedstawiam kod stosowany przeze mnie przystosowany do białego pilota. Tak jak posty, kod pisany był wieczorami, więc nie biorę odpowiedzialności za jego poprawne działanie ;) Kilka słów jeszcze o nim:
- wykrywa kody standardowe i błędne dla wybranych/wciśniętych przycisków
- obsługuje powtórzenia przycisków
- wykrywa liczby dwucyfrowe, jeśli w ciągu 1,5 sekundy zostaną wybrane dwie cyfry
- informacje o wciśniętych przyciskach (kodach) wysyłane są przez złącze szeregowe na np. terminal PC (forma debuggera)
#include <SoftwareSerial.h> #include <Wire.h> #include "libs/IRremote/IRremote.h" #define RECV_PIN 12 //pin connected with IR receiver #define DEFAULT_NUMERIC_VALUE 10 //default value for empty variable #define NUMBER_TIMEOUT 1500 //1.5 second to select two numbers IRrecv irrecv(RECV_PIN); decode_results results; unsigned long currentButtonCode; unsigned long lastButtonCode; unsigned long lastNumericButtonTime = millis(); uint8_t lastNumericButton = DEFAULT_NUMERIC_VALUE; uint8_t newNumericButton = DEFAULT_NUMERIC_VALUE; void setup() { Serial.begin(9600); irrecv.enableIRIn(); //Start the receiver while (!Serial) { // wait for serial port to connect. Needed for native USB port only } Serial.println(F("Pilot IR test")); } void loop() { uint8_t numericButton = DEFAULT_NUMERIC_VALUE; if (irrecv.decode(&results)) { currentButtonCode = results.value; if (currentButtonCode == 0xFFFFFFFF) { //repeated button, get last button code //comment to ignore repeated NEC code currentButtonCode = lastButtonCode; } else { lastButtonCode = currentButtonCode; } Serial.print(F("selected key: ")); switch (currentButtonCode) { case 0xFFA25D: case 0xE318261B: Serial.print(F("IR_KEY_POWER")); break; case 0xFFE01F: Serial.print(F("PREVIOUS")); break; case 0xFF906F: case 0xE5CFBD7F: Serial.print(F("NEXT")); break; case 0xFFE21D: case 0xEE886D7F: Serial.print(F("IR_KEY_MENU")); break; case 0xFF02FD: case 0xD7E84B1B: Serial.print(F("IR_KEY_PLUS")); break; case 0xFF9867: case 0x97483BFB: Serial.print(F("IR_KEY_MINUS")); break; case 0xFFC23D: case 0x20FE4DBB: Serial.print(F("IR_KEY_EXIT")); break; case 0xFF22DD: case 0x52A3D41F: Serial.print(F("IR_KEY_TEST")); break; case 0xFFB04F: case 0xF0C41643: Serial.print(F("IR_KEY_CONTROL")); break; case 0xFFA857: case 0xA3C8EDDB: Serial.print(F("IR_KEY_ENTER")); break; case 0xFF6897: case 0xC101E57B: Serial.print(F("ZERO")); numericButton = 0; break; case 0xFF30CF: case 0x9716BE3F: Serial.print(F("ONE")); numericButton = 1; break; case 0xFF18E7: case 0x3D9AE3F7: Serial.print(F("TWO")); numericButton = 2; break; case 0xFF7A85: case 0x6182021B: Serial.print(F("THREE")); numericButton = 3; break; case 0xFF10EF: case 0x8C22657B: Serial.print(F("FOUR")); numericButton = 4; break; case 0xFF38C7: case 0x488F3CBB: Serial.print(F("FIVE")); numericButton = 5; break; case 0xFF5AA5: case 0x449E79F: Serial.print(F("SIX")); numericButton = 6; break; case 0xFF42BD: case 0x32C6FDF7: Serial.print(F("SEVEN")); numericButton = 7; break; case 0xFF4AB5: case 0x1BC0157B: Serial.print(F("EIGHT")); numericButton = 8; break; case 0xFF52AD: case 0x3EC3FC1B: Serial.print(F("NINE")); numericButton = 9; break; case 0xFFFFFFFF: Serial.print(F("REPEATED KEY")); break; default: Serial.print(F("UNKNOWN")); break; } Serial.print(F(" => hex: ")); Serial.print(results.value, HEX); Serial.println(); //Receive the next value irrecv.resume(); } //find double numbers if (numericButton != DEFAULT_NUMERIC_VALUE) { if (lastNumericButton == DEFAULT_NUMERIC_VALUE) { lastNumericButton = numericButton; lastNumericButtonTime = millis(); } else if (newNumericButton == DEFAULT_NUMERIC_VALUE) { newNumericButton = numericButton; } } if (lastNumericButton != DEFAULT_NUMERIC_VALUE && (millis() - lastNumericButtonTime > NUMBER_TIMEOUT)) { if (newNumericButton != DEFAULT_NUMERIC_VALUE) { Serial.print(F("selected number: ")); Serial.println(lastNumericButton * 10 + newNumericButton); } else if (lastNumericButton > 0) { Serial.print(F("selected number: ")); Serial.println(lastNumericButton); } newNumericButton = DEFAULT_NUMERIC_VALUE; lastNumericButton = DEFAULT_NUMERIC_VALUE; } delay(10); }
Źródła:
1) Dokumentacja HX1838
2) Opis protokołu NEC
3) Biblioteka IRemote
4) Biblioteka IRLib
5) Arduino: 10 common pitfalls with Infrared Remote Control
A czy ten kondensator to nie jest przypadkiem odwrotnie wlutowany? Wg schematu minus powinien być chyba przy GND. Czy się mylę?
OdpowiedzUsuńMinus powinien być przy GND. Teraz z fotki trudno to ustalić. Inna sprawa, że mam też elektrolity, dla których polaryzacja nie ma znaczenia.
Usuń