
Digispark是一个基于ATTINY85微控制器且具備USB接口的开发板,使用Arduino IDE开发,编程与Arduino极相似。这里介绍如何利用家里的红外遥控器配合Digispark遥控设备。
事前准备
- Digispark(你也可以自制Digispark)
- Sharp GP1UX51QS 或其它兼容38KHz红外接收器
- 1个47欧姆电阻器
- 1个47uF电容器(1uF到100uF应该没问题)
- 红外遥控器
Sharp GP1UX511QS是一个38KHz的红外接收器,它支持NEC码,RC-6码等。引脚如图:

一个简单的红外控制器
以下电路设计使用了一个Sharp GP1UX51QS红外接收器用于接收红外信号以便控制LED。任何按键将会触发事件从而点亮LED。
以下电路设计使用了一个Sharp GP1UX51QS红外接收器用于接收红外信号以便控制LED。任何按键将会触发事件从而点亮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); } }
红外遥控解码
如果想知道你的遥控器支持什么红外协议,那么你得使用示波器分析红外信号。然而,也可以使用Arduino或Digispark来获取红外遥控器的信息。
下面例子使用一个Arduino(不是Digispark)来读取红外脉冲,然後使用串行监视器(Serial monitor)将获取的数据显示在屏幕上。 我不熟悉红外遥控,只知道NEC协议是一个32位数据信号,所以用了32作为测试,当然你可以隨时更换BIT_PER_BLOCK来满足你的需求。
如果想知道你的遥控器支持什么红外协议,那么你得使用示波器分析红外信号。然而,也可以使用Arduino或Digispark来获取红外遥控器的信息。
下面例子使用一个Arduino(不是Digispark)来读取红外脉冲,然後使用串行监视器(Serial monitor)将获取的数据显示在屏幕上。 我不熟悉红外遥控,只知道NEC协议是一个32位数据信号,所以用了32作为测试,当然你可以隨时更换BIT_PER_BLOCK来满足你的需求。

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("========="); }
你也可以使用Digispark来获取红外信息,然後把处理了的信息形成模拟键盘发送数据至电脑,同时打开文本编辑器(如Windows Notepad)来查看数据,但是此方式的显示速度要比使用串行监视慢许多。

#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("========="); }
以下是我的红外数据採样
提示:你可以快速按下遥控器的按钮以防止显示许多0

以上报表说明4000以上的值是属于起始位(只有一个值高于4000),1000以下是低脉冲(0),1000以上则是高脉冲(1)。 如果你的结果只有低脉冲(所有数值低于1000),那么你必须更换pulseIn(irPin, HIGH)至pulseIn(irPin, LOW)。
获取起始位值后(Start bit),加入while(pulseIn(irPin, HIGH) < start_bit); 代码,此代码的作用是按键後才运行余下的代码(指令)。 这里使用了2200作为始位值。
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("========="); }
以下是完整的数据。与NEC协议比较,这个遥控器符合NEC IR协议。


再比较他其红外协议
上传同一个代码(Sketch),然後使用另一个遥控器获取红外信息。此时得到的数据不能反映任何红外协议。
上传同一个代码(Sketch),然後使用另一个遥控器获取红外信息。此时得到的数据不能反映任何红外协议。

更改 data[i] = pulseIn(irPin, HIGH) 至 data[i] = pulseIn(irPin, LOW) ,得到数据如下:

以上报表说明高于2000的值是起始位(Start bit),低于500是低脉冲(0),高于800则是高脉(1),另外从第15行到第18行的报表数据,应该是属于指令数据(command data)。再次声明,本人不熟悉红外, 所以不不晓得这是属于什么红外协议。不过已经拥有足够的资料用于设计红外控制器。
修改从Arduino论坛的代码(getIRKey) ,研制了以下代码(Sketch)用于检测NEC红外协议。其中按键值将会转换成整数(Binary to Decimal)便于编程。
#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 }
研制了下面代码,用来遥控电脑,也用来点唱karaoke。 更多信息关于键盘扫描码(Keyboard scan code),请参阅此PDF文件 。
#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路红外遥控
使用相同的红外遥控器来控制4个LED,按下各自按键将会切换各自相关LED。完成代码(Sketch)上载后 ,你可以除去1.5K电阻,两个68ohm电阻和两个Zener二极管。
有句广东话:打完齊唔要和尚
有句广东话:打完齊唔要和尚

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
电子与电脑
Tagged under