New IR transmit program

I just got the Arduino a few days ago and must say that I am quite taken with it. I have quite a lot to learn, but I thought that I'd share my latest creation with you all. I commented it pretty well and tried to be clear when things got a little messy. If you use it, let me know how this works for you!

I wish that I could actually just paste the program here, but it looks as if I will exceed the maximum number of characters by a fair amount. Below is the code for the program, but without the comments. If you want the complete code with all its comments please get it here: http://dustinj.us/files/arduino/Arduino_IR_Transmit.txt

/*********************************\
 *  Author: Dustin Johnson       *
 *  E-mail: Dustin@Dustinj.us    *
 *  Date: January 4, 2008        *
\*********************************/

#define REPLAY_COUNT         4
#define IR_LED_PIN           6     
#define STATUS_LED_PIN       7

#define FRAME_INTERVAL        45000
#define START_INTERVAL        2400
#define LOGICAL_ONE_INTERVAL  1200
#define LOGICAL_ZERO_INTERVAL 600
#define GUARD_INTERVAL        400

#define CMD_NUMBER_1         0x00
#define CMD_NUMBER_2         0x01
#define CMD_NUMBER_3         0x02
#define CMD_NUMBER_4         0x03
#define CMD_NUMBER_5         0x04
#define CMD_NUMBER_6         0x05
#define CMD_NUMBER_7         0x06
#define CMD_NUMBER_8         0x07
#define CMD_NUMBER_9         0x08
#define CMD_NUMBER_0         0x09
#define CMD_ENTER            0x0B
#define CMD_CHANNEL_UP       0x10
#define CMD_CHANNEL_DOWN     0x11
#define CMD_VOLUME_UP        0x12
#define CMD_VOLUME_DOWN      0x13
#define CMD_MUTE             0x14
#define CMD_POWER            0x15
#define CMD_RESET            0x16
#define CMD_MTS              0x17
#define CMD_PICTURE_UP       0x18
#define CMD_PICTURE_DOWN     0x19
#define CMD_COLOR_UP         0x1A
#define CMD_COLOR_DOWN       0x1B
#define CMD_BRIGHTNESS_UP    0x1E
#define CMD_BRIGHTNESS_DOWN  0x1F
#define CMD_HUE_RED          0x20
#define CMD_HUE_GREEN        0x21
#define CMD_SHARPNESS_UP     0x22
#define CMD_SHARPNESS_DOWN   0x23
#define CMD_SELECT_TV_TUNER  0x24
#define CMD_INPUT            0x25
#define CMD_BALANCE_LEFT     0x26
#define CMD_BALANCE_RIGHT    0x27
#define CMD_STEADY_SOUND     0x28
#define CMD_SOUND_EFFECT     0x29
#define CMD_AUX_ANT          0x2A
#define CMD_POWER_ON         0x2E
#define CMD_POWER_OFF        0x2F
#define CMD_TIME_DISPLAY     0x30
#define CMD_RIGHT_ARROW      0x33
#define CMD_LEFT_ARROW       0x34
#define CMD_TIME_SET         0x35
#define CMD_SLEEP            0x36
#define CMD_DISPLAY          0x3A
#define CMD_JUMP             0x3B
#define CMD_SELECT_VIDEO_1   0x40
#define CMD_SELECT_VIDEO_2   0x41
#define CMD_SELECT_VIDEO_3   0x42
#define CMD_NOISE_REDUCTION  0x4A
#define CMD_CABLE_BROADCAST  0x4E
#define CMD_NOTCH_FILTER     0x4F
#define CMD_PIP_CHANNEL_UP   0x58
#define CMD_PIP_CHANNEL_DOWN 0x59
#define CMD_PIP_ON           0x5B
#define CMD_FREEZE_SCREEN    0x5C
#define CMD_PIP_POSITION     0x5E
#define CMD_PIP_SWAP         0x5F
#define CMD_MENU             0x60
#define CMD_VIDEO_SETUP      0x61
#define CMD_AUDIO_SETUP      0x62
#define CMD_EXIT_SETUP       0x63
#define CMD_VIDEO_MODE       0x64
#define CMD_PLUS_BUTTON      0x65
#define CMD_AUTO_PROGRAM     0x6B
#define CMD_TREBLE_UP        0x70
#define CMD_TREBLE_DOWN      0x71
#define CMD_BASS_UP          0x72
#define CMD_BASS_DOWN        0x73
#define CMD_UP_ARROW         0x74
#define CMD_DOWN_ARROW       0x75
#define CMD_ADD_CHANNEL      0x78
#define CMD_DELETE_CHANNEL   0x79
#define CMD_TRINITONE        0x7D
#define CMD_RED_TEST         0x7F

#define DEV_SONY             0x01

void setup() {
  initialize_ir(IR_LED_PIN, STATUS_LED_PIN);
}

void loop() {
  send_ir_code(DEV_SONY, CMD_POWER, IR_LED_PIN, STATUS_LED_PIN);
  delay(500);
}

void initialize_ir(byte ir_pin, byte status_pin) {
  pinMode(status_pin, OUTPUT);
  pinMode(ir_pin, OUTPUT);
  digitalWrite(status_pin, LOW);
  digitalWrite(ir_pin, LOW);
  prepare_timer();
}

void prepare_timer() {
  TCCR1A = 0x00;
  TCCR1B = (1 << CS11) | (1 << CS10);
  TIMSK1 = 0x00;
}

boolean send_ir_code(byte device_code, byte command_code, byte ir_pin, byte status_pin) {
  int data;

  if (ir_pin > 7) {
    return false;
  }

  ir_pin = 0x0001 << ir_pin;
  
  if (((device_code & 0x1F) != device_code) ||
    ((command_code & 0x7F) != command_code)) {
    return false;
  }

  data = ((device_code & 0x1F) << 7) | (command_code & 0x7F);

  digitalWrite(status_pin, HIGH);

  for(int j=0; j<REPLAY_COUNT; j++) {
    TCNT1 &= ~TCNT1;
    ir_write_start(ir_pin);

    for (int i=0; i<12; i++) {
      if ((data >> i) & 0x0001) {
        ir_write_one(ir_pin);
      }
      else {
        ir_write_zero(ir_pin);
      }
    }

    ir_write_frame_space(ir_pin, FRAME_INTERVAL - (TCNT1*4));
  }

  digitalWrite(status_pin, LOW);
}

void ir_write_start(byte pin) {
  ir_raw_write_high(pin, START_INTERVAL);
  ir_raw_write_low(pin, GUARD_INTERVAL);
}

void ir_write_zero(byte pin) {
  ir_raw_write_high(pin, LOGICAL_ZERO_INTERVAL);
  ir_raw_write_low(pin, GUARD_INTERVAL);
}

void ir_write_one(byte pin) {
  ir_raw_write_high(pin, LOGICAL_ONE_INTERVAL);
  ir_raw_write_low(pin, GUARD_INTERVAL);
}

void ir_write_frame_space(byte pin, unsigned int time) {
  ir_raw_write_low(pin, time);
}

void ir_raw_write_low(byte pin, unsigned int time) {
  PORTD = PORTD & ~pin; // sets pin LOW
  delayMicroseconds(time);
}

void ir_raw_write_high(byte pin, unsigned int time) {
  for(int i=0; i <= time/26; i++) {
    PORTD = PORTD | pin;
    delayMicroseconds(13);
    PORTD = PORTD & ~pin;
    delayMicroseconds(13);
  }
}

Very nicely done!

Just out of curiosity, why you used this construct: TCNT1 &= ~TCNT1; Instead of: TCNT1 = 0;

Ugh, sorry about that. :o

It's a hold over from the days when on the x86 platform it was quicker to and something with the inverse than it was to set it to zero. It was also quicker to xor something with itself.

If you dont mind, I post “my” code, I derived from yours. It triggers the shutter of a Nikon D80 and should also work with D70(s) and probably all the other Nikons, that can be remotecontrolled with the standard Nikon remote.

#define IR_LED_PIN       6   // Pin for the IR-LED      
#define STATUS_LED_PIN       13  // Pin for the Status-LED


int c = 0;                   // Counter to repeat loop

void setup() {              // Setup, initialize Ports etc
  initialize_ir(IR_LED_PIN, STATUS_LED_PIN);
}

void loop() {    // sending the IR-Code itself, repeat 2 times with 62ms delay
  digitalWrite(STATUS_LED_PIN, HIGH);
  for (cg=0; cg<=1; cg++)
  {
  delay(62); 
  ir_raw_write_high(1 << 6, 2000);
  ir_raw_write_low(1 << 6, 10000); // lowtime: 27830us, but the delayMicroseconds function is known to be precise only up to 16000 us, thats why I splittet that.
  ir_raw_write_low(1 << 6, 10000);
  ir_raw_write_low(1 << 6, 7830);
  ir_raw_write_high(1 << 6, 390);
  ir_raw_write_low(1 << 6, 1580);
  ir_raw_write_high(1 << 6, 410);
  ir_raw_write_low(1 << 6, 3580);
  ir_raw_write_high(1 << 6, 400);
  ir_raw_write_low(1 << 6, 10);
  }
  digitalWrite(STATUS_LED_PIN, LOW);
  delay(2000); 
}

void initialize_ir(byte ir_pin, byte status_pin) {
  pinMode(status_pin, OUTPUT);
  pinMode(ir_pin, OUTPUT);
  digitalWrite(status_pin, LOW);
  digitalWrite(ir_pin, LOW);
  prepare_timer();
}


void prepare_timer() {
  TCCR1A = 0x00;
  TCCR1B = (1 << CS11) | (1 << CS10);
  TIMSK1 = 0x00;
}


void ir_raw_write_low(byte pin, unsigned int time) {
  PORTD = PORTD & ~pin; // sets pin LOW
  delayMicroseconds(time);
}

void ir_raw_write_high(byte pin, unsigned int time) {
  for(int i=0; i <= time/26; i++) {
    PORTD = PORTD | pin;
    delayMicroseconds(13);
    PORTD = PORTD & ~pin;
    delayMicroseconds(13);
  }
}

As you can see above, I used your code for releasing my camerashutter via IR with the Arduino. I just used ir_raw_write_high/low and it works like a charme. But I’d like to understand what your functions are actually doing.

void prepare_timer() {
TCCR1A = 0x00;
TCCR1B = (1 << CS11) | (1 << CS10);
TIMSK1 = 0x00;
}

You commented on it, but I still dont understand. Do you have a reference, where I can read, what TCCR1A and TIMSK1 are and how they work? I couldnt find anything.

And:
void ir_raw_write_low(byte pin, unsigned int time) {
PORTD = PORTD & ~pin; // sets pin LOW
delayMicroseconds(time);

Same Question :slight_smile:

THX!

Do you have a reference, where I can read, what TCCR1A and TIMSK1 are and how they work?

I actually had a hard time finding documentation on the timers too. I resorted to digging through the datasheet, which wasn't as bad as it sounds. I also found a pretty helpful overview of timers at the avrfreaks website.

And: void ir_raw_write_low(byte pin, unsigned int time) { PORTD = PORTD & ~pin; // sets pin LOW delayMicroseconds(time);

Same Question :)

Documentation for the PORTD stuff can be found Here. Documentation for the bit manipulation part of the code can be found Here or in the extended language reference

Hope that helps! :)

I actually had a hard time finding documentation on the timers too.

This article might be helpful for Arduino timer/interrupt information also.

--Phil.

Thx guys. I now got some time, worked through the links and understood it. Great stuff. The Scanner I wanted to realize with this is working. Some Hardware is missing. If I got that working, I'll post it here and maybe somewhere else, too.

I look forward to see what you come up with!