红外遥控器的解码
实测距离10米时不会错误或需要重复按遥控器 (*^__^*) ……
接收头
(原文件名:接收头.jpg.jpg)
正确解码
(原文件名:20110103426.jpg)
第一行显示的是:地址码+地址码+操作码+操作码反码 接受数据正确时第二行显示OK 旁边的数字是连_发次数
错误解码
(原文件名:20110103427.jpg)
第一行显示的是:地址码+地址码+操作码+操作码反码 接受数据错误时第二行显示error 旁边的数字是连_发次数
51开发板配的万能遥控器
(原文件名:20110103428.jpg)
if(timeout) //如果超时
{
TL0=TIMER0_COUNT; //初始化定时器0
初始化定时器0这一句可以去掉,因为TMOD=0x02。
-----------------------------------------------------------------------
谢谢 你的意思是自动重载方式无需初始化定时器0?
-----------------------------------------------------------------------
不是啊...
贴上我参考您的程序,改写的一个版本。
/*
CPU-XTL :89S52-12MHz
红外编码方案: NEC upd6121,upd6122;PT2222; SC6121; HS6221,HS6222
编码格式:引导信号(或连_发信号)+地址码1+地址码2+数据码+数据码反码
引导码:9ms低电平+4.5ms 高电平
连_发码:9ms低电平+2.25ms高电平
数据0:0.56ms低电平+0.56ms高电平
数据1:0.56ms低电平+1.69ms高电平
2011.1.24 OK
*/
#include<LCD1602.h> //包含延时函数Delay.h
/* 宏定义*/
/* 由于遥控器和程序存在一定误差,须允许编码时长有一定的范围便于调试*/
/******************************************************************/
//#define IR_ADDR1 0x00 //本机地址1
//#define IR_ADDR2 0xFF //本机地址2
#define GTime 39 //引导码最短时长 39*225us=8775us=8.775ms[9ms]
#define CTime 100 //连_发码最短时长 39-> 100
#define D0MinTime 3 //数据0 最短时长 平均5*225us=1125us=1.125ms
#define D0MaxTime 7 //数据0 最长时长 0.56ms+0.56ms=1.120ms
#define D1MinTime 8 //数据1 最短时长 平均10*225us=2250us=2.25ms
#define D1MaxTime 12 //数据1 最长时长 0.56ms+1.69ms=2.25ms
#define TIMER0_COUNT 0x1f //定时器定时时间 12MHz-225us 0x1f=31
#define TimeOut_cnt 250 //超时时长 250*225us=56250us=56.25ms
/*全局公共变量*/
static unsigned char T0_CNT; //定时器计数值
static unsigned char T0_CNT_bk; //计数备份
static bit TimeOut; //超时标志
static bit Guide; //引导码有效
static bit Continuous; //连_发码
static unsigned char IR_Time[33]; //保存每两个下降沿之间的时间间隔
/*结构体*/ /* 保存一次解码后接收到的四字节数据*/
static struct IR_data //红外接收的数据结构
{ unsigned char addr1; //地址1(客户码1)
unsigned char addr2; //地址2(客户码2)
unsigned char data1; //数据1(数据码)
unsigned char data2; //数据2(数据码反码)
}IR_DATA;
//unsigned char IR_KeyValue; //红外遥控器键值
/*LCD显示用ASCII字符表*/
unsigned char code ASCII_Tab[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
/* 看门狗2011.1.21*/
sfr WatchDogTimer = 0xC1;
sbit BEEP=P1^0; /* BEEP */
static unsigned char nKey; //正确解码的次数,用于键值处理2011.1.25
/******************************************************************/
/* 函数声明*/
void Timer0_Init(void); //定时器0初始化
void EX1_Init(void); //外部中断1初始化
void Decode(void); //解码子程序
void get_IRkey(void); //键处理
void display_keyValue(void); //显示从遥控器接收到的数据
void display_Continuous(void); //显示连_发次数
void SysInit(void); //系统初始化
/******************************************************************/
/*函数定义*/
/*定时器0初始化: 定时值:225us 12MHz(11.0592MHz) ;方式2 自动重载 重载值31(0X1F)*/
void Timer0_Init(void)//定时器0初始化
{ TMOD=0x02;//定时器0工作方式2 自动重载
TH0=TIMER0_COUNT; //重载值
TL0=TIMER0_COUNT; //初始化值
ET0=1; //定时器0中断有效
TR0=1; //定时开始
}
/******************************************************************/
/*Timer0中断子程序*/
void Timer0_Int(void) interrupt 1 using 1
{ T0_CNT++;
if(T0_CNT>TimeOut_cnt) TimeOut=1; //超时标志
}
/******************************************************************/
/*外部中断1初始化:外部中断1 P3.3,触发方式:下降沿*/
void EX1_Init(void)
{ EA = 1; //总中断开
IT1 = 1; //指定外部中断1下降沿触发,INT1 (P3.3)
EX1 = 1; //开外部中断1
}
/******************************************************************/
/* 外部中断1函数,下降沿触发*/
void EX1_Int(void) interrupt 2 using 0
{ static unsigned char m=0;
T0_CNT_bk=T0_CNT; //备份时间计数值,即前一个下降沿到本下降沿的时间间隔
T0_CNT=0x00; //清空时间计数值
if(TimeOut) //如果超时
{// TL0=TIMER0_COUNT; //初始化定时器0 -0x1f(31)
TimeOut=0; //清除超时标志
m=0; //复位数据位
T0_CNT=0x00; //清空时间计数值
Guide=0; //清除引导标志
Continuous=0; //清除连_发标志
}
else //正常按键时长58.5ms~76.5ms
{ if(Guide|Continuous) //如果引导码有效
{ IR_Time[m++]=T0_CNT_bk; //保存时间间隔
if(m==32) //接收够32数据后
{ m=0;
Guide=0; //清除引导标志
/*进行解码操作*/
Decode(); //解码
nKey++; //正确解码的次数,用于键值处理2011.1.25
}
}
if(T0_CNT_bk>GTime) //如果时间间隔>引导码时长
{ Guide=1; m=0; };//使能引导标志
if(T0_CNT_bk>CTime) //如果时间间隔>连_发码时长
{ Continuous=1; //使能连_发标志
EX1=0; //关外部中断1
/**此处加入连_发操作代码**/
display_Continuous();
EX1=1; //开外部中断1
m=0;
}
}//end of 超时
}
/******************************************************************/
/*解码核心程序*/
void Decode(void)
{ unsigned char i=0x00,j,k;
static unsigned char *p; //指向结构体IR_DATA.XX的指针
EX1 = 0; //关外部中断1
/*/////////////////////////进行解码处理////////////////////////*/
p=&IR_DATA.addr1;
for(k=0;k<4;k++)
{ for(j=0;j<8;j++)
{ if((IR_Time>D0MinTime)&(IR_Time<D0MaxTime))
{ *p>>=1; *p&=0x7f;}//右移1位, //与0111 1111置0. 数据“0” 0.56ms低电平+0.56ms高电平
else if((IR_Time>D1MinTime)&(IR_Time<D1MaxTime))
{ *p>>=1; *p|=0x80;}//右移1位,//或1000 0000置1. 数据“1” 0.56ms低电平+1.69ms高电平
i++;
}
p++;
}
if(IR_DATA.data2==~IR_DATA.data1){ get_IRkey(); } /*提取按键值*///数据2=数据1反码
else { WriteStrTo1602(2,1,"Error!"); }; /**非本机遥控器或数据错误**/
/*/////////////////////////解码处理完毕////////////////////////*/
EX1 = 1; //重新开放外部中断1
}
/******************************************************************/
/*中断程序调用——红外遥控键处理函数。键值功能为用户自定义*/
void get_IRkey()
{ display_keyValue(); //显示从遥控收到的数据
}
/* 不同的遥控器各键值代码有不同的定义 eg.:
//0~9数字键
0-0x0D 1-0x0C 2-0x18 3-0x5E 4-0x08
5-0x1C 6- 0x5A 7-0x42 8-0x52 9-0x4A
//功能键
|<< 0x07 >|| 0x09 >>| 0x15 VOL- 0x16
VOL+ 0x19 CH+ 0x40 EQ 0x43 CH- 0x44
ON/FF 0x45 RETURN 0x46 MODE 0x47
*/
/******************************************************************/
/*按键处理函数,输入:接收到的数据码——结构体IR_DATA*/
void display_keyValue(void)
{ WriteCharTo1602(1,1,ASCII_Tab[IR_DATA.addr1/0x10]);
WriteCharTo1602(1,2,ASCII_Tab[IR_DATA.addr1%0x10]);
WriteCharTo1602(1,4,ASCII_Tab[IR_DATA.addr2/0x10]);
WriteCharTo1602(1,5,ASCII_Tab[IR_DATA.addr2%0x10]);
WriteCharTo1602(1,7,':');
WriteCharTo1602(1,9,ASCII_Tab[IR_DATA.data1/0x10]);
WriteCharTo1602(1,10,ASCII_Tab[IR_DATA.data1%0x10]);
WriteCharTo1602(1,12,ASCII_Tab[IR_DATA.data2/0x10]);
WriteCharTo1602(1,13,ASCII_Tab[IR_DATA.data2%0x10]);
WriteStrTo1602(1,15,"OK");
WriteStrTo1602(2,1,"U=");
WriteCharTo1602(2,3,ASCII_Tab[IR_DATA.addr1/0x10]);
WriteCharTo1602(2,4,ASCII_Tab[IR_DATA.addr1%0x10]);
WriteCharTo1602(2,6,ASCII_Tab[IR_DATA.addr2/0x10]);
WriteCharTo1602(2,7,ASCII_Tab[IR_DATA.addr2%0x10]);
WriteStrTo1602(2,13,"K=");
WriteCharTo1602(2,15,ASCII_Tab[IR_DATA.data1/0x10]);
WriteCharTo1602(2,16,ASCII_Tab[IR_DATA.data1%0x10]);
BEEP=0;
DelayNms(5);
BEEP=1;
}
/******************************************************************/
/*显示连_发函数*/
void display_Continuous(void)
{ static unsigned char n;
WriteCharTo1602(2,10,ASCII_Tab[n/0x10]);
WriteCharTo1602(2,11,ASCII_Tab[n%0x10]);
n++;
BEEP=0;
DelayNms(50);
BEEP=1;
}
/***************************************
* 名称 : SysInit()
* 功能 : 单片机初始化,设置定时器,中断,看门狗等初值
* 输入 : 无
* 输出 : 无
****************************************/
void SysInit(void)
{ /****************看门狗初始化************************/
WatchDogTimer = 0x3C; /*晶振在12M或11.0592M时,溢出时间为1s左右2011.1.21*/
/* 0011,1100 EN_WDT = 1,CLR_WDT = 1,IDLE_WDT = 1,PS2=1,PS1=0,PS0=0 */
/****************LCD1602显示器初始化*****************/
Initiate1602();
WriteStrTo1602(1,1,"IR Decode System");/*LOGO*/
WriteStrTo1602(2,1,"(c)");
WriteStrTo1602(2,8,"2011-1-24");
DelayNms(1500);
WriteCmdTo1602(0x01);/* 清屏 */
/****************外部中断1初始化**********************/
EX1_Init();
/****************定时器0初始化************************/
Timer0_Init();
/****************波特率初始化************************/
/****************其他硬件相关初始化******************/
}
/***************************************
* 名称 : main()
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
****************************************/
//主函数
void main(void)
{ SysInit();
while(1)
{ /*看门狗——喂狗2011.1.21*/
WriteCharTo1602(2,10,nKey+'0');
DelayNms(1000);
WatchDogTimer = 0x3C; //喂狗
}
}
******************************************************************/
/* 外部中断1函数,下降沿触发*/
void EX1_Int(void) interrupt 2 using 0
{ static unsigned char m=0;
T0_CNT_bk=T0_CNT; //备份时间计数值,即前一个下降沿到本下降沿的时间间隔
T0_CNT=0x00; //清空时间计数值
if(TimeOut) //如果超时
{// TL0=TIMER0_COUNT; //初始化定时器0 -0x1f(31)
TimeOut=0; //清除超时标志
m=0; //复位数据位
T0_CNT=0x00; //清空时间计数值
Guide=0; //清除引导标志
Continuous=0; //清除连_发标志
}
...
一周热门 更多>