ИК-передатчик из Arduino

В предыдущей статье про ИК канал обмена данными был рассмотрен приемник. Это наиболее востребованная задача, т.к. излучателем являются, как правило, пульты ДУ от различной бытовой радиоаппаратуры. Вместе с тем интересно посмотреть как в библиотеке IRremote реализована передача сигнала.ir_vd

Для указанной библиотеки есть стандартный пример для передатчика IRsendDemo.

#include <IRremote.h>

IRsend irsend;

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.read() != -1) {
    for (int i = 0; i < 3; i++) {
      irsend.sendSony(0xa90, 12); // Sony TV power code
      delay(40);
    }
  }
}

Простой пример реализует посылку по ИК каналу команды включения ТВ (видимо) при каждом приеме символа по последовательному интерфейсу. При этом инфракрасный светодиод должен быть подключен к pin3 Arduino (это непременное условие для указанной библиотеки). Анодом к pin3, катодом — через токоограничивающий резистор — на землю. Подключение ИК диода ничем не отличается от подключения к Arduino обычного светодиода и подробно рассмотрено ранее.

Кроме метода sendSony(), в библиотеке реализован ряд алгоритмов кодирования применяемых другими фирмами. В файле библиотеки IRremote.cpp есть методы:

void IRsend::sendNEC(unsigned long data, int nbits)
void IRsend::sendSony(unsigned long data, int nbits)
void IRsend::sendRaw(unsigned int buf[], int len, int hz)
void IRsend::sendRC5(unsigned long data, int nbits)
void IRsend::sendRC6(unsigned long data, int nbits)
void IRsend::sendPanasonic(unsigned int address, unsigned long data)
void IRsend::sendJVC(unsigned long data, int nbits, int repeat)
void IRsend::sendSAMSUNG(unsigned long data, int nbits)

Практически, на «все случаи жизни»…

Рассмотрим наиболее универсальную процедуру sendRaw()

void IRsend::sendRaw(unsigned int buf[], int len, int hz) {
  enableIROut(hz);
  for (int i = 0; i < len; i++) {
    if (i & 1) {
      space(buf[i]);
    } 
    else {
      mark(buf[i]);
    }
  }
  space(0); // Just to be sure
}

Сначала, собственно, включается режим передачи ИК: процедура enableIROut(hz) включает ШИМ на выводе 3 (используется таймер 2) — тем самым осуществляется модуляция сигнала с заданной (hz — частота модуляции в килогерцах) частотой. Затем из буфера buf[] выбираются значения длительностей импульсов (в микросекундах) и четные значения передаются импульсом (mark() заданной в массиве длины), а нечетные — паузой (space() так же заданной длины). Таким образом, создав массив buf длиной len, можно передать практически любой код через импровизированный ИК-передатчик.

Процедуры mark(), space() и enableIROut() доступны для использования в скетче, так что можно реализовать передачу любого «самодельного» кода. При работе с библиотекой надо помнить, что таймер 2 — ЗАНЯТ и прерывания от него либо блокируются, либо используются «не нами». И с выводом 3 надо быть аккуратным…

void IRsend::mark(int time) {
  // Sends an IR mark for the specified number of microseconds.
  // The mark output is modulated at the PWM frequency.
  TIMER_ENABLE_PWM; // Enable pin 3 PWM output
  if (time > 0) delayMicroseconds(time);
}

/* Leave pin off for time (given in microseconds) */
void IRsend::space(int time) {
  // Sends an IR space for the specified number of microseconds.
  // A space is no output, so the PWM output is disabled.
  TIMER_DISABLE_PWM; // Disable pin 3 PWM output
  if (time > 0) delayMicroseconds(time);
}

void IRsend::enableIROut(int khz) {
  // Enables IR output.  The khz value controls the modulation frequency in kilohertz.
  // The IR output will be on pin 3 (OC2B).
  // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
  // to make sure it gives reasonable results.  (Watch out for overflow / underflow / rounding.)
  // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
  // controlling the duty cycle.
  // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
  // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
  
  // Disable the Timer2 Interrupt (which is used for receiving IR)
  TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
  
  pinMode(TIMER_PWM_PIN, OUTPUT);
  digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
  
  // COM2A = 00: disconnect OC2A
  // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
  // WGM2 = 101: phase-correct PWM with OCRA as top
  // CS2 = 000: no prescaling
  // The top value for the timer.  The modulation frequency will be SYSCLOCK / 2 / OCR2A.
  TIMER_CONFIG_KHZ(khz);
}

Добавить комментарий