极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 9314|回复: 9

Arduino红外遥控IRremote扩展库的深入研究----让接受更稳定

[复制链接]
发表于 2015-1-13 16:26:11 | 显示全部楼层 |阅读模式
本帖最后由 弘毅 于 2017-4-23 14:05 编辑

    我从GitHub下载了最新的IRremote扩展库:https://github.com/shirriff/Arduino-IRremote
拿了一个机顶盒的遥控器测试了一下,发现解码非常不稳定,时灵时不灵,换了一个遥控器还是一样,
只能加入调试代码,本来只想调整一下参数,让解码更稳定一些,后来发现代码里有一段逻辑有些问题,
IRremote.cpp代码如下:
  1. int MATCH_MARK(int measured_ticks, int desired_us) {
  2.   Serial.print("Testing mark ");
  3.   Serial.print(measured_ticks * USECPERTICK, DEC);
  4.   Serial.print(" vs ");
  5.   Serial.print(desired_us, DEC);
  6.   Serial.print(": ");
  7.   Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
  8.   Serial.print(" <= ");
  9.   Serial.print(measured_ticks, DEC);
  10.   Serial.print(" <= ");
  11.   Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
  12.   return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
  13. }

  14. int MATCH_SPACE(int measured_ticks, int desired_us) {
  15.   Serial.print("Testing space ");
  16.   Serial.print(measured_ticks * USECPERTICK, DEC);
  17.   Serial.print(" vs ");
  18.   Serial.print(desired_us, DEC);
  19.   Serial.print(": ");
  20.   Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
  21.   Serial.print(" <= ");
  22.   Serial.print(measured_ticks, DEC);
  23.   Serial.print(" <= ");
  24.   Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
  25.   return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
  26. }
复制代码
回复

使用道具 举报

 楼主| 发表于 2015-1-13 16:33:39 | 显示全部楼层
本帖最后由 弘毅 于 2017-4-23 14:06 编辑

参考IRremoteInt.h的代码:
  1. #define TOLERANCE 25  // percent tolerance in measurements
  2. #define LTOL (1.0 - TOLERANCE/100.)
  3. #define UTOL (1.0 + TOLERANCE/100.)

  4. #define _GAP 5000 // Minimum map between transmissions
  5. #define GAP_TICKS (_GAP/USECPERTICK)

  6. #define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
  7. #define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))
复制代码

以及IRremote.h的代码:
  1. // Marks tend to be 100us too long, and spaces 100us too short
  2. // when received due to sensor lag.
  3. #define MARK_EXCESS 100
复制代码

回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-1-13 17:17:13 | 显示全部楼层
本帖最后由 弘毅 于 2017-4-23 14:09 编辑

其中,
MARK_EXCESS是用来补正程序运行时的延迟,默认是100us;
TOLERANCE是容错率,默认25,表示可以允许25%的误差;
TICKS_LOW和TICKS_HIGH用来算容错上下限。

再联系IRremote.cpp我贴出来的53行和67行,
把MARK_EXCESS的补正放到TICKS_LOW和TICKS_HIGH里,事实上就把补正放大了,
本来是100us的,现在就是125us。

修改也比较简单,把53行和67行的MARK_EXCESS的拿出来:
  1.   return measured_ticks - MARK_EXCESS/USECPERTICK >= TICKS_LOW(desired_us) && measured_ticks - MARK_EXCESS/USECPERTICK <= TICKS_HIGH(desired_us);
复制代码
  1.   return measured_ticks + MARK_EXCESS/USECPERTICK >= TICKS_LOW(desired_us) && measured_ticks + MARK_EXCESS/USECPERTICK <= TICKS_HIGH(desired_us);
复制代码


另外,MARK_EXCESS默认的100us有点大,把它设成50us可能更好:
  1. #define MARK_EXCESS 50
复制代码


还有就是TOLERANCE,一般的红外协议占空比是1/3,也就是说到300%的误差才会串码,
如果误码多的话,把TOLERANCE调大也是一个方法。
  1. #define TOLERANCE 50  // percent tolerance in measurements
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-1-13 17:19:44 | 显示全部楼层
通过上面的修改,IRremote库的解码会稳定很多。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-1-14 12:14:17 | 显示全部楼层
本帖最后由 弘毅 于 2017-4-23 14:04 编辑

还是漏了一段,上面的修改只是在DEBUG模式下,正常模式下的修改在下面:
  1. int MATCH(int measured, int desired) {return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);}
  2. int MATCH_MARK(int measured_ticks, int desired_us) {return MATCH((measured_ticks - MARK_EXCESS/USECPERTICK), desired_us);}
  3. int MATCH_SPACE(int measured_ticks, int desired_us) {return MATCH((measured_ticks + MARK_EXCESS/USECPERTICK), desired_us);}
复制代码
回复 支持 反对

使用道具 举报

发表于 2015-1-14 17:51:51 | 显示全部楼层
终于来明白人了,谢谢分享,必须得顶!
回复 支持 反对

使用道具 举报

发表于 2015-6-12 11:30:18 | 显示全部楼层
本帖最后由 stpanzj 于 2015-6-12 11:41 编辑

我认为,这里加入MARK_EXCESS的意思是在MARK的时候,值经常是偏大的,而SPACE的时候测到的值经常是偏小的。
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
因此测MARK时下限应该不变,变的是上限;测SPACE时变下限,上限不变。所以我觉得应该如下修改,取消MATCH,直接在MATCH_MARK/MATCH_SPACE中改公式,更好理解:

int MATCH_MARK(int measured_ticks, int desired_us) {return measured_ticks >= TICKS_LOW(desired_us) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);}
int MATCH_SPACE(int measured_ticks, int desired_us) {return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us);}

也就是删70,改71、72行。晚上回去试一试,看是否实际结果会更好些,我也遇到decode的结果不稳定。

还有
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK)+1)
不知道为何要加1。不加1可以理解,是(1+比例)*原始值,也就是加上上限后的值。加1就不知道为啥了,加上上限后再大1,太小气了。
回复 支持 反对

使用道具 举报

发表于 2015-12-8 13:41:22 | 显示全部楼层
关于空调解码的问题,国外的analys大神给出了一个解码方案,同时解码的长度达到800位,上面两位朋友可以参考一下
analyse大声空调长解码解决方案
网页链接http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/
附上代码
  1. /*
  2. Author: AnalysIR
  3. Revision: 1.0

  4. This code is provided to overcome an issue with Arduino IR libraries
  5. It allows you to capture raw timings for signals longer than 255 marks & spaces.
  6. Typical use case is for long Air conditioner signals.

  7. You can use the output to plug back into IRremote, to resend the signal.

  8. This Software was written by AnalysIR.

  9. Usage: Free to use, subject to conditions posted on blog below.
  10. Please credit AnalysIR and provide a link to our website/blog, where possible.

  11. Copyright AnalysIR 2014

  12. Please refer to the blog posting for conditions associated with use.
  13. http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/

  14. Connections:
  15. IR Receiver      Arduino
  16. V+          ->  +5v
  17. GND          ->  GND
  18. Signal Out   ->  Digital Pin 2
  19. (If using a 3V Arduino, you may connect V+ to +3V)
  20. */

  21. #define LEDPIN 13
  22. //you may increase this value on Arduinos with greater than 2k SRAM
  23. #define maxLen 800

  24. volatile  unsigned int irBuffer[maxLen]; //stores timings - volatile because changed by ISR
  25. volatile unsigned int x = 0; //Pointer thru irBuffer - volatile because changed by ISR

  26. void setup() {
  27.   Serial.begin(9600); //change BAUD rate as required
  28.   attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//set up ISR for receiving IR signal
  29. }

  30. void loop() {
  31.   // put your main code here, to run repeatedly:

  32.   //Serial.println(F("Press the button on the remote now - once only"));
  33.   delay(5000); // pause 5 secs
  34.   if (x) { //if a signal is captured
  35.     digitalWrite(LEDPIN, HIGH);//visual indicator that signal received
  36.     Serial.println();
  37.     Serial.print(F("Raw: (")); //dump raw header format - for library
  38.     Serial.print((x - 1));
  39.     Serial.print(F(") "));
  40.     detachInterrupt(0);//stop interrupts & capture until finshed here
  41.     for (int i = 1; i < x; i++) { //now dump the times
  42.       //if (!(i & 0x1)) Serial.print(F("-"));
  43.       Serial.print(irBuffer[i] - irBuffer[i - 1]);
  44.       Serial.print(F(","));
  45.     }
  46.     x = 0;
  47.     Serial.println();
  48.     Serial.println();
  49.     digitalWrite(LEDPIN, LOW);//end of visual indicator, for this time
  50.     attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//re-enable ISR for receiving IR signal
  51.   }

  52. }

  53. void rxIR_Interrupt_Handler() {
  54.   if (x > maxLen) return; //ignore if irBuffer is already full
  55.   irBuffer[x++] = micros(); //just continually record the time-stamp of signal transitions

  56. }
复制代码
但这样的话,解码的还是会有些不稳定,希望可以一起探讨一下,这种方案 就是直接利用外部中断,感知红外接收管电平变化
回复 支持 反对

使用道具 举报

发表于 2017-4-22 22:37:27 | 显示全部楼层
看了半天也不明白,软件不行啊,楼主能发一个改好的文件吗,我也在为解码乱困惑
回复 支持 反对

使用道具 举报

发表于 2017-4-22 23:57:26 | 显示全部楼层
初学者学习
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2019-2-20 23:47 , Processed in 0.111657 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表