资源描述
51单片机红外解码程序
1、 红外遥控系统
2、 org 000h
3、 ljmp main
4、 org 0003h
5、 ljmp in0zd ;外部中断0入口
6、 org 000Bh
7、 ljmp t0zd;定时器T0
8、 org 0100h
9、 ;主程序
10、 main:clr p2.0 ;选择数码管第一位(共阴)
11、 setb IT0 ;定时器T0设置
12、 setb EX0
13、 setb ea
14、 mov TMOD,#02h ;T0工作在方式2
15、 mov TH0,#00h ;
16、 mov TL0,#00h ; T0赋予初值
17、 setb ET0 ;打开中断
18、 setb p3.2 ;置位3.2
19、 setb tr0 ;tr0置位
20、 main1: acall yyi ;寄存器际初始化
21、 pp:jnb 20h.0,pp;判断有无信号
22、 clr 20h.0 ;有则清零20H.0
23、 acall jy ;接受到的数据是否正确,并显示
24、 sjmp main1 ;跳转到MAIN1
25、 ;int0中断处理1
26、 in0zd: jb 20h.1,js ;判断20H.1是1还是0.是1跳转JS(进入数据处理) 是0说明接收的是引导码
27、 cjne r7,#33h,next ; 为0,判断引导码是否正确 (33h<r7<4fh)
28、 next:jc exit ;引导时间大于13.045MS 小于20.224ms,引导码正确。否则引导码无效。
29、 cjne r7,#4fh,next1
30、 next1:jnc exit
31、 setb 20h.1 ;若正确 置位20H.1
32、 exit:mov r7,#00h ; 并清除R7
33、 ljmp ret1
34、 js:cjne r7,#08h,next2 ;判断接受的数据是1还是0
35、 next2:jc ol ;若大于=2.048ms (0.256ms*8)则为1
36、 ;数码0处理
37、 clr cy ;0处理程序
38、 mov a,@r0 ;接受到的0,送入存储
39、 rlc a
40、 mov @r0,a
41、 sjmp exit1
42、 ol: ;为1处理
43、 setb cy
44、 mov a,@r0 ;假设接受的第6个数据为1,以前的数据是@R0=00001001,
45、 rlc a ;带进位的左移 执行后A=00010011
46、 mov @r0,a ;送回保存
47、 exit1:
48、 djnz r6,exit ;判断一个字节接受完否?若没有 清楚R7,进行下8位数据接受
49、 mov r6,#08h
50、 inc r0
51、 djnz r5,exit ;判断32位数据接受完否?若没有 清楚R7,进行下8位数据接受
52、 clr 20h.1 ;清楚20H.1
53、 setb 20h.0 ;置位接收完标志位
54、 ret1:reti
55、
56、 ;错码检验显示
57、 jy:mov a,33h ;数据接收是否正确
58、 cpl a
59、 cjne a,32h,tch ;数据码和反码是否一样 ,不一样弃掉
60、 xs:cjne a,#68h,tch1 ;一样 键值处理
61、 mov p1,#3fh ;显示0 (数码管事共阴)
62、 sjmp tch
63、 tch1:cjne a,#30h,tch2
64、 mov p1,#06h ;显示1
65、 sjmp tch
66、 tch2:cjne a,#18h,tch3
67、 mov p1,#5bh ;显示2
68、 sjmp tch
69、 tch3:cjne a,#7ah,tch4
70、 mov p1,#4fh ;显示3
71、 sjmp tch
72、 tch4:cjne a,#10h,tch5
73、 mov p1,#66h ;显示4
74、 sjmp tch
75、 tch5:cjne a,#38h,tch6
76、 mov p1,#6dh ;显示5
77、 sjmp tch
78、 tch6:cjne a,#5ah,tch7
79、 mov p1,#7dh ;显示6
80、 sjmp tch
81、 tch7:cjne a,#42h,tch8
82、 mov p1,#07h ;显示7
83、 sjmp tch
84、 tch8:cjne a,#4ah,tch9
85、 mov p1,#7fh ;显示8
86、 sjmp tch
87、 tch9:cjne a,#52h,tch
88、 mov p1,#6fh ;显示9
89、 tch:ret
90、 yyi: mov sp,#60h
91、 mov r0,#30h
92、 mov r6,#08h
93、 mov r7,#00h
94、 mov r5,#04h
95、 ret
96、 ;T0中断处理
97、 t0zd:
98、 inc r7
99、 reti
100、
101、
102、
103、
104、
通用红外遥控系统由发射和接收两大部分组成,应用编/解码专用集成电路芯片来进行控制操作,如图1所示。
发射部分包括键盘矩阵、编码调制、LED红外发送器;
接收部分包括光、电转换放大器、解调、解码电路。
下面,我们将使用下面两种设备:
另外,使用51单片机进行解码。
2、原理图
从原理图看出,IR的data脚与51的PD2(P3.2)相连。
2、红外发射原理
要对红外遥控器所发的信号进行解码,必须先理解这些信号。
a) 波形
首先来看看,当我们按下遥控器时,红外发射器是发送了一个什么样的信号波形,如下图:
由上图所示,当一个键按下超过22ms,振荡器使芯片激活,将发射一组108ms的编码脉冲(由位置1所示)。如果键按下超过108ms仍未松开,接下来发射的代码(连发代码由位置3所示)将仅由起始码(9ms)和结束码(2.5ms)组成。下面把位置1的波形放大:
由位置1的波形得知,这108ms发射代码由一个起始码(9ms),一个结果码(4.5ms),低8位地址码(用户编码)(9ms~18ms),高8位地址码(用户编码)(9ms~18ms),8位数据码(键值数据码)(9ms~18ms)和这8位数据的反码(键值数据码反码)(9ms~18ms)组成。
b) 编码格式
遥控器发射的信号由一串0和1的二进制代码组成.不同的芯片对0和1的编码有所不同。通常有曼彻斯特编码和脉冲宽度编码。XS-091遥控板的0和1采用PWM方法编码,即脉冲宽度调制。下图为一个发射波形对应的编码方法:
放大0和1的波形如下图:
这种编码具有以下特征:以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”。
3、红外接收原理
a) 波形
红外接收头将38K载波信号过虑,接收到的波形刚好与发射波形相反:
放大,位定义0和位定义1波形如下:
4、解码原理及算法
注:代码宽度算法:
16位地址码的最短宽度:1.12×16=18ms 16位地址码的最长宽度:2.24ms×16=36ms
可以得知8位数据代码及其8位反代码的宽度和不变:(1.12ms+2.24ms)×8=27ms
所有32位代码的宽度为(18ms+27ms)~(36ms+27ms)
对于红外线遥控对于很多电子爱好者来讲,都感觉到非常神奇,看不到,摸不着,但能实现无线遥控,其实控制的关键就是我们要用单片机芯片来识别红外线遥控器发出红外光信号,即我们通常所说的解码。单片机得知发过来的是什么信号,然后再做出相应的判断与控制,如我们按电视机遥控器的频道按钮,则单片机会控制更换电视频道,如按的是遥控器音量键,则单片机会控制增减音量。
解码的关键是如何识别“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左右均可。根据码的格式,应该等待9ms的起始码和4.5ms的结果码完成后才能读码。
5、实例代码:
注意一下几点:
1. 从上面“红外接收头与单片机连接原理图”来看,红外接收头的型号脚是与51的int0相连,所以需要使用INT0(外部中断0).
2. 由于解码过程中涉及到延时,为精确起见,我们选择使用定期时1来计时。
;汇编程序(已调试)
org 000h
ljmp main
org 0003h
ljmp in0zd ;外部中断0入口
org 000Bh
ljmp t0zd;定时器T0
org 0100h
;主程序
main:clr p2.0 ;选择数码管第一位(共阴)
setb IT0 ;定时器T0设置
setb EX0
setb ea
mov TMOD,#02h ;T0工作在方式2
mov TH0,#00h ;
mov TL0,#00h ; T0赋予初值
setb ET0 ;打开中断
setb p3.2 ;置位3.2
setb tr0 ;tr0置位
main1: acall yyi ;寄存器际初始化
pp:jnb 20h.0,pp;判断有无信号
clr 20h.0 ;有则清零20H.0
acall js ;调用中断2处理程序
acall jy ;接受到的数据是否正确,并显示
sjmp main1 ;跳转到MAIN1?
;int0中断处理1
in0zd: jb 20h.1,js ;判断20H.1是1还是0.是1跳转JS(进入数据处理) 是0说明接收的是引导码
cjne r7,#33h,next ; 为0,判断引导码是否正确 (33h<r7<4fh)
next:jc exit ;引导时间大于13.045MS 小于20.224ms,引导码正确。否则引导码无效。
cjne r7,#4fh,next1
next1:jnc exit
setb 20h.1 ;若正确 置位20H.1
exit:mov r7,#00h ; 并清除R7
reti
;中断处理2
js:cjne r7,#08h,next2 ;判断接受的数据是1还是0
next2:jnc ol ;若大于=2.048ms (0.256ms*8)则为1
clr cy ;0处理程序
mov a,@r0 ;接受到的0,送入存储
rlc a
mov @r0,a
sjmp exit1
ol: ;为1处理
setb cy
mov a,@r0 ;假设接受的第6个数据为1,以前的数据是@R0=00001001,
rlc a ;带进位的左移 执行后A=00010011
mov @r0,a ;送回保存
exit1:
djnz r6,exit ;判断一个字节接受完否?若没有 清楚R7,进行下8位数据接受
mov r6,#08h
inc r0
djnz r5,exit ;判断32位数据接受完否?若没有 清楚R7,进行下8位数据接受
clr 20h.1 ;清楚20H.1
setb 20h.0 ;置位接收完标志位
ret
;错码检验显示
jy:mov a,33h ;数据接收是否正确
cpl a
cjne a,32h,tch ;数据码和反码是否一样 ,不一样弃掉
xs:cjne a,#68h,tch1 ;一样 键值处理
mov p1,#3fh ;显示0 (数码管事共阴)
sjmp tch
tch1:cjne a,#30h,tch2
mov p1,#06h ;显示1
sjmp tch
tch2:cjne a,#18h,tch3
mov p1,#5bh ;显示2
sjmp tch
tch3:cjne a,#7ah,tch4
mov p1,#4fh ;显示3
sjmp tch
tch4:cjne a,#10h,tch5
mov p1,#66h ;显示4
sjmp tch
tch5:cjne a,#38h,tch6
mov p1,#6dh ;显示5
sjmp tch
tch6:cjne a,#5ah,tch7
mov p1,#7dh ;显示6
sjmp tch
tch7:cjne a,#42h,tch8
mov p1,#07h ;显示7
sjmp tch
tch8:cjne a,#4ah,tch9
mov p1,#7fh ;显示8
sjmp tch
tch9:cjne a,#52h,tch
mov p1,#6fh ;显示9
tch:ret
yyi: mov sp,#60h
mov r0,#30h
mov r6,#08h
mov r7,#00h
mov r5,#04h
ret
;T0中断处理
t0zd:
inc r7
reti
;C程序(注意:尚未调试)
#include
#include
// 函数原型
void SystemInit(void);
void Delay_840us(void);
void Delay_2400us(void);
void LedDisp();
unsigned char GetCode(void);//获得码
void delay(unsigned char loop);
// 位变量
sbit IRIN = P3^2;
sbit BEEP = P1^6;
sbit swch = P1^7;
// 变量
unsigned char KeyValue; //机器码
unsigned char MaValue; //键值码;
unsigned char disbuf[4]; //数码管显示缓冲
unsigned char scan[4]={0x04,0x08,0x10,0x20}; //p2位选择
unsigned char code table[16] = //共陰碼
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7C,0x39,0x5E,0x79,0x71};
/**
* 延时
*/
void delay(unsigned char loop)
{
unsigned char i;
for(i=0;i>8);
TR1=1;
while(!TF1);
TF1=0;
TR1=0;
}
/**
* 延时9ms
*/
void Delay_9000us(void)
{
TL1 = 153.6;
TH1 = 223.6;
TR1 = 1;
while(!TF1);
TF1 = 0;
TR1 = 0;
}
/**
* 延时4.5ms
*/
void Delay_4500us(void)
{
TH1 = 239.8;
TL1 = 204.8;
TR1 = 1;
while(!TF1);
TF1 = 0;
TR1 = 0;
}
/**
* 系统初始化
*/
void SystemInit(void)
{
IRIN = 1; //外断0请求中断输入脚
IT0 = 1; //INT0负跳变触发
TMOD = 0x10; //定时器1工作在方式1,16位定时计数器。
EA = 1; //允许中断
EX0 = 1; //允许外断0允许位
}
/**
* 读码
*/
unsigned char GetCode()
{
unsigned char n;
static temp = 0;
for( n = 0; n < 8; n++ )
{
while(!IRIN); // 等待高电平,开始解码。IRIN=1退出循环
Delay_840us(); // 延时0.84ms
if(IRIN) // 若仍然为高电平,则为1,否则为0
{
temp = (0x80|(temp>>1)); // 1
while(IRIN); //等待跳变成低电平
}
else {
temp=(0x00|(temp>>1)); // 0
}
}
return temp;
}
/**
* 数码管显示
*/
void LedDisp()
{
unsigned char i;
for(i=0;i<4;i++)
{
P0=table[disbuf[i]];
P2 = scan[i];
delay(50);
P0=0x00;
}
}
void main(void)
{
SystemInit();
while(1)
{
//以下是查表显示
disbuf[0]=(((KeyValue&0xf0)>>4)&0x0f);
disbuf[1]=KeyValue&0x0f;
disbuf[2]=(((MaValue&0xf0)>>4)&0x0f);
disbuf[3]=MaValue&0x0f;
LedDisp();
}
}
void interr_ir(void) interrupt 0
{
/**
* 用户码和机器码
*/
unsigned char addrl,addrh,num1,num2;
EA = 0; //先关闭外部中断0
Delay_9000us(); // 检测9ms开始码
if (IRIN) { // 检测是否为干扰信号
EA = 1; // 重新开启外部中断0
return ; // 退出解码
}
while(!IRIN); // 等待跳为高电平
Delay_4500us(); // 检测4.5ms结果码
if (IRIN) { // 检测是否为干扰信号
EA = 1; // 重新开启外部中断0
return ; // 退出解码
}
// 读码
addrl=GetCode(); // 用户编码高位
addrh=GetCode(); // 用户编码低位
num1=GetCode(); // 机器码
num2=GetCode(); // 机器码反码
//校验是否为错码
if(num1!=~num2)
{
KeyValue=14;
EA=1;
return;
}
KeyValue=num2;
MaValue=addrh;
EA=1;
}
代码分析(只分析关键部位):
1. 系统初始化SystemInit()
系统初始化时,我们设置IRIN为高电平,同时把IT0设置成1,即下降沿(负跳变)触发中断。这是用于接收波形的引导码是从低电平开始的(如上面接收波形所示)。这样,当按下按键时,红外接收到信号,IRIN则发生从预先设置的高电平跳为低电平,从而产生中断。
2. 解码--中断程序 interr_ir(void)
首先,第一步把EX0关中断,这步至关重要,因为一个接收波形许多的下降沿,这样会产生干扰中断。
接下来,使用定期时0延时9ms,跳过开始码。注意,延时后,需要检测一下干扰信号。
下一步,while(!IRIN); 等待4.5ms高电平的到来,再延时4.5ms,跳过结果。
引导码过后, 开始读码,执行GetCode():
32位数据码,分4次读取,所以执行4次GetCode(),读取一个字节数据过程如下:
unsigned char GetCode()
{
unsigned char n;
static temp = 0;
for( n = 0; n < 8; n++ )
{
while(!IRIN); // 等待高电平,开始解码
Delay_840us(); // 延时0.84ms
if(IRIN) // 若仍然为高电平,则为1,否则为0
{
temp = (0x80|(temp>>1)); // 1
while(IRIN); //等待跳变成低电平
}
else {
temp=(0x00|(temp>>1)); // 0
}
}
return temp;
}
1. 从上述位定义看,位0和位1都是0.56ms的低电平过后,高电平开始延时。所以,读码的第一步while(!IRIN);是等待这个0.56ms的低电平之后的高电平。
2. 从高定平到后开始延时0.84ms
3. 判断0.84ms的波形高电平还是低电平。若仍然是高电平证明,该位为“1”,否则为“0”。
到这里读码结束。
3. 校验
由于32位数据码中,后两个字节是键数据码和健数据反码。可以通过这两个字节数来实行校验。即,把前一个字节去反判读是否等于后一字节。
展开阅读全文