Arduino红外遥控IRremote扩展库的深入研究----让接受更稳定
本帖最后由 弘毅 于 2017-4-23 14:05 编辑我从GitHub下载了最新的IRremote扩展库:https://github.com/shirriff/Arduino-IRremote
拿了一个机顶盒的遥控器测试了一下,发现解码非常不稳定,时灵时不灵,换了一个遥控器还是一样,
只能加入调试代码,本来只想调整一下参数,让解码更稳定一些,后来发现代码里有一段逻辑有些问题,
IRremote.cpp代码如下:
int MATCH_MARK(int measured_ticks, int desired_us) {
Serial.print("Testing mark ");
Serial.print(measured_ticks * USECPERTICK, DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
}
int MATCH_SPACE(int measured_ticks, int desired_us) {
Serial.print("Testing space ");
Serial.print(measured_ticks * USECPERTICK, DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
}
本帖最后由 弘毅 于 2017-4-23 14:06 编辑
参考IRremoteInt.h的代码:
#define TOLERANCE 25// percent tolerance in measurements
#define LTOL (1.0 - TOLERANCE/100.)
#define UTOL (1.0 + TOLERANCE/100.)
#define _GAP 5000 // Minimum map between transmissions
#define GAP_TICKS (_GAP/USECPERTICK)
#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))
以及IRremote.h的代码:
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100
本帖最后由 弘毅 于 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的拿出来:
return measured_ticks - MARK_EXCESS/USECPERTICK >= TICKS_LOW(desired_us) && measured_ticks - MARK_EXCESS/USECPERTICK <= TICKS_HIGH(desired_us);
return measured_ticks + MARK_EXCESS/USECPERTICK >= TICKS_LOW(desired_us) && measured_ticks + MARK_EXCESS/USECPERTICK <= TICKS_HIGH(desired_us);
另外,MARK_EXCESS默认的100us有点大,把它设成50us可能更好:
#define MARK_EXCESS 50
还有就是TOLERANCE,一般的红外协议占空比是1/3,也就是说到300%的误差才会串码,
如果误码多的话,把TOLERANCE调大也是一个方法。
#define TOLERANCE 50// percent tolerance in measurements
通过上面的修改,IRremote库的解码会稳定很多。 本帖最后由 弘毅 于 2017-4-23 14:04 编辑
还是漏了一段,上面的修改只是在DEBUG模式下,正常模式下的修改在下面:
int MATCH(int measured, int desired) {return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);}
int MATCH_MARK(int measured_ticks, int desired_us) {return MATCH((measured_ticks - MARK_EXCESS/USECPERTICK), desired_us);}
int MATCH_SPACE(int measured_ticks, int desired_us) {return MATCH((measured_ticks + MARK_EXCESS/USECPERTICK), desired_us);}
终于来明白人了,谢谢分享,必须得顶! 本帖最后由 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,太小气了。 关于空调解码的问题,国外的analys大神给出了一个解码方案,同时解码的长度达到800位,上面两位朋友可以参考一下
analyse大声空调长解码解决方案
网页链接http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/
附上代码/*
Author: AnalysIR
Revision: 1.0
This code is provided to overcome an issue with Arduino IR libraries
It allows you to capture raw timings for signals longer than 255 marks & spaces.
Typical use case is for long Air conditioner signals.
You can use the output to plug back into IRremote, to resend the signal.
This Software was written by AnalysIR.
Usage: Free to use, subject to conditions posted on blog below.
Please credit AnalysIR and provide a link to our website/blog, where possible.
Copyright AnalysIR 2014
Please refer to the blog posting for conditions associated with use.
http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/
Connections:
IR Receiver Arduino
V+ ->+5v
GND ->GND
Signal Out ->Digital Pin 2
(If using a 3V Arduino, you may connect V+ to +3V)
*/
#define LEDPIN 13
//you may increase this value on Arduinos with greater than 2k SRAM
#define maxLen 800
volatileunsigned int irBuffer; //stores timings - volatile because changed by ISR
volatile unsigned int x = 0; //Pointer thru irBuffer - volatile because changed by ISR
void setup() {
Serial.begin(9600); //change BAUD rate as required
attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//set up ISR for receiving IR signal
}
void loop() {
// put your main code here, to run repeatedly:
//Serial.println(F("Press the button on the remote now - once only"));
delay(5000); // pause 5 secs
if (x) { //if a signal is captured
digitalWrite(LEDPIN, HIGH);//visual indicator that signal received
Serial.println();
Serial.print(F("Raw: (")); //dump raw header format - for library
Serial.print((x - 1));
Serial.print(F(") "));
detachInterrupt(0);//stop interrupts & capture until finshed here
for (int i = 1; i < x; i++) { //now dump the times
//if (!(i & 0x1)) Serial.print(F("-"));
Serial.print(irBuffer - irBuffer);
Serial.print(F(","));
}
x = 0;
Serial.println();
Serial.println();
digitalWrite(LEDPIN, LOW);//end of visual indicator, for this time
attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//re-enable ISR for receiving IR signal
}
}
void rxIR_Interrupt_Handler() {
if (x > maxLen) return; //ignore if irBuffer is already full
irBuffer = micros(); //just continually record the time-stamp of signal transitions
}但这样的话,解码的还是会有些不稳定,希望可以一起探讨一下,这种方案 就是直接利用外部中断,感知红外接收管电平变化 看了半天也不明白,软件不行啊,楼主能发一个改好的文件吗,我也在为解码乱困惑 初学者学习
页:
[1]