Wednesday, 29 May 2013 18:41
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.
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:

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.
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.


int irPin=2; //digital 2 (ATTINT85 pin 7) int ledPin=0; //digital 0 (ATTINY85 pin 5) void setup() { pinMode(irPin,INPUT); pinMode(ledPin,OUTPUT); digitalWrite(0,HIGH); } void loop() { if(pulseIn(irPin,LOW)) //reads a pulse on a pin { //button pressed delay(100); digitalWrite(ledPin,HIGH); delay(1000); digitalWrite(ledPin,LOW); } }
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.

int irPin = 2; //IR detector connected to digital 2 const byte BIT_PER_BLOCK = 32; void setup() { pinMode(irPin, INPUT); Serial.begin(9600); } void loop() { int data[BIT_PER_BLOCK]; int i; for(i = 0 ; i < BIT_PER_BLOCK ; i++) { //Start measuring bits, I only want high pulses //you may want to use LOW pulse --> pulseIn(irPin, LOW) data[i] = pulseIn(irPin, HIGH); } delay(100); for(i = 0 ; i < BIT_PER_BLOCK ; i++) { Serial.println(data[i]); } Serial.println("========="); }
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 .

#include "DigiKeyboard.h" int irPin = 2; //IR receiver wired to digital 2 (ATTINY pin7) const byte BIT_PER_BLOCK = 32; void setup() { pinMode(irPin, INPUT); Serial.begin(9600); } void loop() { int data[BIT_PER_BLOCK]; int i; // this is generally not necessary but with some older systems it seems to // prevent missing the first character after a delay: DigiKeyboard.sendKeyStroke(0); for(i = 0 ; i < BIT_PER_BLOCK ; i++) { //Start measuring bits, I only want high pulses //you may want to use LOW pulse --> pulseIn(irPin, LOW) data[i] = pulseIn(irPin, HIGH); } delay(100); for(i = 0 ; i < BIT_PER_BLOCK ; i++) { DigiKeyboard.println(data[i]); } DigiKeyboard.println("========="); }
Some infrared samples for my IR remote control.
Tips: You can eliminate 0 showing in the result by pressing the remote button very fast.

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.
int irPin = 2; //IR detector connected to digital 2 const byte BIT_PER_BLOCK = 32; int start_bit = 2200; //start bit threshold (microseconds) void setup() { pinMode(irPin, INPUT); Serial.begin(9600); } void loop() { 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++) { //Start measuring bits, I only want high pulses //you may want to use LOW pulse --> pulseIn(irPin, LOW) data[i] = pulseIn(irPin, HIGH); } for(i = 0 ; i < BIT_PER_BLOCK ; i++) { Serial.println(data[i]); } Serial.println("========="); }
Here is the final result. By comparing the result to NEC message frame, this remote control is compliant to NEC IR protocol.


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.
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.

by changing data[i] = pulseIn(irPin, HIGH) to data[i] = pulseIn(irPin, LOW), I'm getting the following results:

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.

int irPin = 2; //Sensor pin connect to digital pin2 (ATINY85 pin7) int led1 = 0; //led connect to digital pin0 (ATTINY85 pin5) int led2 = 1; //led connect to digital pin1 (ATTINY85 pin6) int led3 = 3; //led connect to digital pin3 (ATTINY85 pin2) int led4 = 4; //led connect to digital pin4 (ATTINY85 pin3) 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); pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT); pinMode(led4, OUTPUT); digitalWrite(led1, LOW); //turn off LED digitalWrite(led2, LOW); digitalWrite(led3, LOW); digitalWrite(led4, LOW); } void loop() { int key = getIRKey(); //Fetch the key if(key != 0) //Ignore keys that are zero { switch(key) { case 78: toggleLED(led1); break; case 74: toggleLED(led2); break; case 70: toggleLED(led3); break; case 77: toggleLED(led4); break; } } } ///////////////////////////////////////////////////////////// // toggle led ///////////////////////////////////////////////////////////// void toggleLED(byte ledPin) { if(digitalRead(ledPin) != 1) //This toggles the led digitalWrite(ledPin, HIGH); else digitalWrite(ledPin, LOW); } ///////////////////////////////////////////////////////////// // 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++) { if(data[i] == 1) result |= (1<<i-16); //Convert data bits to integer } return result; //Return key number }
Published in
Blog
Tagged under