Отправить через инфракрасный порт на Arduino

Мне нужно передать инфракрасный сигнал с помощью Arduino для запуска телевизора Samsung.

Я попробовал следующий код:

// Lucas Eckels
// Http://lucaseckels.com

// IR remote control emitter for NEC protocol remote, as described at
// Http://www.sbprojects.com/knowledge/ir/nec.htm
// Tested on a Samsung LCD TV.

#include <util/delay.h>

#define IR_PIN 13

// With CONTINOUS defined, the first command is repeated continuously until
// You reset the Arduino. Otherwise, it sends the code once, then waits for
// Another command.
#define CONTINUOUS

// Times are in microseconds
#define ON_START_TIME 4500
#define OFF_START_TIME 4500
#define ON_TIME 580
#define OFF_TIME_ONE 1670
#define OFF_TIME_ZERO 540

#define DEVICE_1 7
#define DEVICE_2 7

void setup() {
  pinMode (IR_PIN, OUTPUT);
  digitalWrite(IR_PIN, LOW);
  Serial.begin(9600);
  delay(1000);
  Serial.write("Starting up..\n");
}

byte command = 0;
int commandCount = 0;
bool commandReady = false;

void loop() {
  if (commandReady) {
    Serial.print("Writing command");
    Serial.print(command, DEC);
    Serial.print("\n");

    writeStart();
    // Writing device code
    writeByte(DEVICE_1);
    writeByte(DEVICE_2);

    // Writing command code
    writeByte(command);
    writeByte(~command);
    writeEnd();
    delay(100);

#ifndef CONTINUOUS
    commandReady = false;
    command = 0;
    commandCount = 0;
#endif
    return;
  }

  if (Serial.available () > 0) {
    // Read in a 3-digit decimal command code.
    byte incoming = Serial.read();
    if (incoming <= '9 ' || incoming >= '0') {
      command *= 10;
      command += incoming - '0 ';
      ++commandCount;
    }
    if (commandCount == 3) {
      commandReady = true;
    }
  }
}

void writeStart() {
  modulate(ON_START_TIME);
  delayMicroseconds(OFF_START_TIME);
}

void writeEnd() {
  modulate(ON_TIME);
}

void writeByte(byte val) {
  // Starting with the LSB, write out the
  for (int i = 0x01; i & 0xFF; i <<= 1) {
    modulate(ON_TIME);
    if (val & i) {
      delayMicroseconds (OFF_TIME_ONE);
    } else {
      delayMicroseconds (OFF_TIME_ZERO);
    }
  }
}

void modulate(int time) {
  int count = time / 26;
  byte portb = PORTB;
  byte portbHigh = portb | 0x20; // Pin 13 is controlled by 0x20 on PORTB.
  byte portbLow = portb & ~0x20;
  for (int i = 0; i <= count; i++) {
    // The ideal version of this loop would be:
    // DigitalWrite(IR_PIN, HIGH);
    // DelayMicroseconds(13);
    // DigitalWrite(IR_PIN, LOW);
    // DelayMicroseconds(13);
    // But I had a hard time getting the timing to work right. This approach was found
    // Through experimentation.
    PORTB = portbHigh;
    _delay_loop_1(64);
    PORTB = portbLow;
    _delay_loop_1(64);
  }
  PORTB = portb;
}

Код компилируется, но у меня не работает.


person oren berkovich    schedule 21.12.2011    source источник
comment
i++ кажется мне подозрительным — возможно, i++ будет работать лучше?   -  person David Cary    schedule 24.12.2011
comment
У вас было значительное количество ошибок в вашем коде, поэтому я отредактировал и исправил их, чтобы, по крайней мере, он правильно скомпилировался. Не говоря уже о том, что я добавил что-то, что на самом деле заставит его работать так, как ожидалось. Смотрите мой ответ для этого.   -  person fulvio    schedule 17.02.2012


Ответы (2)


Я написал это для управления телевизором LG и усилителем Sony. Вам просто нужно сохранить свои собственные необработанные коды в заголовочный файл, и все готово:

https://github.com/gotnull/SiriProxy-TV-Control/blob/master/arduino-remote/Remote/Remote.pde

// This procedure sends a 38KHz pulse to the IRledPin
// for a certain # of microseconds. We'll use this whenever we need to send codes
void pulseIR(long microsecs) {
  // we'll count down from the number of microseconds we are told to wait

  cli(); // this turns off any background interrupts

  while (microsecs > 0) {
    // 38 kHz is about 13 microseconds high and 13 microseconds low
   digitalWrite(IRledPin, HIGH); // this takes about 3 microseconds to happen
   delayMicroseconds(10); // hang out for 10 microseconds
   digitalWrite(IRledPin, LOW); // this also takes about 3 microseconds
   delayMicroseconds(10); // hang out for 10 microseconds

   // so 26 microseconds altogether
   microsecs -= 26;
  }

  sei(); // this turns them back on
}

Я бы также порекомендовал прочитать замечательный учебник Ледиады:

Учебные пособия по датчикам – руководство по удаленному ИК-приемнику/декодеру

person fulvio    schedule 17.02.2012
comment
@orenberkovich Это вообще помогло? - person fulvio; 20.02.2012

DelayMicroseconds довольно точен и будет достаточно точен для вашей задачи. Однако вы правы, держась подальше от DigitalWrite. Для завершения требуется примерно в 50 раз больше тактов по сравнению с прямым назначением портов (PORTB=... ), которое занимает ровно один. Таким образом вы сможете синхронизировать только импульс 38 МГц. Я не знаю, что делает ваш _delay_loop_1, но все остальное вроде в порядке. (кроме "i + +", но я думаю, это опечатка вырезания и вставки)

Вы проверили, что он действительно горит? телефон или дешевая цифровая камера на самом деле покажет вам ИК на экране.

person Esben    schedule 02.01.2012