红外线遥控器解码程序.docx
- 文档编号:9269432
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:68
- 大小:49.07KB
红外线遥控器解码程序.docx
《红外线遥控器解码程序.docx》由会员分享,可在线阅读,更多相关《红外线遥控器解码程序.docx(68页珍藏版)》请在冰豆网上搜索。
红外线遥控器解码程序
源动力电子网»单片机»红外线遥控器解码程序
2005-1-1419:
29sina3228
红外线遥控器解码程序
以红外线遥控编码芯片LC7461等芯片为例来说明用单片机实现红外遥控解码的详细过程,站长琢磨这个解码程序花了相当多的精力,后来还用它开发了几个小产品,希望能对网友学习单片机有所帮助。
1红外遥控系统
2遥控发射器及其编码
遥控发射器专用芯片很多,根据编码格式可以分成脉冲宽度调制和脉冲相位调制两大类,这里我们以运用比较广泛,解码比较容易的脉冲宽度调制来加以说明,现以LC7461组成发射电路为例说明编码原理。
这种遥控码具有以下特征:
采用脉宽调制的串行码,以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”
上述“0”和“1”组成的42位二进制码经38kHz的载频进行二次调制以提高发射效率,达到降低电源功耗的目的。
然后再通过红外发射二极管产生红外线向空间发射,
7461产生的遥控编码是连续的42位二进制码组,其中前26位为用户识别码,能区别不同的红外遥控设备,防止不同机种遥控码互相干扰。
后16位为8位的操作码和8位的操作反码用于核对数据是否接收准确。
当遥控器上任意一个按键按下超过36ms时,LC7461芯片的振荡器使芯片激活,将发射一个特定的同步码头,对于接收端而言就是一个9ms的低电平,和一个4.5ms的高电平,这个同步码头可以使程序知道从这个同步码头以后可以开始接收数据。
解码的关键是如何识别“0”和“1”,从位的定义我们可以发现“0”、“1”均以0.56ms的低电平开始,不同的是高电平的宽度不同,“0”为0.56ms,“1”为1.68ms,所以必须根据高电平的宽度区别“0”和“1”。
如果从0.56ms低电平过后,开始延时,0.56ms以后,若读到的电平为低,说明该位为“0”,反之则为“1”,为了可靠起见,延时必须比0.56ms长些,但又不能超过1.12ms,否则如果该位为“0”,读到的已是下一位的高电平,因此取(1.12ms+0.56ms)/2=0.84ms最为可靠,一般取0.84ms左右即可。
LT0038是塑封一体化红外线接收器,它是一种集红外线接收、放大、整形于一体的集成电路,不需要任何外接元件,就能完成从红外线接收到输出与TTL电平信号兼容的所有工作,没有红外遥控信号时为高电平,收到红外信号时为低电平,而体积和普通的塑封三极管大小一样,它适合于各种红外线遥控和红外线数据传输。
下面是一个对51实验板配套的红外线遥控器的解码程序,它可以把上图32键的红外遥控器每一个按键的键值读出来,并且通过实验板上P1口的8个LED显示出来,在解码成功的同时并且能发出“嘀嘀嘀”的提示音。
ORG0000H
AJMPMAIN;转入主程序
ORG0003H;外部中断P3.2脚INT0入口地址
AJMPINT;转入外部中断服务子程序(解码程序)
MAIN:
;以下为主程序进行CPU中断方式设置
SETBEA;打开CPU总中断请求
SETBIT0;设定INT0的触发方式为脉冲负边沿触发
SETBEX0;打开INT0中断请求
;以下对单片机的所有引脚进行初始化,全部设置成高电平
MOVP2,#11100111B
AJMP$
;以下为进入P3.2脚外部中断子程序,也就是解码程序
INT:
CLREA;暂时关闭CPU的所有中断请求
MOVR6,#10
SB:
ACALLYS1;调用882微秒延时子程序
JBP3.2,EXIT;延时882微秒后判断P3.2脚是否出现高电平如果有就退出解码程序
DJNZR6,SB;重复10次,目的是检测在8820微秒内如果出现高电平就退出解码程序
;以上完成对遥控信号的9000微秒的初始低电平信号的识别。
JNBP3.2,$;等待高电平避开9毫秒低电平引导脉冲
ACALLYS2;延时4.74毫秒避开4.5毫秒的结果码
MOVR7,#26;忽略前26位系统识别码
JJJJA:
JNBP3.2,$;等待地址码第一位的高电平信号
LCALLYS1;高电平开始后用882微秒的时间尺去判断信号此时的高低电平状态
MOVC,P3.2;将P3.2引脚此时的电平状态0或1存入C中
JNCUUUA;如果为0就跳转到UUUA
LCALLYS3;检测到高电平1的话延时1毫秒等待脉冲高电平结束
UUUA:
DJNZR7,JJJJA
MOVR1,#1AH;设定1AH为起始RAM区
MOVR2,#2;接收从1AH到1BH的2个内存,用于存放操作码和操作反码
PP:
MOVR3,#8;每组数据为8位
JJJJ:
JNBP3.2,$;等待地址码第一位的高电平信号
LCALLYS1;高电平开始后用882微秒的时间尺去判断信号此时的高低电平状态
MOVC,P3.2;将P3.2引脚此时的电平状态0或1存入C中
JNCUUU;如果为0就跳转到UUU
LCALLYS3;检测到高电平1的话延时1毫秒等待脉冲高电平结束
UUU:
MOVA,@R1;将R1中地址的给A
RRCA;将C中的值0或1移入A中的最低位
MOV@R1,A;将A中的数暂时存放在R1数值的内存中
DJNZR3,JJJJ;接收满8位换一个内存
INCR1;对R1中的值加1,换下一个RAM
DJNZR2,PP;接收完8位数据码和8位数据反码,存放在1AH/1BH中
MOVA,1AH
CPLA;对1AH取反后和1BH比较
CJNEA,1BH,EXIT;如果不等表示接收数据发生错误,放弃
MOVP1,1AH;将按键的键值通过P1口的8个LED显示出来!
CLRP2.5;蜂鸣器鸣响-嘀嘀嘀-的声音,表示解码成功
LCALLYS2
LCALLYS2
LCALLYS2
SETBP2.5;蜂鸣器停止
EXIT:
SETBEA;允许中断
RETI;退出解码子程序
YS1:
MOVR4,#20;延时子程序1,精确延时882微秒
D1:
MOVR5,#20
DJNZR5,$
DJNZR4,D1
RET
YS2:
MOVR4,#10;延时子程序2,精确延时4740微秒
D2:
MOVR5,#235
DJNZR5,$
DJNZR4,D2
RET
YS3:
MOVR4,#2;延时程序3,精确延时1000微秒
D3:
MOVR5,#248
DJNZR5,$
DJNZR4,D3
RET
END
0A 01
11121314
15161718
19101A1B
0E02031C
0604050C
0D08091D
001F1E0B
07 0F
这是按照红外遥控器按键的实际位置给出的32个按键的键值(16进制)
2005-1-1419:
37sina3228
ORG0000H
AJMPMAIN
ORG0003H;外部中断INT0入口地址
AJMPINT;转中断服务子程序
MAIN:
MOVSP,#40H
MOVP1,#00H
SETBEA;开CPU中断
SETBIT0;设定INT0触发方式
SETBEX0;INT0请求中断
DSP:
MOVR2,#9;将遥控器键值转化成A(0~9)
MOVDPTR,#TAB1
VV:
MOVA,R2
MOVCA,@A+DPTR
XRLA,1CH
JZABC
DJNZR2,VV
ABC:
MOVA,R2
MOVDPTR,#TAB;将A的值通过数码管显示出来
MOVCA,@A+DPTR
RX1:
MOVP1,A
CLRP0.1
AJMPDSP
INT:
CLREA
MOVR6,#10
SB:
ACALLYS1
JBP3.2,EXIT
DJNZR6,SB
JNBP3.2,$;等待高电平避开9毫秒低电平引导脉冲
ACALLYS2;延时4。
74毫秒判断是否连发
JBP3.2,EXIT
CPLP0.0
MOVR1,#1AH;将32位代码分别放在1AH/1BH/1CH/1DH中
MOVR2,#4
PP:
MOVR3,#8
JJJJ:
JNBP3.2,$
LCALLYS1
MOVC,P3.2
JNCUUU
JBP3.2,$
UUU:
MOVA,@R1
RRCA
MOV@R1,A
DJNZR3,JJJJ
INCR1
DJNZR2,PP
MOVP2,1CH
MOVA,1AH;进行代码识别
XRLA,#0;判断1AH的值是否等于00000000
JNZEXI;如果不同则无效将1CH清零
CLRP0.1
MOVA,1BH
XRLA,#11110111B;再判断高8位地址是否正确
JNZEXI
MOVA,1CH
CPLA
XRLA,1DH;将1CH的值取反后和1DH比较不同则无效丢弃核对数据是否准确
JNZEXI
AJMPEXIT
EXI:
MOV1CH,#0
EXIT:
SETBEA;允许中断
RETI
YS1:
MOVR4,#20;精确延时882微秒
D1:
MOVR5,#20
DJNZR5,$
DJNZR4,D1
RET
YS2:
MOVR4,#10;精确延时4740微秒
D2:
MOVR5,#235
DJNZR5,$
DJNZR4,D2
RET
TAB:
DB60H,7DH,0D0H,58H,4DH
DB4AH,42H,7CH,40H,48H
TAB1:
DB0CH,09H,1DH,1FH,0DH
DB19H,1BH,11H,15H,17H
END
;TABLED数码管显示表TAB1遥控器键值表
这里我们以红外线遥控编码芯片为uPD6121G(或者是HT622、7461等芯片)为例来说明用单片机实现红外遥控解码的详细过程
采用脉宽调制的串行码,以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”,其波形如图2所示。
UPD6121G产生的遥控编码是连续的32位二进制码组,其中前16位为用户识别码,能区别不同的电器设备,防止不同机种遥控码互相干扰。
该芯片的用户识别码固定为十六进制01H;后16位为8位操作码(功能码)及其反码。
UPD6121G最多额128种不同组合的编码。
遥控器在按键按下后,周期性地发出同一种32位二进制码,周期约为108ms。
一组码本身的持续时间随它包含的二进制“0”和“1”的个数不同而不同,大约在45~63ms之间,图4为发射波形图。
当一个键按下超过36ms,振荡器使芯片激活,将发射一组108ms的编码脉冲,这108ms发射代码由一个起始码(9ms),一个结果码(4.5ms),低8位地址码(9ms~18ms),高8位地址码(9ms~18ms),8位数据码(9ms~18ms)和这8位数据的反码(9ms~18ms)组成。
如果键按下超过108ms仍未松开,接下来发射的代码(连发代码)将仅由起始码(9ms)和结束码(2.5ms)组成。
代码宽度算法:
16位地址码的最短宽度:
1.12×16=18ms16位地址码的最长宽度:
2.24ms×16=36ms
易知8位数据代码及其8位反代码的宽度和不变:
(1.12ms+2.24ms)×8=27ms
∴32位代码的宽度为(18ms+27ms)~(36ms+27ms)
1.解码的关键是如何识别“0”和“1”,从位的定义我们可以发现“0”、“1”均以0.56ms的低电平开始,不同的是高电平的宽度不同,“0”为0.56ms,“1”为1.68ms,所以必须根据高电平的宽度区别“0”和“1”。
如果从0.56ms低电平过后,开始延时,0.56ms以后,若读到的电平为低,说明该位为“0”,反之则为“1”,为了可靠起见,延时必须比0.56ms长些,但又不能超过1.12ms,否则如果该位为“0”,读到的已是下一位的高电平,因此取(1.12ms+0.56ms)/2=0.84ms最为可靠,一般取0.84ms左右均可。
2.根据码的格式,应该等待9ms的起始码和4.5ms的结果码完成后才能读码。
接收器及解码
下面是一个对51实验板配套的红外线遥控器的解码程序,它可以把上图32键的红外遥控器每一个按键的键值读出来,并且通过实验板上P1口的8个LED显示出来,在解码成功的同时并且能发出“嘀嘀嘀”的提示音。
这是站长最新用单片机AT89C51制作的30路红外遥控器,遥控器就是自家的VCD遥控器,接收板用了5片CD4069作为输出缓冲隔离,当按下遥控器30个按键中的一个,接收板对应的一个触点会变成高电平,松开按键,立即恢复成低电平,和TTL兼容。
2005-1-1419:
45sina3228
红外遥控器软件解码原理及程序
红外一开始发送一段13.5ms的引导码,引导码由9ms的高电平和4.5ms的低电平组成,跟着引导码是系统码,系统反码,按键码,按键反码,如果按着键不放,则遥控器则发送一段重复码,重复码由9ms的高电平,2.25ms的低电平,跟着是一个短脉冲,本程序经过试用,能解大部分遥控器的编码!
#include"at89x52.h"
#defineNULL0x00//数据无效
#defineRESET0X01//程序复位
#defineREQUEST0X02//请求信号
#defineACK0x03//应答信号,在接收数据后发送ACK信号表示数据接收正确,也位请求信号的应答信号
#defineNACK0x04//应答信号,表示接收数据错误
#defineBUSY0x05//忙信号,表示正在忙
#defineFREE0x06//空闲信号,表示处于空闲状态
#defineREAD_IR0x0b//读取红外
#defineSTORE_IR0x0c//保存数据
#defineREAD_KEY0x0d//读取键值
#defineRECEIVE0Xf400//接收缓冲开始地址
#defineSEND0xfa00//发送缓冲开始地址
#defineIR0x50//红外接收缓冲开始地址
#defineHEAD0xaa//数据帧头
#defineTAIL0x55//数据帧尾
#defineSDAP1_7
#defineSCLP1_6
unsignedcharxdata*buf1;//接受数据缓冲
unsignedintbuf1_length;//接收到的数据实际长度
unsignedcharxdata*buf2;//发送数据缓冲
unsignedintbuf2_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{//
//unsignedchara[2];//
//unsignedintb;
//unsignedchardata*p1[2];
//unsignedintdata*p2[2];
//unsignedcharxdata*p3;
//unsignedintxdata*p4;//地址指针
//}q;//
union{
unsignedchara[2];
unsignedintb;
}count;
union{
unsignedchara[2];
unsignedintb;
}temp;
union{
unsignedchara[4];
unsignedintb[2];
unsignedlongc;
}ir_code;
union{
unsignedchara[4];
unsignedintb[2];
unsignedlongc;
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=0;//将EXF2清零
if(!
TH0)//判断是否是长低电平脉冲过来了
{//不是长低电平脉冲而是短低电平
if(F0)count.b++;//短脉冲数加一
temp.a[0]=RCAP2H;//将捕捉数临时存放起来
temp.a[1]=RCAP2L;
gotoloop;//返回继续查询
}
else{//是低电平脉冲,则进行处理
F0=0;
*ir=temp.a[0];//把连续的短脉冲总时间记录下来
ir++;
*ir=temp.a[1];
ir++;
*ir=RCAP2H;//把长电平脉冲时间记录下来
ir++;
*ir=RCAP2L;
ir++;
if(ir>=0xda){
gotoexit;//判断是否溢出缓冲,如果溢出则失败退出
}
gotoloop;//返回继续查询
}
exit:
ir_flag=1;//置ir_flag为1表示接收成功
end:
;
}
voidrs232(void)interrupt4{
staticunsignedcharsbuf1,sbuf2,rsbuf1,rsbuf2;//sbuf1,sbuf2用来接收发送临时用,rsbuf1,rsbuf2用来分别用来存放接收发送的半字节
EA=0;//禁止中断
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)//判断是否接收到数据帧尾
{//是接收到数据帧尾
buf1=RECEIVE;//初始化接收的地址
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
{//不是接受到数据帧尾,表明接收错误
state1=0;//将接收状态标志置为零,重新接收
buf1=RECEIVE;//初始化发送的地址
*buf1=NACK;//把NACK信号存入接收缓冲里
buf1_flag=1;//置标志位为1,使主
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 红外线 遥控器 解码 程序