V tomto článku se pokusíme rozšířit možnosti ovládání programů s pomocí infračerveného přenosu dat. Použijeme jednoduchý infračervený ovládací pult a infračervený přijímač a budeme dálkově ovládat náš program, který běží na Raspberry Pi Pico. Protokol používaný v infračerveném dálkovém ovládání je poněkud složitější, takže si nevystačíme s programováním GPIO, ale budeme muset použít PIO koprocesor. Infračervené světlo obvykle používané v dálkových ovladačích má vlnovou délku \(\lambda=940 nm\). Vysílač je infračervená LED a přijímačem je infračervená fotodioda.

Infračervený vysílač

Dálkový IR ovladač

IMG 20250501 114823

Dálkový ovladač používá k přenosu dat NEC protokol.

Ne všechny dálkové ovladače používají NEC protokol. Přenosových protokolů v IR ovladačích je spousta. Například: APPLE, DENON, JVC, LG, LG2, NEC2, ONKYO, PANASONIC, KASEIKYO, RC5, RC6, RC6A, SAMSUNG, SHARP, SONY a další. Popis těchto protokolů je dobře dokumentován v knihovně pro Arduino Arduino IRremote

NEC protokol

Modulace

Protokol NEC používá kódování bitů s pulzní vzdáleností. Každý puls je 560 µs dlouhý nosný signál s frekvencí 38 kHz (přibližně 21 cyklů). Přenos logické „1“ trvá 2,25 ms, zatímco přenos logické „0“ trvá pouze polovinu této doby, tedy 1,125 ms. Doporučený pracovní cyklus (střída) nosné je 1/4 nebo 1/3.

Modulace (zakódování 1 a 0) v NEC protokolu

necmodulation

Protokol

Protokol používá dva pojmy: adresa (ta bude u všech ovladačů pro konkrétní zařízení jednoho výrobce stejná) a příkaz — to je kód konkrétního stisknutého tlačítka na ovladači.

Sled impulsů - kódování dat

nectrain

Obrázek nahoře ukazuje typický sled impulsů protokolu NEC. U tohoto protokolu se jako první vysílá LSB (nejméně významny bit). V tomto případě se vysílá adresa 0x59 a příkaz 0x16. Zpráva je zahájena 9ms dávkou (burst) AGC, který se používal k nastavení zisku starších IR přijímačů. Po tomto burstu AGC následuje 4,5ms mezera, po které následuje adresa a příkaz. Adresa a příkaz se vysílají dvakrát. Podruhé jsou všechny bity invertovány a lze je použít k ověření přijaté zprávy. Celková doba přenosu je konstantní, protože každý bit se opakuje s invertovanou délkou. Pokud nemáte zájem o tuto spolehlivost, můžete invertované hodnoty ignorovat nebo můžete adresu a příkaz rozšířit na 16 bitů (to používá NEC extended protokol).

Mějte na paměti, že na konci zprávy musí následovat jedna dávka o délce 560 µs navíc, aby bylo možné určit hodnotu posledního bitu.

Čas celého přenosu je vždy konstatní, protože obsahuje stejný počet jedniček a nul. Je to \(9ms + 4.5ms + (2.25ms+1.12ms)*16 + 0.56 ms = 67.98 ms\) přesně.

Opakování

Příkaz se vyšle pouze jednou, a to i v případě, že je tlačítko na dálkovém ovladači stisknuté déle. Každých 110 ms se vysílá opakující se kód, dokud je tlačítko stisknuté. Tento opakující se kód je jednoduše 9ms impuls AGC, následovaný 2,25ms mezerou a 560µs trvající dávkou.

Opakovací dávka

necrepeat

Příkaz a opakování (celkem 5x)

necsequence

Rozšířený protokol NEC (Extended NEC protocol)

Protokol NEC je tak široce používán, že brzy byly vyčerpány všechny možné adresy. Obětováním redundance adres byl rozsah adres rozšířen z 256 možných hodnot na přibližně 65 000 různých hodnot. Tímto způsobem byl rozsah adres rozšířen z 8 bitů na 16 bitů, aniž by se změnila jakákoli jiná vlastnost protokolu. Rozšířením rozsahu adres tímto způsobem již není celkový čas zprávy konstantní. Nyní závisí na celkovém počtu jedniček a nul ve zprávě. Pokud chcete zachovat celkový čas zprávy konstantní, musíte se ujistit, že počet jedniček v adresním poli je 8 (automaticky to znamená, že počet nul je také 8). Tím se maximální počet různých adres sníží na pouhých 13 000.

Redundance příkazů je stále zachována. Každá adresa tedy stále zvládne 256 různých příkazů.

Rozšířený NEC protokol

necexttrain

Infračervený přijímač

Programování PIO

nec_receive.pio
;
; Copyright (c) 2021 mjcross
;
; SPDX-License-Identifier: BSD-3-Clause
;
.pio_version 0 // only requires PIO version 0

.program nec_receive

; Decode IR frames in NEC format and push 32-bit words to the input FIFO.
;
; The input pin should be connected to an IR detector with an 'active low' output.
;
; This program expects there to be 10 state machine clock ticks per 'normal' 562.5us burst period
; in order to permit timely detection of start of a burst. The initialisation function below sets
; the correct divisor to achieve this relative to the system clock.
;
; Within the 'NEC' protocol frames consists of 32 bits sent least-siginificant bit first; so the
; Input Shift Register should be configured to shift right and autopush after 32 bits, as in the
; initialisation function below.
;
.define BURST_LOOP_COUNTER 30      ; the detection threshold for a 'frame sync' burst
.define BIT_SAMPLE_DELAY 15        ; how long to wait after the end of the burst before sampling

.wrap_target

next_burst:
    set X, BURST_LOOP_COUNTER
    wait 0 pin 0                   ; wait for the next burst to start

burst_loop:
    jmp pin data_bit               ; the burst ended before the counter expired
    jmp X-- burst_loop             ; wait for the burst to end

                                   ; the counter expired - this is a sync burst
    mov ISR, NULL                  ; reset the Input Shift Register
    wait 1 pin 0                   ; wait for the sync burst to finish
    jmp next_burst                 ; wait for the first data bit

data_bit:
    nop [ BIT_SAMPLE_DELAY - 1 ]   ; wait for 1.5 burst periods before sampling the bit value
    in PINS, 1                     ; if the next burst has started then detect a '0' (short gap)
                                   ; otherwise detect a '1' (long gap)
                                   ; after 32 bits the ISR will autopush to the receive FIFO
.wrap


% c-sdk {
static inline void nec_receive_program_init (PIO pio, uint sm, uint offset, uint pin) {

    // Set the GPIO function of the pin (connect the PIO to the pad)
    //
    pio_gpio_init(pio, pin);

    // Set the pin direction to `input` at the PIO
    //
    pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);

    // Create a new state machine configuration
    //
    pio_sm_config c = nec_receive_program_get_default_config (offset);

    // configure the Input Shift Register
    //
    sm_config_set_in_shift (&c,
                            true,       // shift right
                            true,       // enable autopush
                            32);        // autopush after 32 bits

    // join the FIFOs to make a single large receive FIFO
    //
    sm_config_set_fifo_join (&c, PIO_FIFO_JOIN_RX);

    // Map the IN pin group to one pin, namely the `pin`
    // parameter to this function.
    //
    sm_config_set_in_pins (&c, pin);

    // Map the JMP pin to the `pin` parameter of this function.
    //
    sm_config_set_jmp_pin (&c, pin);

    // Set the clock divider to 10 ticks per 562.5us burst period
    //
    float div = clock_get_hz (clk_sys) / (10.0 / 562.5e-6);
    sm_config_set_clkdiv (&c, div);

    // Apply the configuration to the state machine
    //
    pio_sm_init (pio, sm, offset, &c);

    // Set the state machine running
    //
    pio_sm_set_enabled (pio, sm, true);
}
%}

Celý program

Zdroje a odkazy