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;
		}
	}			
}

  

 

posted @ 2022-02-28 22:39  xiaoberber  阅读(747)  评论(0编辑  收藏  举报