资讯详情

基于51单片机的红外接收

红外接收的通信原理有很多,常用的是脉宽调制(PWM)和脉时调制(PPM)这两种方法,最近小编试图写基于51单片机脉搏的红外接收程序,有一些经验与大家分享。

通常的红外遥控器是将二进制脉冲码调制到38KHz在载波上,缓冲放大后送至红外发光二极管,转化为红外信号。 由于二进制脉冲代码的形式很多,为了开发红外接收设备,我们必须了解红外遥控器的载体模式和载体频率,才能选择综合红外接收头,制定解码方案。

在这里插入图片描述

从原理图可以看出,我使用的一体红外接收头有三个引脚,即VCC、GND数据引脚(用于传输数据)。

现在我们已经知道它是由数据引脚传输的,那么数据是如何传输的呢?传输一次的数据格式是什么?

很明显,数据是由五段数据组成的。

首先,它会给一个9ms的低电平,4.5ms由高电平组成的起始码告诉我们下一步要传输数据,然后开始传输32位二进制数据码。

因为它只有一个数据引脚,我们需要判断它传输的数据是二进制的 ‘ 0 ’ 还是 ‘ 1 ’ 。

这里可以看到,无论数据传输如何 ‘ 0 ’ 还是 ‘ 1 ’ ,都会先传输0.56ms,也就是560us低电平,用来判断上一个数据的结束和下一个数据的开始。至于传输的数据,用下一个高电平时间来判断。

高电平时间为565um就是数据 ‘ 0 ’ ,1690um就是数据 ‘ 1 ’ 。由于环境因素影响实际数据传输,我们需要判断中间值。超过这个中间值是数据 ‘ 1 ’ ,相反,是数据 ‘ 0 ’ 。

理论讲了这么久,估计都很无聊,然后开始分析代码。

void main(void) { 
        //我们使用51单片机,所以我们可以使用定时器来计时。 //对于延迟函数,确实很方便,但小编强烈不建议使用延迟函数,尽量不要使用延迟函数,可以用定时器解决。 //延迟函数时间不准确。至于为什么不使用延迟函数,小编稍后会写一篇文章来解释。  TMOD = 0x01;打开这里的定时器1,用于计时。  TR0 = 0; //关闭允许定时器1计时,当我们需要定时器1计时时时打开。  IT0 = 1;  EX0 = 1; //这两句话是51单片机外部中断1允许的,由于红外数据最初是9ms低电平,可使用外部中断(无中断)。  EA = 1;  ///打开总中断  while (1)  { 
          //while(1)循环中的代码将单独列出。  } } 

以上是我们程序需要打开的配置 接下来是外部中断程序

bit InFrared_Way = 0;   //我在程序的开头定义了一个字节的变量。至于功能,接下来我们来谈谈。  void Int_0(void) interrupt 0 //外部中断程序 { 
        //一开始,我直接在外部中断中写红外解码程序,但我发现无论如何都无法进入中断程序(可能是我的代码问题)。 //然后我想到我的老师告诉我,外部中断程序越简单越好,我就变成了现在。  InFrared_Way  = 1;   //让变量置1在主程序中判断红外信号。 } 

 if (InFrared_Way == 1) //判断是否接收到红外信号,如果能接收到信号,则进入函数。  { 
          EX0 = 0;			//关闭外部中断,防止干扰。
		TR0 = 1;			//允许定时器1计时。
		InFrared_Init();	//这是我写的红外接收函数,下面会提到,这儿不做过多解释。
		TR0 = 1;			//关闭允许定时器1计时。
		EX0 = 1;			//打开外部中断。
		InFrared_Way = 0;	//清零InFrared_Way ,标志着已经结束红外接收。
	}

sbit INIR = P3^2;				//51单片机的引脚定义,我的51板子上数据引脚连接的是P3^2引脚。
unsigned char Data[4] = { 
       0};	//定义四组8位的数据,刚好储存红外信号的32位数据。

void InFrared_Init(void)		//这个就是上面提到的红外接收函数。
{ 
       
	unsigned char i, j;			//因为定义了4个数据,每个数据8个位,所以这儿用i表示是哪个数据,j表示数据哪个位。

	TH0 = 0;
	TL0 = 0;					//将定时器1的时间清0,方便计时。
	while (INIR == 0 && TH0 <= 35);	//等待9ms低电平过去。
	if (INIR == 1)				//判断是否为高电平。
	{ 
       
		while (INIR == 1 && TH0 <= 55);	//等待4.5ms高电平过去。
//开始接收数据。
		for (i = 0; i < 4; i++)
		{ 
       
			for (j = 0; j < 8; j++)	//接收4组8位数据。
			{ 
       
				TH0 = 0;
				TL0 = 0;					//将定时器1的时间清0,方便计时。
				while (INIR == 0 && TH0 <= 3);	//等待560us低电平过去。
				while (INIR == 1);	//判断高电平时间。
				Data[i] >>= 1;	//数据左移一位,使接收位默认为0,因为数据是由低位开始接收。
				if (TH0 >= 7)	//判断是否超过中间值,超过就是数据1。
				{ 
       
					Data[i] |= 0x80;	//数据写1,默认为0,所以只需要有写1的操作。
				}
			}
		}
	}
}

到此为止,全部函数就分享出来啦!

#include <STC12C5A60S2> //这个根据自己的51单片机芯片来修改。

sbit INIR = P3^2;			//这个根据自己定义引脚。
bit InFrared_Way = 0;
unsigned char Data[4] = { 
       0};

void InFrared_Init(void);

void main(void)
{ 
       
	TMOD = 0x01;
	TR0 = 0;
	IT0 = 1;
	EX0 = 1;
	EA = 1;
	while (1)
	{ 
       
		if (InFrared_Way == 1)
		{ 
       
			EX0 = 0;
			TR0 = 1;
			InFrared_Init();
			TR0 = 1;
			EX0 = 1;
			InFrared_Way = 0;
		}
	}
}

void Int_0(void) interrupt 0
{ 
       
	InFrared_Way  = 1;
}

void InFrared_Init(void)
{ 
       
	unsigned char i, j;
	
	TH0 = 0;
	TL0 = 0;
	while (INIR == 0 && TH0 <= 35);
	if (INIR == 1)
	{ 
       
		while (INIR == 1 && TH0 <= 55);
		for (i = 0; i < 4; i++)
		{ 
       
			for (j = 0; j < 8; j++)
			{ 
       
				TH0 = 0;
				TL0 = 0;
				while (INIR == 0 && TH0 <= 3);
				while (INIR == 1);
				Data[i] >>= 1;
				if (TH0 >= 7)
				{ 
       
					Data[i] |= 0x80;
				}
			}
		}
	}
}

小编的代码里面并没有处理4组数据,是因为每个人使用的显示的东西不同,小编是使用的0.96寸的OLED来处理的4组数据,有些人可能会使用数码管来显示。因为这儿只是讨论红外,所以并没有介绍到其他的东西。

(以下仅仅代表个人看法,如果有大佬愿意指导在下,感恩不尽!) 对于这四组数据,我最开始使用的遥控器上的 0 — 9 这10个数据的第三组数据是顺序连着的。

例如:

0 的数据码如果是 0x10 ,那么 1 的数据码就是 0x11 。

但是,我换了一个遥控器之后,0 — 9 的数据码并不是连在一起的,所以,目前的我认为,不能光看了 0 的数据码就可以判断 1 — 9 的数据码,而需要实事求是的每一个去验证。

标签: 红外遥控接收器模块传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台