51单片机:红外遥控(B站江科大)

        红外遥控器使用的是红外LED,人眼看不到。

        红外遥控器的电路有两种。

**第一种**:有两个输入,第一个输入:控制38MHZ,第二个输入控制高低电平(低电平才会使红外LED发光),发光时LED是以38MHZ闪烁的。这两个输入个通过一个PNP型三极管控制LED的亮灭

第二种:只有一个输入,这个输入包括了频率及高低电平,低电平会有38MHZ的抖动。同样也有一个三极管控制LED的亮灭。这两种就是信号的调制电路。

        为什么需要信号的调制呢?

        这是因为生活中的干扰红外信号太多了,所以信号需要调制,我们只要找到我们对应频率的信号解调就可以了(感觉可以理解为红外发射器和接收器之间的一种通讯协议)。

        当然,对于调制和解调是硬件自动完成的。调制就是上面所说的调制电路,解调是有一个单独的解调模块,我们单片机只需要关注解调模块的输出脚电平即可。解调后的信号和调制前的信号一模一样。

解调模块:

        

        上面的信息不想知道也可,下面的必须 了解嗷。

        在解调模块连接了我们的外部中断,原因就是我们不能够使用 if 等语句来判断是什么电平,这样的话就太慢了,所以我们需要中断,这里不使用定时器中断是因为这个中断是突发的不是有规律的。

        红外信号就是高电平代表1,低电平代表0嘛?肯定不是

        红外信号是使用 NEC编码 来表示0  1 的

        以下是NEC编码的内容:

开始(start):

0:

1:

重复(repeat):

数据发送格式:

地址反码和命令反码都是用来校验数据是否准确的。

        那么接下来就到了代码思路了:我们可以看到代码当中不仅需要外部中断,还需要定时器来判断是0 是1 是start 还是 repeat。我们的外部中断选用的是下降沿触发,定时器是12MHZ的晶振频率,定时器0,16位计数器,定时器时钟12

  我们选择使用状态机的思维,分别给0,1,2三种状态

  0状态:空闲状态,进入中断,我们要改为状态1

  状态1:根据定时计数器的数值,判断是start还是repeat信号,start信号将状态改为状态2,repeat信号将状态改为0

  状态2:我们根据定时计数器的数值,判断是0 还是 1,然后再对应的给上面**数据发送格式**的四个字节,来进行每一位的赋值,在赋值的时候我们需要一个指针,通过这个指针指到对应的某一位进行置0 或 置1的操作,指针是通过移位来完成的(注意:移位的距离不够超过16位,否则可能会出错),这里使用数组存每一个字节。当指针指到了第32位时,就可以返回数据,或者接受错误开始重新接收了。

好了,来看看代码吧

//状态机的代码思路
#include <REGX52.H>
#include "INT0.h"
#include "Timer0.h"
unsigned char IR_RepeatFlag;	//重复标志位
unsigned char IR_Data[4];		//四个数据位
unsigned char IR_pData;			//当前指针已经走到了哪一位,总共四个字节的数据即32位
unsigned char IR_State;			//表明当前的状态
unsigned int  IR_Time;			//记入此时定时器计数器的值
unsigned char IR_Address;		//记入地址
unsigned char IR_Num;			//记录接收的值
unsigned char IR_DataFlag;		//成功的接收到了数据
/*
红外遥控初始化
*/
void IR_Init(void)
{
	INT0_Init();
	Timer0_Init();
}
/*
返回我们的地址
*/
unsigned char IR_GetAddress(void)
{
	return IR_Address;
}
/*
返回我们的数据
*/
unsigned char IR_GetNum(void)
{
	return IR_Num;
}
/*
返回我们的重复标志
*/
unsigned char IR_GetRepeatFlag(void)
{
	if(IR_RepeatFlag == 1)	
	{
		IR_RepeatFlag = 0;	//将重复标志位清零
		return 1;	//返回重复
	}
	return 0;	//返回不重复
}
/*
返回我们接收到数据的标志位
*/
unsigned char IR_GetDataFlag(void)
{
	if(IR_DataFlag == 1)
	{
		IR_DataFlag = 0;
		return 1;
	}
	return 0;
}

/*
在外部中断函数当中,根据状态来判断我们代码的执行,这里是外部中断,下降沿执行
0表示空闲状态
1表示进入了判断是开始还是重复的状态
2表示是开始这时候就可以进行对数据的操作了.
*/
//!(这个函数我们全程状态为0的时候才会启动和关闭定时器,数据读取完成之后关闭定时器),!(这里的判断当中口号内没有等号)
void Int0_Routine(void) interrupt 0
{
	if(IR_State == 0)	//下降沿进入状态1,出中断函数,然后根据下一个下降沿的中断来判断是开始还是重复信号
	{
		IR_State = 1;
		Timer0_SetCounter(0);	//初始化我们计数器的值为0
		Timer0_Run(1);	//开启定时器
	}
	else if(IR_State == 1)
	{
		IR_Time = Timer0_GetCounter();	//获取当前计数器的值,根据当前计数器的值来判断是开始信号还是我们的重复信号
		Timer0_SetCounter(0);//!(我们只需要清零即可,不需要关掉定时器)
		if(IR_Time > 13500 - 500 && IR_Time < 13500 + 500)	//因为定时器不一定准确,因此我们可以给一个500的上下浮动范围
		{
			IR_State = 2;	//当为开始的时候只需要将我们的状态改为2,等待下一次下降沿的触发即可	
		}
		else if(IR_Time > 11250 - 500 && IR_Time < 11250 + 500)
		{
			IR_State = 0;	//当为重复的时候再重新开始
			Timer0_Run(0);	//!此时状态0需要关掉定时器,再等待状态0进中断的时候开启
			IR_RepeatFlag = 1; //重复标志位置1,我们可以使用这个标志位再main函数当中用来判断是不是一直再按某个红外遥控器的按键
		}
		else	//!接收出错,可能都不在这两个时间区间,那么就会走到这里
		{
			IR_State = 1;
		}
	}
	else if(IR_State == 2)	//状态2接收数据
	{
		IR_Time = Timer0_GetCounter();
		Timer0_SetCounter(0);	//定时器清零
		if(IR_Time > 1120 - 500 && IR_Time < 1120 + 500)	//表示0,此时我们需要进行将对应位置0的操作
		{
			IR_Data[IR_pData / 8] &= ~(0x01 << (IR_pData % 8)); 
			IR_pData ++;//!(忘记写了)数据位指针自增
		}
		else if(IR_pData > 2250 - 500 && IR_pData < 2250 + 500)	//表示1,此时我们需要进行将对应位置1
		{
			IR_Data[IR_pData / 8] |= (0x01 << (IR_pData % 8));
			IR_pData ++;//!(忘记写了)数据位指针自增
		}
		else	//!(没判断)接收出错
		{
			IR_pData=0;			//数据位置指针清0
			IR_State=1;			//置状态为1
		}
		if(IR_pData == 32)	//当我们已经完全的读取完了之后我们就需要再将数据位指针变为0
		{
			IR_pData = 0;
			if(IR_Data[0] == ~IR_Data[1] && IR_Data[2] == ~IR_Data[3])	//地址、数据进行校验
			{
				IR_DataFlag = 1;	//数据接收标志位置1
				IR_Address = IR_Data[0];	//地址存储
				IR_Num = IR_Data[2];		//数据存储
			}
			//!(没有写)
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
	}
}

        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值