51单片机红外遥控

红外遥控:利用红外光进行通讯的设备,有红外LED讲调制后的信号发出,由专门的红外接收头进行解调输出。由单工异步的通讯方式进行通讯。通信协议标准是NEC标准。(红外LED标准940nm)

硬件电路
在这里插入图片描述
解释:IN引脚是我们要发送波形信息的引脚,38KHZ是调制的信号加载到IN的波形上的。采用两个PNP三极管的串联,使当两个三级管的基极同时为低电平时LED才亮。
亮灭变化:当IN为高电平时,LED不发光,当IN为低电平时,LED按照38KHZ的频率,当为低电平时发光,高电平时不发光。
加上38KHZ的调制波形是为了与自然光区别,当红外光接收器接收信号时会通过滤波电路把38KHZ的波形滤掉,保留信息发送引脚发送的波形信号。

在这里插入图片描述使用一个IN引脚模拟上面所讲的时序也行

接收装置:
在这里插入图片描述为了保证红外光接收装置接收信息的准确性,不使用IF语句,使用响应更为快送的外部中断处理。

tip:
在这里插入图片描述在实际运用中,我们只需控制IN引脚发送的信号,38KHZ的频率是底层配置好的。

基本发送与接收
IN空闲状态:红外LED不亮,接收头输出高电平。
IN低电平:红外LED以38KHZ闪烁发光,接收头输出低电平
IN高电平:红外LED不亮,接收头输出高电平。

遥控器键码值
在这里插入图片描述

NEC协议
1、起始信号:由9ms的低电平和4.5ms 的高电平组成。
2、数据格式:地址码+地址码反码+命令+命令反码(都是8位的数据,发送时低位在前高位在后

//外部中断0中断函数,下降沿触发执行
void Int0_Routine(void) interrupt 0
{
	if(IR_State==0)				//状态0,空闲状态
	{
		Timer0_SetCounter(0);	//定时计数器清0
		Timer0_Run(1);			//定时器启动
		IR_State=1;				//置状态为1
	}
	else if(IR_State==1)		//状态1,等待Start信号或Repeat信号
	{
		IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间
		Timer0_SetCounter(0);	//定时计数器清0
		//如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
		if(IR_Time>13500-500 && IR_Time<13500+500)
		{
			IR_State=2;			//置状态为2
		}
		//如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
		else if(IR_Time>11250-500 && IR_Time<11250+500)
		{
			IR_RepeatFlag=1;	//置收到连发帧标志位为1
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
		else					//接收出错
		{
			IR_State=1;			//置状态为1
		}
	}
	else if(IR_State==2)		//状态2,接收数据
	{
		IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间
		Timer0_SetCounter(0);	//定时计数器清0
		//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
		if(IR_Time>1120-500 && IR_Time<1120+500)
		{
			IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));	//数据对应位清0
			IR_pData++;			//数据位置指针自增
		}
		//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
		else if(IR_Time>2250-500 && IR_Time<2250+500)
		{
			IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));	//数据对应位置1
			IR_pData++;			//数据位置指针自增
		}
		else					//接收出错
		{
			IR_pData=0;			//数据位置指针清0
			IR_State=1;			//置状态为1
		}
		if(IR_pData>=32)		//如果接收到了32位数据
		{
			IR_pData=0;			//数据位置指针清0
			if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3]))	//数据验证
			{
				IR_Address=IR_Data[0];	//转存数据
				IR_Command=IR_Data[2];
				IR_DataFlag=1;	//置收到连发帧标志位为1
			}
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
	}
}

代码实现思路
使用状态位IR_State,IR_State0表示空闲状态,IR_State1表示等待Start信号或Repeat信号,IR_State2表示接收信号。
上篇说到为了响应迅速故使用外部中断,由于每个数据位的发送都是以下降沿结束,所以使用下降沿触发的外部中断。因为数据位0或1是由高低电平的时间决定,所以使用定时器定时时间来确定数据位是多少。
红外线接收装置的OUT引脚连接到了外部中断引脚上,当接收装置接收到红外线信号时将会进入外部中断函数。
首次进入到中断函数中,已经产生了外部中断,此时把IR_State置为1进而判断是Start信号还是Repeat信号。进入中断后可能是开始信号也可能是重复信号,差别是中断时间的不同 ,因此判断时间的多少就可以识别出是开始信号还是结束信号。判断时间时在保证时间不会交集的情况下可以判断时间的范围,因为定时也不一定准确,
若判断的时间长度为开始信号时间的长度,IR_State置为2,判断的时间长度为重复信号时间的长度,IR_State置为0,如果这两个都不是,说明接收出错,则把这次接收结果舍去,IR_State清零,准备下次接收。
当IR_State
2时,说明已接受到开始信号,准备开始接收数据。组成数据的“0”,“1”码是根据高低电平的持续时间确定的,所以只要检测定时器的计数值就能确定数据。
采用了以下算法:

else if(IR_State==2)		//状态2,接收数据
	{
		IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间
		Timer0_SetCounter(0);	//定时计数器清0
		//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
		if(IR_Time>1120-500 && IR_Time<1120+500)
		{
			IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));	//数据对应位清0
			IR_pData++;			//数据位置指针自增
		}
		//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
		else if(IR_Time>2250-500 && IR_Time<2250+500)
		{
			IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));	//数据对应位置1
			IR_pData++;			//数据位置指针自增
		}
		else					//接收出错
		{
			IR_pData=0;			//数据位置指针清0
			IR_State=1;			//置状态为1
		}
		if(IR_pData>=32)		//如果接收到了32位数据
		{
			IR_pData=0;			//数据位置指针清0
			if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3]))	//数据验证
			{
				IR_Address=IR_Data[0];	//转存数据
				IR_Command=IR_Data[2];
				IR_DataFlag=1;	//置收到连发帧标志位为1
			}
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
	}

IR_Data[IR_pData/8]  划分了四个8位数据,IR_Data[0],IR_Data[1],IR_Data[2],IR_Data[3]分别代表地址码,地址码反码,命令,命令反码

8*****************************-----*********************8
当判断的时间长度为“0”的时间长度时:
则把该数据位清0。

if(IR_Time>1120-500 && IR_Time<1120+500)
		{
			IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));	//数据对应位清0
			IR_pData++;			//数据位置指针自增
		}
8*****************************-----*********************8

当判断的时间长度为“0”的时间长度时:
则把该数据位置1。

else if(IR_Time>2250-500 && IR_Time<2250+500)
		{
			IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));	//数据对应位置1
			IR_pData++;			//数据位置指针自增
		}

8*****************************-----*********************8
当判断的时间长度既不是“0”的时间长度也不是“1”的是时间长度时,说明数据接收错误,数据位置指针清0,重新接收。

else					//接收出错
		{
			IR_pData=0;			//数据位置指针清0
			IR_State=1;			//置状态为1
		}

8*****************************-----*********************8

因为共需要接收4个8位数据,共32位,所以当地址指针等于32时说明接收完毕,然后就能进入判断:

if(IR_pData>=32)		//如果接收到了32位数据
		{
			IR_pData=0;			//数据位置指针清0
			if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3]))	//数据验证
			{
				IR_Address=IR_Data[0];	//转存数据
				IR_Command=IR_Data[2];
				IR_DataFlag=1;	//置收到连发帧标志位为1
			}
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
  • 10
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值