红外遥控器软件解码及其应用Word文档下载推荐.docx
《红外遥控器软件解码及其应用Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《红外遥控器软件解码及其应用Word文档下载推荐.docx(10页珍藏版)》请在冰豆网上搜索。
笔者用软件方法实现了对脉冲流分析。
以图1所示接口为例,如果没有红外遥控信号到来,接收器输出端口PO保持高电平;
当接收到红外遥控信号时,接收器件信号转换成脉冲序列加到CPU中断输入引脚。
用软件测试引脚逻辑电平,同时启动TC计时器,测量该引脚分别为逻辑“0”和逻辑“1”情况下时间值,存储起来,然后打印、分析。
下面用8051汇编语言给出对脉冲流进行采集、存储程序段:
MOVR0,#00H
MOVR1,#28H
MOVTMOD,#01H
TK:
JBP3.3,TK;
等待低电平到来
;
测低电平宽度
TK1:
MOVTH0,#00H
MOVTL0,#00H
SETBTR0
TK0:
JBTF0,TKE;
超时无效返回
JNBP3.3,TK2
CLRTR0
MOVA,TH0
MOVX@R0,A
INCR0
MOVA,TL0
测高电平宽度
TK3:
JBP3.3,TK3
DJNZR1,TK1;
循环
TKE:
RET
这段程序首先将TC0设置成16位定时器方式,初始化RAM地址指针R0和循环计数指针R1,每当引脚逻辑电平发生跳变时,停止计时,将计时值保存到连续RAM中。
这段程序可以连续测量40个脉冲时间值(包括40个低电平脉宽)。
笔者以TC9012芯片遥控器为对象,采集了所有按键编程脉冲波形,并且对同一按键进行了重复实验。
限于篇幅,采样数据不能给出,仅给出脉冲流规律(仿真机CPU晶振为6MHz):
①引导脉冲是一个时间值为0937H~0957H低电平和时间值为084FH~086FH高电平;
②数据脉冲低电平时间值约为0.127H~0177H;
③高电平时间值有2种情况:
00BBH~00FFH(窄)、02EFH~0333H(宽)。
由大量数据总结分析,按键编码有如下规律:
①除引导脉冲外脉冲是数据编码脉冲,数据“位”信息由高电平脉宽决定:
窄脉宽表示“0”、宽脉宽表示“1”;
②每个按键脉冲流译码后,包含4个字节信息:
*所有按键前2个字节编码都一样,都是2个字节“0EH”;
*第3字节是键码;
*第4字节是键码反码。
经过对相同按键脉冲进行多次采样发现,相同按键脉冲序列对应位置脉宽时间值是在一个小范围内波动(不是一个确定值),因此,对模式识别不能采取精确比较法。
对此,本人采取模糊办法进行了抽象处理。
根据上述实验规律,将软件译码时对脉冲分析判断依据及算法设计思想总结如下:
①引导脉冲低电平和高电平宽度判断依据是时间值“高字节大于08H”,低字节忽略;
②数据脉冲流低电平脉宽相同,忽略不判断;
③高电平脉宽是判断数据流每位是“0”还是“1”依据。
本人抽取判断是脉宽高字节若小于2表示“0”,否则表示“1”,脉宽低字节忽略。
实践证明,上述判据是有效可行。
这样处理不仅使解码软件设计简单化,而且大大提高了解码速度。
使用上述判据编写软件解码程序时,要注意脉冲流采样数据存储地址与脉冲对应关系。
软件主要有如下几部分:
①判断遥控信号到来(在解码前调用1个独立子程序);
②采样并存储脉冲流;
③判断引导脉冲是否有效;
④解码前2个字节并判断是否为“0EH”;
⑤解码第3个字节,该字节即为有效键码;
⑥键码查表映射(如果使用原键码,可省略这一步)。
3解码软件设计
基于上述思路设计软件解码系统成功地应用于多个控制系统。
下面给出一个实例(用MCS-51系列MC交通规则TC9012红外遥控器进行软件解码)汇编语言程序。
程序中使用参数是针对MCU使用6MHz晶振情况,使用其它频率晶振,只需修改脉宽判据即可。
为便于理解,尽量保持与原理叙述中致性,程序中给出了较详细注翻译,详见网络补充版()。
本文虽然是用MCS-51系列MCU对TC9012红外遥控器软件解码研究,但其方法具有一般性。
具体应用,可自行变通。
红外遥控器软件解码原理和程序
红外一开始发送一段13.5ms的引导码,引导码由9ms的高电平和4.5ms的低电平组成,跟着引导码是系统码,系统反码,按键码,按键反码,如果按着键不放,则遥控器则发送一段重复码,重复码由9ms的高电平,2.25ms的低电平,跟着是一个短脉冲,本程序经过试用,能解大部分遥控器的编码!
#include
"
at89x52.h"
#define
NULL
0x00//数据无效
RESET
0X01//程序复位
REQUEST
0X02//请求信号
ACK
0x03//应答信号,在接收数据后发送ACK信号表示数据接收正确,
也位请求信号的应答信号
NACK
0x04//应答信号,表示接收数据错误
BUSY
0x05//忙信号,表示正在忙
FREE
0x06//空闲信号,表示处于空闲状态
READ_IR
0x0b//读取红外
STORE_IR
0x0c//保存数据
READ_KEY
0x0d//读取键值
RECEIVE
0Xf400//接收缓冲开始地址
SEND
0xfa00//发送缓冲开始地址
IR
0x50//红外接收缓冲开始地址
HEAD
0xaa//数据帧头
TAIL
0x55//数据帧尾
SDA
P1_7
SCL
P1_6
unsignedcharxdata*buf1;
//接受数据缓冲
unsignedint
buf1_length;
//接收到的数据实际长度
unsignedcharxdata*buf2;
//发送数据缓冲
buf2_length;
//要发送的数据实际长度
bitbuf1_flag;
//接收标志,1表示接受到一个数据帧,0表示没有接受到数据帧或数据
帧为空
bitbuf2_flag;
//发送标志,1表示需要发送或没发送完毕,0表示没有要发送的数据或
发送完毕
unsignedcharstate1,state2;
//用来标志接收字符的状态,state1用来表示接
收状态,state2用来表示发送状态
unsignedchardata*ir;
union{
unsignedchara[2];
unsignedintb;
unsignedchardata*p1[2];
unsignedintdata*p2[2];
unsignedcharxdata*p3;
//红外缓冲的指针
unsignedintxdata*p4;
}p;
//union{
//
//
//地址指针
//}q;
}count;
}temp;
unsignedchara[4];
unsignedintb[2];
unsignedlongc;
}ir_code;
unsignedchardata*p1[4];
unsignedintdata*p2[4];
unsignedcharxdata*p3[2];
unsignedintxdata*p4[2];
}i;
unsignedcharir_key;
bitir_flag;
//红外接收标志,0为缓冲区空,1为接收成功,2为缓冲溢出
voidsub(void);
voiddelay(void);
voidie_0(void);
voidtf_0(void);
voidie_1(void);
voidtf_1(void);
voidtf_2(void);
voidread_ir(void);
voidir_jiema(void);
voidir_init(void);
voidir_exit(void);
voidstore_ir(void);
voidread_key(void);
voidreset_iic(void);
unsignedcharread_byte_ack_iic(void);
unsignedcharread_byte_nack_iic(void);
bitwrite_byte_iic(unsignedchara);
voidsend_ack_iic(void);
voidsend_nack_iic(void);
bitreceive_ack_iic(void);
voidstart_iic(void);
voidstop_iic(void);
voidwrite_key_data(unsignedchara);
unsignedintread_key_data(unsignedchara);
voidie0(void)
interrupt0{ie_0();
}
voidtf0(void)
interrupt1{tf_0();
voidie1(void)
interrupt2{ie_1();
voidtf1(void)
interrupt3{tf_1();
tf_2();
voidtf2(void)
interrupt5{
//采用中断方式跟查询方式相结合的办法解
码
EA=0;
//禁止中断
if(TF2){
//判断是否是溢出还是电平变化产生的中断
TF2=0;
//如果是溢出产生的中断则清除溢出位,重
新开放中断退出
EA=1;
gotoend;
EXF2=0;
//清除电平变化产生的中断位
*ir=RCAP2H;
//把捕捉的数保存起来
ir++;
*ir=RCAP2L;
*ir++;
F0=1;
TR0=1;
//开启计数器0
loop:
TL0=0;
//将计数器0重新置为零
TH0=0;
while(!
EXF2){
//查询等待EXF2变为1
if(TF0)gotoexit;
//检查有没超时,如果超时则退出
};
//将EXF2清零
if(!
TH0)
//判断是否是长低电平脉冲过来了
{
//不是长低电平脉冲而是短低电平
if(F0)count.b++;
//短脉冲数加一
temp.a[0]=RCAP2H;
//将捕捉数临时存放起来
temp.a[1]=RCAP2L;
gotoloop;
//返回继续查询
else{
//是低电平脉冲,则进行处理
F0=0;
*ir=temp.a[0];
//把连续的短脉冲总时间记录下来
*ir=temp.a[1];
//把长电平脉冲时间记录下来
if(ir>
=0xda){
gotoexit;
//判断是否溢出缓冲,如果溢出则失败退出
exit:
ir_flag=1;
//置ir_flag为1表示接收成功
end:
;
voidrs232(void)
interrupt
4{
staticunsignedcharsbuf1,sbuf2,rsbuf1,rsbuf2;
//sbuf1,sbuf2用来接收
发送临时用,rsbuf1,rsbuf2用来分别用来存放接收发送的半字节
if(RI){
RI=0;
//清除接收中断标志位
sbuf1=SBUF;
//将接收缓冲的字符复制到sbuf1
if(sbuf1==HEAD){
//判断是否帧开头
state1=10;
//是则把state赋值为10
buf1=RECEIVE;
//初始化接收地
址
else{
switch(state1){
case10:
sbuf2=sbuf1>
>
4;
//把高半字节右移到的半字节
sbuf2=~sbuf2;
//把低半字节取反
if((sbuf2&
0x0f)!
=(sbuf1&
0x0f))
//判断接收是否正确
//接收错误,有可能接收的是数
据帧尾,也有可能是接收错误
if(sbuf1==TAIL)
//判断是否接收到数据帧尾
//是接收到数据帧尾
//初始化接收的地址
if(*buf1==RESET)
//判断是否为复位命令
{
ES=0;
sbuf2=SP+1;
for(p.p1[0]=SP-0x10;
p.p1[0]<
=sbuf2;
p.p1
[0]++)*p.p1[0]=0;
state1=0;
//将接收状态标志置为零,接收
下一个数据帧
buf1_flag=1;
//置接收标志为1,表示已经接收
到一个数据帧
REN=0;
//禁止接收
else
//不是接受到数据帧尾,表明接
收错误
//将接收状态标志置为零,重新
接收
//初始化发送的地址
*buf1=NACK;
//把NACK信号存入接收缓冲里
//置标志位为1,使主程序能对接
收错误进行处理
//接收正确
rsbuf1=~sbuf1;
//按位取反,使高半字节变原码
rsbuf1&
=0xf0;
//仅保留高半字节,低半字节去
掉
state1=20;
//将状态标志置为20,准备接收
低半字节
break;
case20:
//将低半字节取反
//接受