51单片机;红外解码

红外通信

注意:本文采用的是判断相邻下降沿时间来解码的,还有一种方式即分别判断载波和空闲的时间来进行解码

​ NEC协议的数据格式包括:引导码、用户码、用户码(用户反码)、按键码、按键码(按键反码)、最后一个停止位。停止位只要起隔离作用,一般不进行判断,程序中可以不予理会。

​ 数据编码共4个字节32位,分别为:用户码、用户码(用户反码)、按键码、按键码(按键反码)(具体是源码还是反码由生产商决定,反码可用于对数据纠错)

解码:(其中载波为低电平,空闲为高电平)

​ 引导码:9ms载波+4.5ms的空闲 信号时间为:13.5ms

​ 比特值 “ 0 ”:560us的载波+560us的空闲 信号时间为:1.12ms

​ 比特值 “ 1 ”:560us的载波+1.68ms的空闲 信号时间为:2.24ms

​ 在程序中,将定时器配置为8位自动重装模式,用于计数下降沿的时间:

//定时器0初始化
void Init_Timer0()
{
   TMOD = 0x02;//八位自动重装
   TH0 = 0;//重载值
   TL0 = 0;//初始值
   ET0 = 1;//溢出中断允许位
   TR0 = 1;//运行控制位
}
void Timer0_Break() interrupt 1
{
	ir_time++;//用于记录相邻两个下降沿的时间
}

​ 红外接收头接单片机的P3^2引脚(即外部中断0),配置外部中断为下降沿触发方式,在中断函数中将下降沿的时间进行记录,存到数组中以便对码值进行判断。

//外部中断0配置
void Init_EXT0()
{
	IT0 = 1;//下降沿触发中断
	EX0 = 1;//外部中断0中断允许位
	EA = 1;//开总中断	
}
//中断处理
void EX0_Break() interrupt 0
{
	static bit Flag_Star;//开始处理标志
    static uchar i;

	if(Flag_Star)
	{
		//干扰信号的处理
		//if(ir_time<63 && ir_time>=33)//9ms-17ms左右记为干扰信号
		if(ir_time>48)//超过13.5ms的则为干扰信号
			i = 0;//不记录进电平数组
		ir_data[i] = ir_time;//将电信号时间进行记录
		ir_time = 0;//清空计数
		i++;
		if(i==33)//记录一个完整的周期
		{
			i = 0;
			ir_recode = 1;//记录完毕标志
		}
	}
	else
	{
		ir_time = 0;
		Flag_Star = 1;		
	}		
}

​ 电信号时间记录后,我们对记录到的时间进行处理。其中,引导码我们不予处理,主要处理4位数据编码,将其转换为对应的二进制编码。

//将接收到的时间转换为电平信号
void Ir_Single_Trun()
{
	uchar i,j,k,value,temp;
	k = 1;//略过引导码
	for(i=0;i<4;i++)//4位
	{
		for(j=0;j<8;j++)//8个字节
		{
			temp = ir_data[k];//取出时间信息
			if(temp > 7)//"1"的电平时间为2.24ms,2.24/0.000278
				value |= 0x80;//为1,则最高位置1
			if(j<7)
				value >>= 1;//直接右移就会在最高位出来一个0
			k++;
		}
		ir_code[i] = value;//将处理完的值存进码值数组
		value = 0;
	}
	ir_turn = 1;//键值转换完毕
}

​ 最后,我们将解码到的码值与编码值进行比较,判断出对应的操作。

​ 我的红外遥控器编码值为:

//数码管显示处理	DataPort为P0口宏定义
void led_view()
{
	switch(ir_code[2])//判断键码值
	{
		case 0x0c:DataPort=led_table[1];break;
		case 0x18:DataPort=led_table[2];break;
		case 0x5e:DataPort=led_table[3];break;
		case 0x08:DataPort=led_table[4];break;
		case 0x1c:DataPort=led_table[5];break;
		case 0x5a:DataPort=led_table[6];break;
		case 0x42:DataPort=led_table[7];break;
		case 0x52:DataPort=led_table[8];break;
		case 0x4a:DataPort=led_table[9];break;
		default:DataPort=0x79;break;//未接收显示"E"
	}
	ir_turn = 0;//处理完成置0,以便下一次键值转换处理
}

​ 最后在主函数中对各个函数进行调用。

//主函数
void main()
{
	Init_Timer0();
	Init_EXT0();
	du = 0;
	DataPort=0xfe;
	we = 1;
	we = 0;
	DataPort=0x3f;
	du=1;
	while(1)
	{
		if(ir_recode)//时间记录完毕
		{
			Ir_Single_Trun();
			ir_recode = 0;	
		}
		if(ir_turn)
		{
			led_view();		
		}	
	}
}
posted @ 2021-01-31 12:15  是小魏啊  阅读(737)  评论(0编辑  收藏  举报