Saturday, 01 June 2013 11:44

Digispark红外接收器

Written by
Rate this item
(0 votes)
Digispark Infrared Receiver
Digispark是一个基于ATTINY85微控制器且具備USB接口的开发板,使用Arduino IDE开发,编程与Arduino极相似。这里介绍如何利用家里的红外遥控器配合Digispark遥控设备。
 
Digispark是Digistump LLC (digistump.com)版权所有,请使用者仔细阅读Digispark使用协议和版权声明
 
 
 
 
事前准备
  • Digispark(你也可以自制Digispark
  • Sharp GP1UX51QS 或其它兼容38KHz红外接收器
  • 1个47欧姆电阻器
  • 1个47uF电容器(1uF到100uF应该没问题)
  • 红外遥控器
Sharp GP1UX511QS是一个38KHz的红外接收器,它支持NEC码,RC-6。引脚图:
Sharp GP1UX51QS IR detector connection diagram 
 
 
一个简单的红外控制器
以下电路设计使用了一个Sharp GP1UX51QS红外接收器用于接收红外信号以便控制LED。任何按键将会触发事件从而点亮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. }
 
 
红外遥控解码
如果想知道你的遥控器支持什么红外协议,那么你得使用示波器分析红外信号。然而,也可以使用Arduino或Digispark来获取红外遥控器的信息。
 
下面例子使用一个Arduino(不是Digispark)来读取红外脉冲,然後使用串行监视器(Serial monitor)将获取的数据显示在屏幕上。 我不熟悉红外遥控,只知道NEC协议是一个32位数据信号,所以用了32作为测试,当然你可以隨时更换BIT_PER_BLOCK来满足你的需求。
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. }
 
你也可以使用Digispark来获取红外信,然後把处理了的形成模拟键盘发送数据至电脑,同时打开文本编辑器(如Windows Notepad)来查看数据,但是此方式的显示速度要比使用串行监视慢许多。
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. }
 
以下是我的红外数据採样
提示:你可以快速按下遥控器的按钮以防止显示许多0
Infrared sample data 
以上报表说明4000以上的值是属于起始位(只有一个值高于4000),1000以下是低脉冲(0),1000以上则是高脉冲(1)。 如果你的结果只有低脉冲(所有数值低于1000),那么你必须更换pulseIn(irPin, HIGH)pulseIn(irPin, LOW)

获取起始位值后(Start bit),加入while(pulseIn(irPin, HIGH) < start_bit); 代码,此的作用是按键後才运行余下的代码(指令)。 这里使用了2200作为始位值。
  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. }
 
以下是完整的数据。与NEC协议比较,这个遥控器符合NEC IR协议。
Infrared sample data Final
 
NEC Message Frame 
 
 
再比较他其红外协议
上传同一个代码(Sketch),然後使用另一个遥控器获取红外信息。此时得到的数据不能反映任何红外协议。
Sample data 
 
更改 data[i] = pulseIn(irPin, HIGH) 至 data[i] = pulseIn(irPin, LOW) ,得到数据如下:
Sample data
以上报表说明高于2000的值是起始位(Start bit),低于500是低脉冲(0),高于800则是高脉(1),另外从第15行到第18行的报表数据,应该是属于指令数据(command data)。再次声明,本人不熟悉红外, 所以不不晓得这是属于什么红外协议。不过已经拥有足够的资料用于设计红外控制器。
 
修改从Arduino论坛的代码(getIRKey) ,研制了以下代码(Sketch)用于检测NEC红外协议。其中按键值将会转换成整数(Binary to Decimal)便于编程。
  1. #include "DigiKeyboard.h"
  2. int irPin = 2; //Sensor pin connect to digital pin2 (ATINY85 pin7)
  3. int start_bit = 2200; //Start bit threshold (Microseconds)
  4. int bin_1 = 1000; //Binary 1 threshold (Microseconds)
  5. int bin_0 = 400; //Binary 0 threshold (Microseconds)
  6. const byte BIT_PER_BLOCK = 32;
  7.  
  8. void setup() {
  9. pinMode(irPin, INPUT);
  10. }
  11.  
  12. void loop() {
  13. DigiKeyboard.update(); //keep on updating the keyboard
  14. // this is generally not necessary but with some older systems it seems to
  15. // prevent missing the first character after a delay:
  16. DigiKeyboard.sendKeyStroke(0);
  17.  
  18. int key = getIRKey(); //Fetch the key
  19.  
  20. if(key != 0) //Ignore keys that are zero
  21. {
  22. DigiKeyboard.print("=>"); //uncomment this if you want to
  23. DigiKeyboard.println(key); //print out the value of the button
  24. }
  25. }
  26.  
  27. /////////////////////////////////////////////////////////////
  28. // decode infrared signal
  29. /////////////////////////////////////////////////////////////
  30. int getIRKey() {
  31. int data[BIT_PER_BLOCK];
  32. int i;
  33. while(pulseIn(irPin, HIGH) < start_bit); //Wait for a start bit
  34.  
  35. for(i = 0 ; i < BIT_PER_BLOCK ; i++)
  36. data[i] = pulseIn(irPin, HIGH); //Start measuring bits, I only want HIGH pulses
  37.  
  38. delay(100);
  39. for(i = 0 ; i < BIT_PER_BLOCK ; i++) //Parse them
  40. {
  41. if(data[i] > bin_1) //is it a 1?
  42. data[i] = 1;
  43. else if(data[i] > bin_0) //is it a 0?
  44. data[i] = 0;
  45. else
  46. return -1; //Flag the data as invalid; Return -1 on invalid data
  47. }
  48. //based on NEC protocol, command data started from bit 16
  49. //and end with bit 24 (8 bits long)
  50. int result = 0;
  51. for(i = 16 ; i < 24; i++) {
  52. DigiKeyboard.print(data[i]); //print out the value of button in binary form
  53. if(data[i] == 1) result |= (1<<i-16); //Convert data bits to integer
  54. }
  55. return result; //Return key number
  56. }
 
研制了下面代码,用来遥控电脑,也用来点唱karaoke。 更多信息关于键盘扫描码(Keyboard scan code),请参阅此PDF文件
  1. #include "DigiKeyboard.h"
  2. // not all keys are mapped in the DigiKeyboard.h file.
  3. // you have to map it here
  4. #define KEY_HOME 0x4A
  5. #define KEY_PAGE_UP 0x4B
  6. #define KEY_PAGE_DOWN 0x4E
  7. #define KEY_ESCAPE 0x29
  8. #define KEY_UP_ARROW 0x52
  9. #define KEY_DOWN_ARROW 0x51
  10. #define KEY_LEFT_ARROW 0x50
  11. #define KEY_RIGHT_ARROW 0x4F
  12.  
  13. int irPin = 2; //Sensor pin connect to digital pin2 (ATINY85 pin7)
  14. int start_bit = 2200; //Start bit threshold (Microseconds)
  15. int bin_1 = 1000; //Binary 1 threshold (Microseconds)
  16. int bin_0 = 400; //Binary 0 threshold (Microseconds)
  17. const byte BIT_PER_BLOCK = 32;
  18.  
  19. void setup() {
  20. pinMode(irPin, INPUT);
  21. }
  22.  
  23. void loop() {
  24. DigiKeyboard.update(); // keep updating the keyboard
  25. // this is generally not necessary but with some older systems it seems to
  26. // prevent missing the first character after a delay:
  27. DigiKeyboard.sendKeyStroke(0);
  28.  
  29. int key = getIRKey(); //Fetch the key
  30.  
  31. if(key != 0) //Ignore keys that are zero
  32. {
  33. //DigiKeyboard.print("=>"); //uncomment this if you want to
  34. //DigiKeyboard.println(key); //print out the value of the button
  35.  
  36. switch(key)
  37. {
  38. case 78: DigiKeyboard.println("1"); break;
  39. case 74: DigiKeyboard.println("2"); break;
  40. case 70: DigiKeyboard.println("3"); break;
  41. case 77: DigiKeyboard.println("4"); break;
  42. case 73: DigiKeyboard.println("5"); break;
  43. case 69: DigiKeyboard.println("6"); break;
  44. case 76: DigiKeyboard.println("7"); break;
  45. case 72: DigiKeyboard.println("8"); break;
  46. case 68: DigiKeyboard.println("9"); break;
  47. case 12: DigiKeyboard.println("0"); break;
  48. case 15: DigiKeyboard.sendKeyStroke(KEY_SPACE); break;
  49. case 6: DigiKeyboard.sendKeyStroke(KEY_ENTER); break;
  50. case 4: DigiKeyboard.sendKeyStroke(KEY_ESCAPE); break;
  51. case 81: DigiKeyboard.sendKeyStroke(KEY_HOME); break;
  52. case 14: DigiKeyboard.sendKeyStroke(KEY_LEFT_ARROW); break;
  53. case 10: DigiKeyboard.sendKeyStroke(KEY_RIGHT_ARROW); break;
  54. case 11: DigiKeyboard.sendKeyStroke(KEY_DOWN_ARROW); break;
  55. case 7: DigiKeyboard.sendKeyStroke(KEY_UP_ARROW); break;
  56. }
  57. }
  58. }
  59.  
  60. /////////////////////////////////////////////////////////////
  61. // decode infrared signal
  62. /////////////////////////////////////////////////////////////
  63. int getIRKey() {
  64. int data[BIT_PER_BLOCK];
  65. int i;
  66. while(pulseIn(irPin, HIGH) < start_bit); //Wait for a start bit
  67.  
  68. for(i = 0 ; i < BIT_PER_BLOCK ; i++)
  69. data[i] = pulseIn(irPin, HIGH); //Start measuring bits, I only want HIGH pulses
  70.  
  71. delay(100);
  72. for(i = 0 ; i < BIT_PER_BLOCK ; i++) //Parse them
  73. {
  74. if(data[i] > bin_1) //is it a 1?
  75. data[i] = 1;
  76. else if(data[i] > bin_0) //is it a 0?
  77. data[i] = 0;
  78. else
  79. return -1; //Flag the data as invalid; Return -1 on invalid data
  80. }
  81.  
  82. //based on NEC protocol, command data started from bit 16
  83. //and end with bit 24 (8 bits long)
  84. int result = 0;
  85. for(i = 16 ; i < 24; i++) {
  86. //DigiKeyboard.print(data[i]); //print out the value of button in binary form
  87. if(data[i] == 1) result |= (1<<i-16); //Convert data bits to integer
  88. }
  89. return result; //Return key number
  90. }
 
 
4路红外遥控 
使用相同的红外遥控器来控制4个LED,按下各自按键将会切换各自相关LED。完成代码(Sketch)上载后 ,你可以除去1.5K电阻,两个68ohm电阻和两个Zener二极管。
有句广东话:打完齊唔要和尚
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 13050 times Last modified on Saturday, 09 July 2016 17:58

Leave a comment

Back to Top