Default Remote


Arduino code to go with the default original remote of the IR Remote Creator App.

IR Remote


The default remote has 23 buttons, all of which have been set to use the NEC InfraRed protocol.

Color Changing LED Remote
Default Remote

If you have deleted the remote from the app, you can get it again in one of these ways:

1) If you are accessing this page from a device with the app installed, then tap here to load it into the App.

2) Alternatively download default.txt into the keuwlsoft/ir-remotes/ directory on your Android device, and then load it from within the app.

3) Alternatively, in the load from web link option within the app, enter: http://www.keuwl.com/ir-remotes/default.txt

4) In the App settings, Reset defaults with the restore original remotes option checked (although this method will delete any other remotes currently loaded into the app).


NEC Protocol


This is a popular InfraRed protocol that has some nice built in error checking. It uses pulse distance modulation on a carrier wave that is typically 38 kHz. The distance between pulses is used to differentiate a 0 or 1.

Pulse Distance Modulation
Pulse Distance Modulation

The IR pattern comprises a header pulse, 32 bits of information, and then a stop or end bit. The 32 bits of data are split into an address and a command.

The address decides the target device of the IR transmission whilst the command determines the function on that device.

Both the command and address are sent twice, first as it is, and then as a one's compliment (i.e. inverted) version. For example if the address is 01100111, then the inverted address, address' is 10011000. If the transmitted data hasn't been corrupted, then the logical bitwise AND of the address and address' will yield zero. Likewise for the bitwise AND of command and command'.

For all buttons, the address being used for this demo project is zero. If changing the address of the sent data, make sure the Arduino code is adjusted to match. For example, If you have multiple IR projects, you can assign them different addresses so that the signal is only received by the one that should receive it.

For the buttons, we have used command numbers 0 to 22 (0x00 to 0x16 hex). Thus the code table for the remote is:

Button Address  Command 
00x000x00
10x000x01
20x000x02
30x000x03
40x000x04
50x000x05
60x000x06
70x000x07
80x000x08
90x000x09
On/Off0x000x0A
Up Triangle0x000x0B
 Down Triangle 0x000x0C
Rewind0x000x0D
Pause0x000x0E
Stop0x000x0F
Play0x000x10
Forward0x000x11
Up0x000x12
Down0x000x13
Left0x000x14
Right0x000x15
Ok0x000x16
Table of Assigned IR Codes for the Remote

There is nothing special about this choice of command numbers. Change them if required and update the Arduino code to match.


IR Receiver Module


This project used a VS1838B InfraRed Receiver Module. There are a range of IR receiver modules available, the main difference being in the carrier frequency. 38 kHz is by far the most popular frequency for IR remotes, but you will also find 30 kHz, 33 kHz, 36 kHz 40 kHz, 56 kHz and others available. Unless you need a specific frequency to match a particular remote/device, 38 kHz is probably going to be the cheapest and best option. There is some overlap in frequency capability. i.e. expect a 38 kHz receiver to also be able to pick up a 36 kHz signal (for example), but weaker and at a closer range.

Check the datasheet of your IR receiver module so that you connect you device correctly (otherwise it might heat up and burn out and then not work anymore). The IR receivers generally will have three connections: Ground, +V and a Output. Note that the output could be inverted to what you think it is going to be. Checking the data sheet that the IR receiver uses a suitable voltage for your Arduino to supply is probably a good idea too.

The IR receiver packages do all the necessary amplification & demodulation and just output any IR pattern they receive as a digital signal which we will read with the Arduino.

Some IR Receiver Modules
Some IR Receiver Modules (TSOP4838, TSOP31256 and VS1838B).


Components used


  • Arduino Uno
  • VS1838B InfraRed Receiver Module

Circuit Diagram


Connect the InfraRed Receiver Module to the Arduino as in the circuit diagram below. The output of the receiver module needs to go to pin 2 or 3 of the Arduino as we can enable external interrupts for those pins.

circuit diagram


Whilst we are using an Arduino Uno for this demo, you could use a different model if you prefer, just make sure the ir receiver module output is to an external interrupt pin.

The VS1838B InfraRed Receiver Module has 3 connections, GND, 5V, and OUT. For other Receiver Modules, see datasheet to get the correct connections etc.


Arduino code


Open the Arduino software, select the correct COM Port and Arduino device in the Tools menu, copy and paste the sketch below and click upload.

Of note in this sketch is the way it handles the incomming IR pattern data. Rather than tieing up the main loop with PulseIn() commands and constantly monitoring the IR signal, we have used interrupts instead. This leaves the main loop free to carry out other important tasks.

The interrupt is called every time the external interrupt pin changes state. It logs the elapsed micros() time of the Arduino, and then resumes from where it was before. Once IR pattern data has been collected and a pause is observed at the end of the pattern, it's analysis is done in the main loop.

Once new IR command has been received, a switch-case is used to run code for that command. Except, this is just the template, so commands wont do anything unless you add some code.


// Code template for default remote in keuwlsoft's IR remote Creator App
// By keuwlsoft:  www.keuwl.com  24th Feb 2019
// cc Attribution-ShareAlike
//
// This sketch will receive an IR Pattern, Decode the Address and Command (NEC Protocol).
// Then if data valid and address matches, will use a switch case to action the command. 
// Does nothing, unless code is added to the switch-case for the buttons you want to use. 
// An Interrupt is used to gather the IR Pattern timing, which is later analysed, thus keeping the main loop free for other tasks.
// The Remote and explanation can be found at www.keuwl.com/electronics/rduino/ir/03-default-remote/

int ir_pin=2; //use pins 2 or 3 for external interupts, connect the IR receiver module output here.

long no_change_time=10000; //No change in IR pin for this duration (microseconds) will mark the end of pattern.
const int array_size=100; //Max times to log.  If array is full, it will report the pattern to that point. 
long t_array[array_size]; //Array of times of when the IR pin changes state.
int count=0; // Number of times logged to array.
boolean log_micros=true;  //Flag to indicate if able to log times to array
long last_micros=0; //previous array time entry

int addr=0; //Device address decoded from IR pattern
int cmmd=0; //Command decoded from IR pattern
int our_device_addr=0; //integer (0-255) that is an address to identify our device amoungst other devices.
boolean new_data=false; //Flag that is set everytime a new IR command is received


void setup() {
  pinMode(ir_pin, INPUT);

  //attach an interupt to log when the IR pin changes state
  attachInterrupt(digitalPinToInterrupt(ir_pin),interupt,CHANGE);
}

void loop() {
  
//=========================================== Extract IR Command
  if (count>0){
    if (!log_micros|((micros()-last_micros)>no_change_time)){
      log_micros=false; //make sure array not modified while we analyse it
      //Get Pattern  
      count--;
      for (int i=0;i<count;i++){
        t_array[i]=t_array[i+1]-t_array[i];
      }
      //Extract Command And Address of NEC protocol
      if (count>=64){ //Check patten long enough for 32 bits of data
        int pos=count;
        // Extract Command Compliment
        int cmmd2=0x00;
        for (int i=0;i<8;i++){
          cmmd2=cmmd2<<1; pos-=2;
           if (t_array[pos]>1000)cmmd2=cmmd2|1;
        }
        // Extract Command 
        cmmd=0x00;
        for (int i=0;i<8;i++){
          cmmd=cmmd<<1; pos-=2;
          if (t_array[pos]>1000)cmmd=cmmd|1;
        }
        //Extract Address Complement
        int addr2=0x00;
        for (int i=0;i<8;i++){
          addr2=addr2<<1; pos-=2;
          if (t_array[pos]>1000)addr2=addr2|1;
        }
        //Extract Address
        addr=0x00;
        for (int i=0;i<8;i++){
          addr=addr<<1; pos-=2;
          if (t_array[pos]>1000)addr=addr|1;
        }
    
        //check if data was for our device and is valid
        if ((addr2&addr)==0&&(addr2&addr)==0){
          if (addr==our_device_addr) new_data=true;
        }
      }  
  
    log_micros=true; count=0; //Reset array so another IR pattern can be received
    }
  }
//===========================================


//=========== Do Something with the Newly Received Command
  if (new_data){
    switch(cmmd){
      case 0: 
        //<-- Insert Code for button '0' press here 
      break;
      case 1:
        //<-- Insert Code for button '1' press here 
      break;
      case 2:
        //<-- Insert Code for button '2' press here 
      break;
      case 3:
        //<-- Insert Code for button '3' press here 
      break;
      case 4:
        //<-- Insert Code for button '4' press here 
      break;
      case 5:
        //<-- Insert Code for button '5' press here 
      break;
      case 6:
        //<-- Insert Code for button '6' press here 
      break;
      case 7:
        //<-- Insert Code for button '7' press here 
      break;
      case 8:
        //<-- Insert Code for button '8' press here 
      break;
      case 9:
        //<-- Insert Code for button '9' press here 
      break;
      case 10:
        //<-- Insert Code for On/Off button press here 
      break;
      case 11:
        //<-- Insert Code for up triangle button press here 
      break;
      case 12:
        //<-- Insert Code for down triangle button press here 
      break;
      case 13:
        //<-- Insert Code for Rewind button press here 
      break;
      case 14:
        //<-- Insert Code for Pause button press here 
      break;
      case 15:
        //<-- Insert Code for Stop button press here 
      break;
      case 16:
        //<-- Insert Code for Play button press here 
      break;
      case 17:
        //<-- Insert Code for Forward button press here 
      break;
      case 18:
        //<-- Insert Code for Up button press here 
      break;
      case 19:
        //<-- Insert Code for Down button press here 
      break;
      case 20:
        //<-- Insert Code for Left button press here 
      break;
      case 21:
        //<-- Insert Code for Right button press here 
      break;
      case 22:
        //<-- Insert Code for Ok button press here 
      break;
      
      default:
      break;
    }
    new_data=false;
  }
//===========

  
  delay(10); 
}

  
//========================================================
// Interupt to log each time the IR signal changes state 
void interupt(){
  if (log_micros){
    long m=micros();
    if (count>0&&(m-last_micros)>no_change_time){
      log_micros=false;
    }else{
       t_array[count]=m;
       count++;
       last_micros=m;
       if (count>=array_size) log_micros=false;
     }
  }
}
//========================================================