Wednesday, 29 May 2013 18:41

Digispark Infrared Receiver

Digispark Infrared Receiver
Digispark is an Attiny85 based microcontroller development board similar to the Arduino line which is smaller and cheaper. Now you can connect an infrared detector to the Digispark and turn it to an infrared controller to control your devices.
 
Digispark is copyrighted by Digistump LLC (digistump.com) and the full license is here
 
 
 
Prerequisite
  • Digispark (You can build your own Digispark)
  • Sharp GP1UX51QS or other 38KHz compatible Infrared receiver
  • 1 x 47 ohm resistor
  • 1 x 47uF capacitor (1uF to 100uF shoud work)
  • Infrared remote control
Sharp GP1UX511QS is a 38KHz infrared detector which support NEC code, RC-6 code etc. Connection diagram as below:
Sharp GP1UX51QS IR detector connection diagram
 
 
Build a simple ON/OFF infrared controller
Below is a infrared circuit which the infrared detector is connect to the digital 2 of Digispark, the circuit will not analyze the IR signal, pressing any button from the remote control will turn on the LED.
Schematic for Digispark infrared controller
 
 Breadboard for Digispark infrared controller
 
  1. int irPin=2; //digital 2 (ATTINT85 pin 7)
  2. int ledPin=0; //digital 0 (ATTINY85 pin 5)
  3.  
  4. void setup()
  5. {
  6. pinMode(irPin,INPUT);
  7. pinMode(ledPin,OUTPUT);
  8. digitalWrite(0,HIGH);
  9. }
  10.  
  11. void loop()
  12. {
  13. if(pulseIn(irPin,LOW)) //reads a pulse on a pin
  14. {
  15. //button pressed
  16. delay(100);
  17. digitalWrite(ledPin,HIGH);
  18. delay(1000);
  19. digitalWrite(ledPin,LOW);
  20. }
  21. }
  22.  
 
 
Decode an Infrared Remote
If you had no idea what is the infrared protocol that your remote control will support, then you need an oscilloscope to analyse the signals format. However you can use an Arduino or Digispark to capture the signals from an IR remote control.
 
Sketch below shows an IR detector connect to the digital 2 of an Arduino (not Digispark), it  read the pulse from the IR detector and you can use the serial monitor to capture the result. I don't know much about infrared, I only know NEC protocol is a 32 bits data block signal, you may want to change BIT_PER_BLOCK to a higher value to suit your needs.
Arduino infrared receiver
 
  1. int irPin = 2; //IR detector connected to digital 2
  2. const byte BIT_PER_BLOCK = 32;
  3.  
  4. void setup() {
  5. pinMode(irPin, INPUT);
  6. Serial.begin(9600);
  7. }
  8. void loop() {
  9. int data[BIT_PER_BLOCK];
  10. int i;
  11.  
  12. for(i = 0 ; i < BIT_PER_BLOCK ; i++) {
  13. //Start measuring bits, I only want high pulses
  14. //you may want to use LOW pulse --> pulseIn(irPin, LOW)
  15. data[i] = pulseIn(irPin, HIGH);
  16. }
  17.  
  18. delay(100);
  19. for(i = 0 ; i < BIT_PER_BLOCK ; i++) {
  20. Serial.println(data[i]);
  21. }
  22. Serial.println("=========");
  23. }
 
Of course you can use a Digispark to capture the IR signal, it sending the data as keyboard keystrokes using the keyboard emulation, you can use any text editor such as Windows Notepad to view the result, however the result appear on the screen is much more slower than using serial port .
Digispark Infrared receiver
 
  1. #include "DigiKeyboard.h"
  2. int irPin = 2; //IR receiver wired to digital 2 (ATTINY pin7)
  3. const byte BIT_PER_BLOCK = 32;
  4. void setup() {
  5. pinMode(irPin, INPUT);
  6. Serial.begin(9600);
  7. }
  8. void loop() {
  9. int data[BIT_PER_BLOCK];
  10. int i;
  11.  
  12. // this is generally not necessary but with some older systems it seems to
  13. // prevent missing the first character after a delay:
  14. DigiKeyboard.sendKeyStroke(0);
  15.  
  16. for(i = 0 ; i < BIT_PER_BLOCK ; i++) {
  17. //Start measuring bits, I only want high pulses
  18. //you may want to use LOW pulse --> pulseIn(irPin, LOW)
  19. data[i] = pulseIn(irPin, HIGH);
  20. }
  21.  
  22. delay(100);
  23. for(i = 0 ; i < BIT_PER_BLOCK ; i++) {
  24. DigiKeyboard.println(data[i]);
  25. }
  26. DigiKeyboard.println("=========");
  27. }
 
Some infrared samples for my IR remote control.
Tips: You can eliminate 0 showing in the result by pressing the remote button very fast.
Infrared sample data 
Result above shows that there is only one value above 4000 that is the start bit, value below 1000 is a LOW pulse and value above 1000 is a HIGH pulse. If your result shows only LOW pulses (all values below 1000), then you shoud change pulseIn(irPin, HIGH) to pulseIn(irPin, LOW)
 
After getting the value of start bit, add while(pulseIn(irPin, HIGH) < start_bit); to your sketch, it wait for a key press before proceed to the rest of code (command). Here using 2200 as the value for start_bit which is above the value of HIGH pulse.
  1. int irPin = 2; //IR detector connected to digital 2
  2. const byte BIT_PER_BLOCK = 32;
  3. int start_bit = 2200; //start bit threshold (microseconds)
  4.  
  5. void setup() {
  6. pinMode(irPin, INPUT);
  7. Serial.begin(9600);
  8. }
  9. void loop() {
  10. int data[BIT_PER_BLOCK];
  11. int i;
  12.  
  13. while(pulseIn(irPin, HIGH) < start_bit); //wait for a start bit
  14.  
  15. for(i = 0 ; i < BIT_PER_BLOCK ; i++) {
  16. //Start measuring bits, I only want high pulses
  17. //you may want to use LOW pulse --> pulseIn(irPin, LOW)
  18. data[i] = pulseIn(irPin, HIGH);
  19. }
  20.  
  21. for(i = 0 ; i < BIT_PER_BLOCK ; i++) {
  22. Serial.println(data[i]);
  23. }
  24. Serial.println("=========");
  25. }
 
Here is the final result. By comparing the result to NEC message frame, this remote control is compliant to NEC IR protocol.
Infrared sample data Final
 
NEC Message Frame
 
 

 

Play with other infrared protocol
Upload same sketch as above to capture infrared signal from another remote control. I'm getting the following result which does not reflect any infrared protocol.
Sample data
 
by changing data[i] = pulseIn(irPin, HIGH) to data[i] = pulseIn(irPin, LOW), I'm getting the following results:
Sample data
It shows that the start bit is above 2000, LOW pulse below 500, HIGH pulse above 800, and the command data would start from row 15 to row 18. I have no idea what IR protocol is, but there is enough information to build your own infrared controller.
 

 

By modified the code (getIRKey) from Arduino forum, I came out my own sketch which detect the NEC infrared protocol, the value of button press is converted to integer for easy coding.
#include "DigiKeyboard.h"
int irPin = 2; //Sensor pin connect to digital pin2 (ATINY85 pin7)
int start_bit = 2200; //Start bit threshold (Microseconds)
int bin_1 = 1000; //Binary 1 threshold (Microseconds)
int bin_0 = 400; //Binary 0 threshold (Microseconds)
const byte BIT_PER_BLOCK = 32;
 
void setup() {
  pinMode(irPin, INPUT);
}
 
void loop() {
  DigiKeyboard.update(); //keep on updating the keyboard 
  // this is generally not necessary but with some older systems it seems to
  // prevent missing the first character after a delay:
  DigiKeyboard.sendKeyStroke(0);
 
  int key = getIRKey();        //Fetch the key
 
  if(key != 0) //Ignore keys that are zero
  {
    DigiKeyboard.print("=>");  //uncomment this if you want to 
    DigiKeyboard.println(key); //print out the value of the button
  }
}
 
/////////////////////////////////////////////////////////////
// decode infrared signal
/////////////////////////////////////////////////////////////
int getIRKey() {
  int data[BIT_PER_BLOCK];
  int i;
  while(pulseIn(irPin, HIGH) < start_bit); //Wait for a start bit
 
  for(i = 0 ; i < BIT_PER_BLOCK ; i++) 
    data[i] = pulseIn(irPin, HIGH); //Start measuring bits, I only want HIGH pulses
 
  delay(100);  
  for(i = 0 ; i < BIT_PER_BLOCK ; i++) //Parse them
  {   
    if(data[i] > bin_1) //is it a 1?
      data[i] = 1;
    else if(data[i] > bin_0) //is it a 0?
      data[i] = 0;
    else
      return -1; //Flag the data as invalid; Return -1 on invalid data
  }
  //based on NEC protocol, command data started from bit 16
  //and end with bit 24 (8 bits long)
  int result = 0;
  for(i = 16 ; i < 24; i++) { 
    DigiKeyboard.print(data[i]); //print out the value of button in binary form
    if(data[i] == 1) result |= (1<<i-16); //Convert data bits to integer
  }  
  return result; //Return key number
}
 
This would be the final sketch. I use this to control my computer. Please refer to this PDF for more about keyboard scan code.
#include "DigiKeyboard.h"
// not all keys are mapped in the DigiKeyboard.h file.
// you have to map it here
#define KEY_HOME   0x4A
#define KEY_PAGE_UP   0x4B
#define KEY_PAGE_DOWN   0x4E
#define KEY_ESCAPE   0x29
#define KEY_UP_ARROW   0x52
#define KEY_DOWN_ARROW   0x51
#define KEY_LEFT_ARROW   0x50
#define KEY_RIGHT_ARROW   0x4F
 
int irPin = 2; //Sensor pin connect to digital pin2 (ATINY85 pin7)
int start_bit = 2200; //Start bit threshold (Microseconds)
int bin_1 = 1000; //Binary 1 threshold (Microseconds)
int bin_0 = 400; //Binary 0 threshold (Microseconds)
const byte BIT_PER_BLOCK = 32;
 
void setup() {
  pinMode(irPin, INPUT);
}
 
void loop() {
  DigiKeyboard.update(); // keep updating the keyboard
  // this is generally not necessary but with some older systems it seems to
  // prevent missing the first character after a delay:
  DigiKeyboard.sendKeyStroke(0);
 
  int key = getIRKey();        //Fetch the key
 
  if(key != 0) //Ignore keys that are zero
  {
    //DigiKeyboard.print("=>");  //uncomment this if you want to 
    //DigiKeyboard.println(key); //print out the value of the button
 
    switch(key)
    {
      case 78: DigiKeyboard.println("1"); break;
      case 74: DigiKeyboard.println("2"); break;
      case 70: DigiKeyboard.println("3"); break;
      case 77: DigiKeyboard.println("4"); break;
      case 73: DigiKeyboard.println("5"); break;
      case 69: DigiKeyboard.println("6"); break;
      case 76: DigiKeyboard.println("7"); break;
      case 72: DigiKeyboard.println("8"); break;
      case 68: DigiKeyboard.println("9"); break;    
      case 12: DigiKeyboard.println("0"); break;
      case 15: DigiKeyboard.sendKeyStroke(KEY_SPACE); break;
      case  6: DigiKeyboard.sendKeyStroke(KEY_ENTER); break;    
      case  4: DigiKeyboard.sendKeyStroke(KEY_ESCAPE); break; 
      case 81: DigiKeyboard.sendKeyStroke(KEY_HOME); break; 
      case 14: DigiKeyboard.sendKeyStroke(KEY_LEFT_ARROW); break; 
      case 10: DigiKeyboard.sendKeyStroke(KEY_RIGHT_ARROW); break;
      case 11: DigiKeyboard.sendKeyStroke(KEY_DOWN_ARROW); break;  
      case  7: DigiKeyboard.sendKeyStroke(KEY_UP_ARROW); break;    
    }    
  }
}
 
/////////////////////////////////////////////////////////////
// decode infrared signal
/////////////////////////////////////////////////////////////
int getIRKey() {
  int data[BIT_PER_BLOCK];
  int i;
  while(pulseIn(irPin, HIGH) < start_bit); //Wait for a start bit
 
  for(i = 0 ; i < BIT_PER_BLOCK ; i++) 
    data[i] = pulseIn(irPin, HIGH); //Start measuring bits, I only want HIGH pulses
 
  delay(100);  
  for(i = 0 ; i < BIT_PER_BLOCK ; i++) //Parse them
  {   
    if(data[i] > bin_1) //is it a 1?
      data[i] = 1;
    else if(data[i] > bin_0) //is it a 0?
      data[i] = 0;
    else
      return -1; //Flag the data as invalid; Return -1 on invalid data
  }
 
  //based on NEC protocol, command data started from bit 16
  //and end with bit 24 (8 bits long)
  int result = 0;
  for(i = 16 ; i < 24; i++) { 
    //DigiKeyboard.print(data[i]); //print out the value of button in binary form
    if(data[i] == 1) result |= (1<<i-16); //Convert data bits to integer
  }  
  return result; //Return key number
}
 
 
4 Channel Infrared Remote Control
Use the same infrared remote control to control 4 LED, it toggle the LED on and off each time pressing a button from the remote control. You can remove the 1.5K resistor, two 68ohm resistors,  and two zener diode from the circuit after the sketch had been upload to Digispark.
Schematic for 4 channel remote control
 
  1. int irPin = 2; //Sensor pin connect to digital pin2 (ATINY85 pin7)
  2. int led1 = 0; //led connect to digital pin0 (ATTINY85 pin5)
  3. int led2 = 1; //led connect to digital pin1 (ATTINY85 pin6)
  4. int led3 = 3; //led connect to digital pin3 (ATTINY85 pin2)
  5. int led4 = 4; //led connect to digital pin4 (ATTINY85 pin3)
  6. int start_bit = 2200; //Start bit threshold (Microseconds)
  7. int bin_1 = 1000; //Binary 1 threshold (Microseconds)
  8. int bin_0 = 400; //Binary 0 threshold (Microseconds)
  9. const byte BIT_PER_BLOCK = 32;
  10.  
  11. void setup() {
  12. pinMode(irPin, INPUT);
  13. pinMode(led1, OUTPUT);
  14. pinMode(led2, OUTPUT);
  15. pinMode(led3, OUTPUT);
  16. pinMode(led4, OUTPUT);
  17. digitalWrite(led1, LOW); //turn off LED
  18. digitalWrite(led2, LOW);
  19. digitalWrite(led3, LOW);
  20. digitalWrite(led4, LOW);
  21. }
  22.  
  23. void loop() {
  24. int key = getIRKey(); //Fetch the key
  25.  
  26. if(key != 0) //Ignore keys that are zero
  27. {
  28. switch(key)
  29. {
  30. case 78: toggleLED(led1); break;
  31. case 74: toggleLED(led2); break;
  32. case 70: toggleLED(led3); break;
  33. case 77: toggleLED(led4); break;
  34. }
  35. }
  36. }
  37.  
  38. /////////////////////////////////////////////////////////////
  39. // toggle led
  40. /////////////////////////////////////////////////////////////
  41. void toggleLED(byte ledPin) {
  42. if(digitalRead(ledPin) != 1) //This toggles the led
  43. digitalWrite(ledPin, HIGH);
  44. else
  45. digitalWrite(ledPin, LOW);
  46. }
  47. /////////////////////////////////////////////////////////////
  48. // decode infrared signal
  49. /////////////////////////////////////////////////////////////
  50. int getIRKey() {
  51. int data[BIT_PER_BLOCK];
  52. int i;
  53. while(pulseIn(irPin, HIGH) < start_bit); //Wait for a start bit
  54.  
  55. for(i = 0 ; i < BIT_PER_BLOCK ; i++)
  56. data[i] = pulseIn(irPin, HIGH); //Start measuring bits, I only want HIGH pulses
  57.  
  58. delay(100);
  59. for(i = 0 ; i < BIT_PER_BLOCK ; i++) //Parse them
  60. {
  61. if(data[i] > bin_1) //is it a 1?
  62. data[i] = 1;
  63. else if(data[i] > bin_0) //is it a 0?
  64. data[i] = 0;
  65. else
  66. return -1; //Flag the data as invalid; Return -1 on invalid data
  67. }
  68.  
  69. //based on NEC protocol, command data started from bit 16
  70. //and end with bit 24 (8 bits long)
  71. int result = 0;
  72. for(i = 16 ; i < 24; i++) {
  73. if(data[i] == 1) result |= (1<<i-16); //Convert data bits to integer
  74. }
  75. return result; //Return key number
  76. }
 
 
Read 17859 times Last modified on Saturday, 09 July 2016 17:57

1 comment

  • Comment Link Oskar Monday, 26 December 2016 05:46 posted by Oskar

    This is fantastic I'm brand new to arduino and micro controllers in general and this helped me immensely. Thank you!

Leave a comment

Back to Top