/***************************************
程序名:
红外遥控器解码
硬件:
MCU:
STC89C52,11.0592MHZ
红外:
遥控器:
电视遥控器
接收器:
VS1838B一体化红外接收头,38KHZ
,接INT0
数码管:
1位共阴,位选、数据均接P0,由两片
74HC573控制。
说明:
μPD6121G型遥控器编码协议:
启动码->16位地址->8位数据->8位数据反码
数据位为先低电平,在高电平。
启动码:9ms+4.5ms=13.5ms
‘0' 0.565ms+0.56ms=1.125ms
'1': 1.685ms+0.56ms=2.245ms
采用外部中断配合定时器解码,外部中断
INT0捕获红外脉冲下降沿,则捕获两次即
为一个周期,将两次定时器计数值相减,
所得时间即为周期时间。因所用晶振为
11.0592MHZ,此值需做变换后才得真实周
期,但也没必要,只需要将真实周期做
相反变换后,和测量值相对应即可。
变换公式为:12/11.0592*time=period
如period=1125us,则time=1036.8=1036
程序只要检测到time=1036则认定为‘0’,
当然允许在小范围波动。详见INT0中断。
检测到数据后,依次按从低到高位送
rcv_buf[4]数组暂存。rcv_buf[0],
rcv_buf[1]为地址,rcv_buf[2]为数据,
rcv_buf[3]为数据反码。
****************************************/
#include <at89x51.h>
#include "led.h"//包含led[],数码管段码,共阳
//uart配置
#define F_OSC 11059200L//时钟频率
#define BAUD 57600//波特率
#define S_MOD 1//加倍
#include "uart51.h"//uart头文件
uint told=0,tnew,time;//old time,new time,周期time
uchar count=0,rcv_buf[4],i,tmp1,tmp2;//位计数,数据数组,i=0~4,暂存TH0,TL0
bit f_rcv=0,f_handle=0,bit1;//启动码已收到可以接收数据,可以执行,暂存接收位
/****************************************
函数名:I/O端口初始化
说明:
P0:数码管; P2:74HC573; P3:INT0
****************************************/
void PortInit()
{
P0=0xfe;//只用最低位数码管
P2_7=1;//锁存
P2_7=0;
P0=0x00;//初始化关闭
P2_6=1;//锁存
P2_6=0;
P3=0xff;//INT0
}
/****************************************
函数名:定时器初始化
说明:
T0自由计数,不开放中断
****************************************/
void TimerInit()
{
TMOD|=0x01;
TH0=0x00;
TL0=0x00;
TR0=1;
}
/****************************************
函数名:外部中断初始化
说明:
INT0。边沿(下降沿)触发,开放中断
****************************************/
void INT0Init()
{
IT0=1;
EX0=1;
EA=1;
}
/****************************************
函数名:INT0中断
说明:
解码核心部分。首先检测启动码,成功后,
置f_rcv标志,检测到f_rcv后,解码数据。
循环32次,解码完成,置f_handle,通知主
程序处理。若中途出现错误码,则放弃当前
解码过程,重新检测启动码,再解码。
调试用信息已注释掉。可自行修改。
1.125ms->1036.8
2.245ms->2068.992
13.5ms->12441.6
****************************************/
void ISR_INT0() interrupt IE0_VECTOR
{
tmp1=TH0;//暂存TH0,TL0
tmp2=TL0;
tnew=(uint)(tmp1<<8)+tmp2;//newtime等于当前定时器值
//计算脉冲周期。两种情况:1. new time>old time,定时
//器未溢出,time=tnew-told; 2.new time<old time,定时
//器溢出,time=65536-told+tnew。如’0‘=1036,1.tnew
//=60000,told=58964,tnew>told,直接相减即得time;
//2.tnew=100,told=64600,T0溢出一次,tnew<told。需
//65536+tnew-told=time
if(tnew>=told)
time=tnew-told;
else
time=65536-told+tnew;
//Putc(time>>8);//发送time
//Putc(time&0x00ff);
if(f_rcv==1)//标志置位,接收数据
{
if(time>1600 && time<2400)//'1',要有一定裕量,不可能那么精确
{
bit1=1;
//Putc('1');
}
else
if(time>600 && time<1400)//'0'
{
bit1=0;
//Putc('0');
}
else
{
bit1=0;
f_rcv=0;
count=0;
return;//错误码,放弃返回
}
//存数据
rcv_buf[count/8]>>=1;
rcv_buf[count/8]|=(uchar)bit1<<7;
if(++count==32)//接受完
{
count=0;
f_rcv=0;
//Putc(' ');
/*for(i=0;i<4;i++)//发送全部代码
{
Putc(rcv_buf[i]);
}*/
//Putc(rcv_buf[2]);//发送数据代码
f_handle=1;
}
}
if(!f_handle && time>11800 && time<13000)
f_rcv=1;
told=tnew;
}
/****************************************
函数名:主函数
说明:
初始化、代码显示
****************************************/
void main()
{
//初始化
PortInit();
TimerInit();
UartInit();
INT0Init();
while(1)
{
if(f_handle)//可执行标志
{
f_handle=0;
//0~9:92 87 86 85 8B 8A 89 8F 8E 8D
//送数码管显示
switch(rcv_buf[2])
{
case 0x92:
P0=~led[0];
break;
case 0x87:
P0=~led[1];
break;
case 0x86:
P0=~led[2];
break;
case 0x85:
P0=~led[3];
break;
case 0x8b:
P0=~led[4];
break;
case 0x8a:
P0=~led[5];
break;
case 0x89:
P0=~led[6];
break;
case 0x8f:
P0=~led[7];
break;
case 0x8e:
P0=~led[8];
break;
case 0x8d:
P0=~led[9];
break;
}
P2_6=1;//锁存
P2_6=0;
}
}
}
- 1
- 2
前往页