51_红外遥控
红外遥控器,顾名思义,是通过红外光来进行数据传输的。被广泛应用在各种家电产品上,例如电视、空调、车载MP3等。它是如此的普遍,以至于让人都快忘记了它的存在。 只要温度高于绝对零度(-273.15°C)的物体都会发出红外光,因此它无处不在。因此,使用红外光进行通信时,需要对光波有一些特殊的要求,这样才能使它能够在众多的同类信号中被识别出来。 首先是波长,一般来说红外发射管发出的光波波长以850nm和940nm两种比较常见。 然后是频率,发射端以一个固定的频率来发射红外光,一般以37.91KHZ比较常见,也有的地方直接说成是38KHZ。同时,接收端只识别该频率下的信号,只要发射频率与接收频率正负相差不超过1KHZ,都可以正常工作;如果相差超过2KHZ,会出现失灵或者距离短等情况。
第二类接收管如图所示,也是要使用的接收管。和前面几种管子的最大区别在于它有三只脚,而功能也大大增强了。它的内部电路包括红外监测二极管,放大器,限幅器,带通滤波器,积分电路,比较器等。 通过内部电路,还原出发射端的信号波形,可以直接被单片机使用。因此也被称为一体化红外接收头。

也就是说,它输出的是符合数字电路要求的数字信号了,可以直接拿来使用。所以,虽然外型上只是多了一个引脚,但实际内部功能增加了很多很多,大大简化了电路设计者的工作。另外,此类接收头的内部放大增益比较大,很容易引起干扰,因此一般厂家建议在供电脚加上4.7uf以上的电容进行滤波。 常用型号有IRM3638、HS0038和VS1838等。其接口电路如图所示

这里使用的遥控器用的是NEC协议,因此这里着重讲解该协议下信号是如何传播的。首先,遥控器内部一般会使用455KHZ的晶体做为振荡源,通过内部分频电路将其调制为频率37.91KHZ、占空比三分之一的振荡信号。 遥控器闲置时,发射端无输出。当有按键按下时,会发送一串信号驱动红外发射端发射红外线,信号格式如下:一段引导码、两个字节的用户码(由厂家定义)、一个字节的按键数据、一个字节的按键数据反码,最后跟一个停止位(编程时基本不考虑)。

有两个事情要注意: 1、该图是遥控器发出的信号格式,并不是接收端收到的信号格式,两者是不一样的; 2、图中高电平的位置并不是真的高电平,而是被频率37.91KHZ、三分之一占空比的信号填充的。 那么接收端收到的信号是什么样?首先,闲置状态下,它是高电平的。当收到37.91KHZ的红外光时,接收端调制出的信号是低电平,无红外光时,又恢复为高电平。所以,将上图中的信号全部取反,即为红外接收端输出的信号格式。
接下来,了解一下数据的传输过程中是如何定义0和1这两种状态的。以接收端的状态来考虑,空闲的状态下引脚输出高电平。 当表示一个bit位为0时,先输出一个0.56ms的低电平,然后输出一个0.565ms的高电平; 当表示一个bit位为1时,先输出一个0.56ms的低电平,然后输出一个1.69ms的高电平。


要想识别发送的指令是什么,就要先知道遥控器上每个按键对应的数据码是什么,而这部分内容,需要跟遥控器供应商索取。记住,即便是外形一模一样的遥控器,只要厂家不同,也有可能相同位置的按键数据码不一样。这里选购的遥控器用户码为0x00FF,按键对应的数据码如图所示

/*******************************************************************************
* 实验名 : 1602显示红外线值实验
* 使用的IO : 电机用P1口,键盘使用P3.0、P3.1、P3.2、P3.3
* 实验效果 : LCD1602显示出读取到的红外线的值
* 注意 :
*******************************************************************************/
#include<reg51.h>
#include"lcd.h"
sbit IRIN=P3^2;
unsigned char code CDIS1[13]={" Red Control "};
unsigned char code CDIS2[13]={" IR-CODE:--H "};
unsigned char IrValue[6];
unsigned char Time;
void IrInit();
void DelayMs(unsigned int );
/*******************************************************************************
* 函数名 : main
* 函数功能 : 主函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void main()
{
unsigned char i;
IrInit();
LcdInit();
LcdWriteCom(0x80);
for(i=0;i<13;i++)
{
LcdWriteData(CDIS1[i]);
}
LcdWriteCom(0x80+0x40);
for(i=0;i<13;i++)
{
LcdWriteData(CDIS2[i]);
}
while(1)
{
IrValue[4]=IrValue[2]>>4; //高位
IrValue[5]=IrValue[2]&0x0f; //低位
if(IrValue[4]>9)
{
LcdWriteCom(0xc0+0x09); //设置显示位置
LcdWriteData(0x37+IrValue[4]); //将数值转换为该显示的ASCII码
}
else
{
LcdWriteCom(0xc0+0x09);
LcdWriteData(IrValue[4]+0x30); //将数值转换为该显示的ASCII码
}
if(IrValue[5]>9)
{
LcdWriteCom(0xc0+0x0a);
LcdWriteData(IrValue[5]+0x37); //将数值转换为该显示的ASCII码
}
else
{
LcdWriteCom(0xc0+0x0a);
LcdWriteData(IrValue[5]+0x30); //将数值转换为该显示的ASCII码
}
}
}
/*******************************************************************************
* 函数名 : DelayMs()
* 函数功能 : 延时
* 输入 : x
* 输出 : 无
*******************************************************************************/
void DelayMs(unsigned int x) //0.14ms误差 0us
{
unsigned char i;
while(x--)
{
for (i = 0; i<13; i++)
{}
}
}
/*******************************************************************************
* 函数名 : IrInit()
* 函数功能 : 初始化红外线接收
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void IrInit()
{
IT0=1;//下降沿触发
EX0=1;//打开中断0允许
EA=1; //打开总中断
IRIN=1;//初始化端口
}
/*******************************************************************************
* 函数名 : ReadIr()
* 函数功能 : 读取红外数值的中断函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void ReadIr() interrupt 0
{
unsigned char j,k;
unsigned int err;
Time=0;
DelayMs(70);
if(IRIN==0) //确认是否真的接收到正确的信号
{
err=1000; //1000*10us=10ms,超过说明接收到错误的信号
/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
侯,程序死在这里*/
while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去
{
DelayMs(1);
err--;
}
if(IRIN==1) //如果正确等到9ms低电平
{
err=500;
while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去
{
DelayMs(1);
err--;
}
for(k=0;k<4;k++) //共有4组数据
{
for(j=0;j<8;j++) //接收一组数据
{
err=60;
while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
// while (!IRIN)
{
DelayMs(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0)) //计算高电平的时间长度。
{
DelayMs(1);//0.14ms
Time++;
err--;
if(Time>30)
{
EX0=1;
return;
}
}
IrValue[k]>>=1; //k表示第几组数据
if(Time>=8) //如果高电平出现大于565us,那么是1
{
IrValue[k]|=0x80;
}
Time=0; //用完时间要重新赋值
}
}
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
}
}
浙公网安备 33010602011771号