本帖最后由 benbens 于 2015-7-15 00:19 编辑
前不久迷上了红外遥控解码,虽然自己在学校时曾经研究过,但一直没有搞清楚。温故而知新,加上得到一大神指点,让我茅塞顿开。
当一个红外遥控器的按键按下去时,共有四组数据发送出去了,第一组是低8位用户码, 第二组是高8位用户码,第三组是数据码, 第四组是数据反码。 用户码也叫引导码,用来区别不同的遥控器,数据码也叫按键码,用来区别不同的按键。数据反码就是数据码取反之后,用来进行数据校验的。
自己手头的有一块0802的液晶显示模块,刚好利用起来,做一个红外遥控码值测试的工具。 主控芯片用的是STC89C52RC单片机, 用它主要是因为这片单片机一直闲置在这里,大家也可以把程序移植到其它型号的单片机上(移植时注意延时函数)。想到只用来测试红外遥控码值太可惜这片单片机和0802液晶显示屏了,何不加上其它功能?手上有DS1302时钟芯片,用来做一个万年历在合适不过了,再用一个拨动开关来切换码值测试功能和时钟功能(拨动开关后要重启一下)。STC89C52RC有好多IO口,索性再加蜂鸣器和LED。
码值测试功能:当解码出四组数据后蜂鸣器滴一声,LED闪烁一下。
时钟功能:1.当按键按下蜂鸣器滴一声 2.每当到整点的时候,蜂鸣器滴一声(整点报时)。
以下是实物效果图:
依次是 年 月 日 星期 时 分
照片名称:红外解码-1
所属相册:电子DIY
首次开机,没有接收到红外信号时显示
照片名称:红外解码-3
所属相册:电子DIY
接收到红外信号并成功解码时
引导码:0x00ff 按键码:0x01 按键反码:0xfe
照片名称:红外解码-2
所属相册:电子DIY
整体效果图
照片名称:红外解码-4
所属相册:电子DIY
供电电源采取USB供电,直接插电脑或者手机充电器就行了。。。。
我是直接现场发挥,没有画电路图,大家也可以从我的程序里看出电路的连接,鉴于我菜鸟般的编程能力,我就不全部把程序公布出来,只给出关键程序。需要的童鞋也可以留下邮箱,我可以发给你。
1. IO接口定义
unsigned char IR_code[4] = {0,0,0,0};//存放四组数据
sbit fmq=P1^0;//蜂鸣器接口
sbit RS=P1^1;
sbit RW=P1^2;
sbit EN=P1^3;
sbit mode=P1^4;//模式选择接口
sbit IR_Out = P3^2; // 此口为红外信号输入MCU口
sbit led=P3^7;
sbit mos_key=P1^6;
sbit up_key=P1^5;
sbit down_key=P3^6;
sbit CE=P2^5; //DS1302片选口
sbit IO=P2^6; //DS1302数据口
sbit SCLK=P2^7; //DS1302时钟口
2. 0802液晶驱动程序
void write_com(unsigned char com) //写指令
{
RW=0;
RS=0;
EN=0;
P0=com;
EN=1;
delayms(5);
EN=0;
}
void write_dat(unsigned char dat)//写数据
{
RW=0;
RS=1;
EN=0;
P0=dat;
EN=1;
delayms(5);
EN=0;
}
void lcdIR_init()
{
EA = 1; // CPU准许中断
delayms(400);
write_com(0x3c); //8位数据总线,两行显示模式,5*10点阵
write_com(0x01); //清显示
write_com(0x0c); // 开显示,关闭光标,关闭闪烁
write_com(0x80);
write_dat('B');
write_dat('C');
write_dat(':');
write_com(0x80+5);
write_dat('-');
write_com(0xc0);
write_dat('K');
write_dat('C');
write_dat(':');
write_com(0xc0+5);
write_dat('-');
}
void lcdtime_init()
{
EA = 0; // CPU不准许中断
delayms(400);
write_com(0x3c); //8位数据总线,两行显示模式,5*10点阵
write_com(0x01); //清显示
write_com(0x0c); // 开显示,关闭光标,关闭闪烁
write_com(0x80);
write_dat(' ');
write_dat(' ');
write_dat('-');
write_dat(' ');
write_dat(' ');
write_dat('-');
write_dat(' ');
write_dat(' ');
}
3. 红外解码程序
/*------------------------------------------------------------*-
函数名称:Int0()
函数输入:无(容许中断时,外部触发)
函数输出:无
函数说明:外部中断0中断处理
-*------------------------------------------------------------*/
void Int0() interrupt 0
{
unsigned char i,j;
EX0 = 0; // 关闭外部中断0
i = 10; // 0.793ms延时,运行10次
while( --i )
{
// 定时0.793ms,延时0.793ms*10=7.93ms
Delay793us();
// 这7.93ms期间只要IR_Out变高电平,就非合法的红外信号,跳出
if( IR_Out )
{
EX0 = 1; // 准许中断
return ;
}
}
// 程序进行到这里,表明是合法的红外信号(利用9ms判断)
while( !IR_Out ); // 等待9ms低电平过去
// 程序进行到这里,表明经过9ms低电平
Delay2305us(); // 延时2.305ms
// IR_Out 为低表明是连发码,不予理睬,跳出
if( !IR_Out )
{
EX0=1;
return;
}
// 程序进行到这里,表明是引导码,等待4.5ms高电平的过去
while( IR_Out );
// 开始接收四组数据
for(i=0; i<4; i++)
{
for(j=0; j<8; j++)
{
while( !IR_Out ); // 等待低电平过去
IR_code[ i] >>= 1; // 把上次的数据位右移一位
Delay793us(); //延时0.793ms
// 若为数据"1",则延时后IR_Out为高电平
if( IR_Out )
{
IR_code[ i] |= 0x80; // 所有数据位1放最高位
while( IR_Out ); // 等待高电平过去
}
}
}
//IR_code[0]低8位用户码,IR_code[1]高8位用户码,IR_code[2]为数据码,IR_code[3]为数据反码----dat为二进制
if (IR_code[2]!=~IR_code[3]) //数据码校验
{
EX0=1;
return;
}
fmq=led=0;
diaplay_IRcode(0,0x80+3);
diaplay_IRcode(1,0x80+6);
diaplay_IRcode(2,0xc0+3);
diaplay_IRcode(3,0xc0+6);
EX0=1; // 开中断
return;
}
4. 主函数
void main()
{
IR_Out = 1; // 此口为MCU输入口,故需要置1
IT0 = 1; // 外部中断0,下降沿触发
EX0 = 1; // 准许外部中断
while(1)
{
while(mode==1)
{
lcdIR_init();
while(1)
fmq=led=1;
}
while(mode==0)
{
lcdtime_init();
while(1)
display_settime();
}
}
}
|