The good news is that it is very easy to hook up this sensor. Just connect the output to a digital pin. The bad news is that the Arduino's friendly digitalRead() procedure is a tad too slow to reliably read the fast signal as its coming in. Thus we use the hardware pin reading function directly from pin D2, that's what the line "IRpin_PIN & BV(IRpin))" does. This trick is specific to ATmega328 based boards such as Arduino Uno, Adafruit Metro, etc.

Angled shot of a Adafruit METRO 328 Fully Assembled
We sure love the ATmega328 here at Adafruit, and we use them a lot for our own projects. The processor has plenty of GPIO, Analog inputs, hardware UART SPI and I2C,...
Out of Stock
// SPDX-FileCopyrightText: Limor Fried for Adafruit Industries
// SPDX-License-Identifier: MIT

/* Raw IR decoder sketch!
 This sketch/program uses the Arduno and a PNA4602 to 
 decode IR received. This can be used to make a IR receiver
 (by looking for a particular code)
 or transmitter (by pulsing an IR LED at ~38KHz for the
 durations detected 
 Check out and for more tutorials! 
// We need to use the 'raw' pin reading methods
// because timing is very important here and the digitalRead()
// procedure is slower!
//uint8_t IRpin = 2;
// Digital pin #2 is the same as Pin D2 see
// for the 'raw' pin mapping
#define IRpin_PIN      PIND
#define IRpin          2
// the maximum pulse we'll listen for - 65 milliseconds is a long time
#define MAXPULSE 65000
// what our timing resolution should be, larger is better
// as its more 'precise' - but too large and you wont get
// accurate timing
#define RESOLUTION 20 
// we will store up to 100 pulse pairs (this is -a lot-)
uint16_t pulses[100][2];  // pair is high and low pulse 
uint8_t currentpulse = 0; // index for pulses we're storing
void setup(void) {
  Serial.println("Ready to decode IR!");
void loop(void) {
  uint16_t highpulse, lowpulse;  // temporary storage timing
  highpulse = lowpulse = 0; // start out with no pulse length
//  while (digitalRead(IRpin)) { // this is too slow!
    while (IRpin_PIN & (1 << IRpin)) {
     // pin is still HIGH
     // count off another few microseconds
     // If the pulse is too long, we 'timed out' - either nothing
     // was received or the code is finished, so print what
     // we've grabbed so far, and then reset
     if ((highpulse >= MAXPULSE) && (currentpulse != 0)) {
  // we didn't time out so lets stash the reading
  pulses[currentpulse][0] = highpulse;
  // same as above
  while (! (IRpin_PIN & _BV(IRpin))) {
     // pin is still LOW
     if ((lowpulse >= MAXPULSE)  && (currentpulse != 0)) {
  pulses[currentpulse][1] = lowpulse;
  // we read one high-low pulse successfully, continue!
void printpulses(void) {
  Serial.println("\n\r\n\rReceived: \n\rOFF \tON");
  for (uint8_t i = 0; i < currentpulse; i++) {
    Serial.print(pulses[i][0] * RESOLUTION, DEC);
    Serial.print(" usec, ");
    Serial.print(pulses[i][1] * RESOLUTION, DEC);
    Serial.println(" usec");
  // print it in a 'array' format
  Serial.println("int IRsignal[] = {");
  Serial.println("// ON, OFF ");
  for (uint8_t i = 0; i < currentpulse-1; i++) {
    //Serial.print("\t"); // tab
    Serial.print(pulses[i][1] * RESOLUTION , DEC);
    Serial.print(pulses[i+1][0] * RESOLUTION , DEC);
  //Serial.print("\t"); // tab
  Serial.print(pulses[currentpulse-1][1] * RESOLUTION, DEC);
If you run this while pointing a Sony IR remote and pressing the ON button you will get the following...
If you ignore the first OFF pulse (its just the time from when the Arduino turned on to the first IR signal received) and the last ON pulse (it the beginning of the next code) you'll find the Sony power code:
2.5 ms 0.6 ms
1.2 ms 0.6 ms
0.6 ms 0.6 ms
1.2 ms 0.6 ms
0.6 ms 0.6 ms
1.2 ms 0.6 ms
0.6 ms 0.6 ms
0.6 ms 0.6 ms
1.2 ms 0.6 ms
0.6 ms 0.6 ms
0.6 ms 0.6 ms
0.6 ms 0.6 ms
0.6 ms 27.2 ms

This guide was first published on Jul 29, 2012. It was last updated on Jun 28, 2012.

This page (Using an IR Sensor) was last updated on Jun 28, 2012.

Text editor powered by tinymce.