车载红外遥控之51单片机解码
对单片机的了解学习,是作为简单的遥控器解码学习的基础,因为本次DIY是通过MCU作为解码媒介的。但实验中的DIY方式又不必需要功能强大的ARM系列单片机去实现,一般0851单片机就能解决。
本实验的演示功能是通过对红外遥控键值解码后,对设定的目标键值做出响应,实验中的响应是单片机对继电器的开合、通断控制,可以简单理解为单片机检测到遥控器某个指定的按键按下,则控制继电器实现开关的切换功能,实现过程如下:
Figure 1原理图
首先是选型,由于物资条件,我们考虑成本,
所以选择的都是廉价器件,器件有车载MP3红
外遥控,1318红外接收头,51系列的stc15F104w
芯片,一个11.0592MHZ的晶振,两个100pf的电
容,一个继电器,一个二极管1N4148,一个PNP三极管9012/S8550,两个200欧姆电阻。
其次是电路搭建,电路通过红外遥控接收头,将接收到的遥控编码信息发送至单片机,单片机对红外遥控的键值解码后在P3.5口输出控制信
号,控制继电器的开关效果。具体的电路原理图见
原理图所示。
最后,实现解码功能的51程序流程图如右图
所示:首先硬件上电,软件初始化外部中断,初始
化定时器配置,之后是不断地轮询单片机的中断引
脚,检测单片机的引脚状态是否改变,如果引脚状态被改变了,说明端口有数据到来,此时单片机的定时器将在中断中被激活。定时器被激活的作用是用来给给每个二进制数据位进行定时的,将高低电平状态产生的时间存储到一个数组里面,最后将该时间值数组转换成高低电平状态。
左图是红外遥控采集单片机中断引脚的高低电平时间,并将得到的时间放在irdate数组里,我们使用的红外遥控的编码是32位的编码。由引导码、用户码、数据码和数据码反码组成32位的编码方式。实验测试得到,引导码是有9ms的高电平和4.5ms的低电平组成。用户码或数据码中的每一个位可以是位‘1’,也可以是位‘0’。区分‘0’和‘1’是利用脉冲的时间间隔来区分,这种编码方式称为脉冲位置调制方式。英文简写PPM。其脉冲调制是使用455KHz晶体产生的载波脉冲实现。
总结:通过本次实验,了解到了红外遥控编码及解码的工作原理。并实践应用51单片机解码实现继电器的吸合开关电路控制。实验中用到了单片机的外部中断配置和单片机的定时器配置。
具体代码如下
hwjm.c
#include<stc15f104w.h> #include"hwjm.h" #include"delay.h" #include"music.h" uchar irreceok;//一整数据接收完毕 uchar irprosok; unsigned char b; extern unsigned char b; //uchar irtime,irtime1;//第一步时间存储 uchar irtime; //第一步时间存储 uchar startflag; uchar bitnum; uchar ircode[4]; extern unsigned char Count; extern uchar smg_gyangji[]; //uchar display[8]; uchar irdate[33];//接收数组此为一些时间变量;0.25ms或者2.256ms uchar anjianjiema[]={0x16,0x0c,0x18,0x5e,0x08,0x1c,0x5a,0x42,0x52,0x4a};//0-7; uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; //uchar smg_gyangji[]={ //0xC0,0xF9,0xA4,0xB0, //0x99,0x92,0x82,0xF8, //0x80,0x90,0x88,0x83, //0xC6,0xA1,0x86,0x8E //}; //////////////红外接收到数据的数据函数//////////////////////// void hwxm_irrece(void) { if(startflag)//第一次红外数据为引导码不起作用所以startflag为0直接跳过 { if(irtime>30)//检测引导吗; { bitnum=0; } irdate[bitnum]=irtime;//存的是时间0.25/0.256或是2.25/0.256时刻提取计时器实计数 irtime=0; bitnum++;//红外接收数据数组下标每次检测到一次下降沿引发中断时加一 if(bitnum==33)// { bitnum=0; irreceok=1;//档主函数判断是否当一次红外数据发送并接收完毕 } } else { startflag=1;//中断触发后中断标志变量startflag将一直为1; irtime=0; } } void hwxm_irpros(void) { uchar k,i,j; uchar value; k=1;//只提取用户吗;4*8=32位; for(j=0;j<4;j++)//四个码 { for(i=0;i<8;i++)//每个码有8位 { value=value>>1;//7ci第一次vlalue等于0右移后等于0; if(irdate[k]>6) { value=value | 0x80;//10000000 } k++; } ircode[j]=value;//为2进制 } irprosok=1;//对时间转化成2进制的转换完毕; }
int.c
#include<stc15f104w.h> #include"int.h" #include"hwjm.h" extern uchar ircode[4]; extern unsigned char Count; unsigned char Temp2; sfr T2MOD=0xc9; void timer0init(void) //计时器零初始化 { EA=1; ET0=1; TH0=0X00; TL0=0X00;//工作方式0 TMOD=0X02; TR0=1; } void timer1init(void) //计时器1初始化//最大值是255 { EA=1; ET1=1; T2H=0XDC; T2L=0X00; T2MOD=0X02;//工作方式2,8位初值自动重装8位定时器/计数器 TR1=1; } void int0init(void)//中断0初始化函数 { EA=1; EX0=1; IT0=1; //为跳变触发方式,电平从高到低的负跳变有效IT0=0时为低电平有效的电平触发方式 } //////////////////////////////////////////////////////////////////////// ///////////计时器0服务函数////////////////// void timer0() interrupt 1 { irtime++; } void timer1() interrupt 3 { TH1 = 0xDC; TL1 = 0x00; Count++; } ///////中断服务函数//////////////// void int0 () interrupt 0//外部中断 服务函数 { hwxm_irrece(); hwxm_irpros(); if(ircode[2]==0x45||ircode[2]==0x47) Temp2 = Count; }
main.c
#include<stc15f104w.h> #include"delay.h" #include"music.h" #include"hwjm.h" #include"int.h" /////////////////////////////// extern unsigned char b; extern uchar ircode[4]; extern uchar smg_gyangji[]; extern uchar anjianjiema[]; unsigned char Count; extern uchar irreceok;//一整数据接收完毕 extern uchar irprosok; sbit JD=P3^0; sbit D=P3^1; void main(void) { timer1init(); timer0init(); int0init(); P0=0xff; while(1) { unsigned char b; if(irreceok)//判断总中断服务函数中对接收时间的存储是否接收完眎rreceok为接收完毕标志位; { hwxm_irpros();//解码服务函数;将时间间隔大小转换成16进制数 irreceok=0;//解码是否完毕; } if(irprosok) { irprosok=0;//对时间做出相应的十六进制转化完成标志清零; for(b=0;b<10;b++) { if(ircode[2]==anjianjiema[b]) { delay_50us(2); if(ircode[2]==anjianjiema[0]) { JD=1; D=1; } else { JD=0; D=0; } } } } } }