Bardzo łatwo można zbudować układ do sterowania STM32F4Discovery za pomocą pilota telewizyjnego (TV Remote). Na początek trochę teorii.
Najbardziej powszechne są dwa rodzaje nadajników i odbiorników podczerwieni: 36kHz i 38kHz. Częstotliwości te są używane do modulowania impulsów danych. Odbiornik 36kHz nie będzie reagował na piloty 38kHz i na odwrót. Pilot wysyła impulsy, które po odebraniu przez odbiornik można zamienić na kod przycisku naciśniętego na pilocie. Sposób w jaki są zakodowane impulsy danych (liczba impulsów i ich szerokości), to protokół transmisyjny. Piloty mogą mieć różne protokoły transmisji (zależy od firmy). Najbardziej powszechnym jest chyba protokół RC5, wymyślony przez Philipsa. Więcej o tym można poczytać tutaj: TR Remote Control Theory
Ja akurat zakupiłem (w ciemno bo nie wiedziałem jakie mam piloty) odbiornik podczerwieni na 36kHz: TSOP31236, ale jest podobny na 38kHz: TSOP31238. Zresztą chyba i inne się nadadzą tylko trzeba w notach katalogowych popatrzeć jak je podłączyć. Ja mój podłączyłem tak jak na obrazku poniżej (kondensator i rezystor do testów można sobie darować):
Teraz kot. Konstruujemy klasę, która podłączona pod nóżkę odbiornika będzie informowała (EventHandler) o odebranych danych. Interesuje nas stan (1 lub 0) oraz czas trwania każdego impulsu. Obsługujemy każdą zmianę sygnału na pinie odbiornika (InterruptEdgeBoth).
public class IRReceiver : IDisposable { public delegate void PulseEventHandler(TimeSpan width, bool state); public event PulseEventHandler Pulse; private readonly InterruptPort _receiverPort; private long _lastTick = DateTime.Now.Ticks; public IRReceiver(Cpu.Pin pin) { _receiverPort = new InterruptPort(pin, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth); _receiverPort.OnInterrupt += PortInterrupt; } public void Dispose() { _receiverPort.Dispose(); } private void PortInterrupt(uint port, uint state, DateTime time) { long current = time.Ticks; TimeSpan pulseWidth = TimeSpan.FromTicks(current - _lastTick); _lastTick = current; //Debug.Print("pulse " + pulseWidth.TotalMicroseconds()+ "us " + state); if (Pulse != null) Pulse(pulseWidth, state == 1); } }
Teraz program, który będzie reagował na impulsy z IRReceiver. Na razie bez rozpoznawania protokołu transmisyjnego i dekodowania impulsów. Będziemy włączać i wyłączać diody na płytce STM32F4Discovery dowolnym klawiszem na pilocie. Nie możemy jednak reagować na każdy impuls, bo w ramce transmisyjnej może ich być kilka czy kilkanaście i diody będą miały losowy stan. Robimy więc opóźnienie, tak aby reagować na pierwszy impuls, a na kolejny dopiero po 500 milisekundach.
public class Program { private const int DelayBetweenCommands = 500; //ms public static void Main() { var leds = new[] { new OutputPort(Stm32F4Discovery.LedPins.Green, true), new OutputPort(Stm32F4Discovery.LedPins.Orange, true), new OutputPort(Stm32F4Discovery.LedPins.Red, true), new OutputPort(Stm32F4Discovery.LedPins.Blue, true) }; var receiver = new IRReceiver(Stm32F4Discovery.FreePins.PB5); DateTime nextCommand = DateTime.MinValue; receiver.Pulse += (width, state) => { DateTime now = DateTime.Now; if (now < nextCommand) return; nextCommand = now.AddMilliseconds(DelayBetweenCommands); Toggle(leds); }; Thread.Sleep(Timeout.Infinite); } private static void Toggle(OutputPort[] leds) { bool state = !leds[0].Read(); foreach (OutputPort led in leds) led.Write(state); } }Piloty w dłoń i celujemy w odbiornik. Naciskamy dowolne klawisze. U mnie w domu na trzy piloty dwa były 36kHz, a jeden prawdopodobnie 38kHz.
Pełny kot: DemoIRReceiver
Brak komentarzy:
Prześlij komentarz