用c语言实现查询红外解码

MCU 用c语言实现查询红外解码

红外解码的实现一般有定时器中断、外部中断+定时器、查询三种解码方案,其中查询方式解码在一些资源极少的MCU中或需要长时间关闭中断的系统中比较实用。下面给出的是用应广PMS150C单片机上实现的代码。
最近在用双元单通数字输出热释电红外传感器,感觉做出来的成本比现有方案有竞争优势,下次给大家写这个。

一.红外的编码格式

一般红外接收都采用市场上的集成接收头,它主要将38KHz的调制信号处理成电平信号,不过在一些应用中需要注意集成接收头有上电延时和接收延时,也不能长时间一直接收38KHz信号(会被接收头识别为干扰而被过滤)。
在这里插入图片描述
上图为编码格式:包括引导码+起始码+地址码+数据码+【结束码】其中结束码如不识别长按基本用不到!
上面为编码方式,当经过接收头的信号处理后得到的信号需要倒向,下面讲解都为倒向后的信号。
在这里插入图片描述

1.引导码和起始码

	引导码为9ms低电平,起始码为4.5ms 高电平
	注:在识别时需要考虑容错范围。

2.0码和1码

在这0码和1码里插入图片描述
上图为0码和1码的编码方式,而实际接收到是倒向的。

3.地址码

地址码为2个八位表示 :如0xFF,0x00
其中一个码是另一个码的反码。一般应用的时候可以利用该码来屏蔽一些错误或遥控器。

4.数据码

数据码也是2个八位表示:如0x01,0xFE
2个字节也是互为反码。一般应用的时候可以了利用来屏蔽接收错误的情况。

5.结束码

如果红外遥控器的按键一直按着,一般会每隔108ms左右发送一次,这里具体的时间还需要实际测试一下!
注:上面每次的电平识别都需要考虑容错的问题!!!

二.各阶段主要代码介绍

1.空闲处理

接收初始假设是处于空闲状态,即接收端口一直为高电平。

		//--------------idle
		if(ir_rcvsta==0)//idle
		{
			if(ir_rcvio==1)
			{
				return_byte(0);//退出
			}
			ir_rcvsta++;
			ir_rcvTimeCntL = 0;
			ir_rcvTimeCntH = 0;
			ir_rcvLevel_flag = 0;
    	}

2.引导码和起始码

一旦接收端口变为低电平后会进入该状态

//--------------boot
		else if(ir_rcvsta == 1) 
		{
			if(ir_rcvLevel_flag == 0)
			{//low boot 9ms
				if(ir_rcvio== 0)
				{
					ir_rcvTimeCntL++;
					if(ir_rcvTimeCntL>=150)//>=15ms error
					{//boot error
						return_byte(0);	
    	            }
				}
				else
				{	
					if(ir_rcvTimeCntL<45)//<4.5ms error
					{
						return_byte(0);
					}
					ir_rcvLevel_flag = 1;
				}
			}
			else
			{//high boot 4.5ms
				if(ir_rcvio == 1)
				{
					ir_rcvTimeCntH++;
					if(ir_rcvTimeCntH>=65)//>=6.5ms error
					{//high level timeout
						return_byte(0);	
					}
				}
				else
				{	
					if(ir_rcvTimeCntH < 25)
					{//low<4ms or high<2.5ms boot error
						return_byte(0);
					}
    	            ir_rcvIndex = 0;
					ir_rcvTimeCnt = 0;
					ir_rcvsta++;
    	            ir_rcvTimeCntL = 0;
					ir_rcvTimeCntH = 0;
					ir_rcvLevel_flag = 0;
				}
			}
		}//1 end

3.地址码和数据码接收

数据码和地址码可以放在一起,因为他们都一样!只是在应用逻辑上定义不同而已。该接收方式只需要稍微改改,就可以接收任意多个数据,例如用在433的无线解码上。

else if(ir_rcvsta == 2)//address or data recive.
    	{
    		if(ir_rcvLevel_flag==0)
    		{//low
				if(ir_rcvio==0)
				{
					ir_rcvTimeCntL++;
					if(ir_rcvTimeCntL>=9)//low >=900us error
					{
						return_byte(0);
					}
				}
    	        else
    	        {
	    	        if(ir_rcvTimeCntL<=1)
	    	        {
		    	        return_byte(0);
	    	        }
		    		ir_rcvLevel_flag = 1;
    	        }
    		}
    		else
    		{//high
		    	if(ir_rcvio == 1)
		    	{
					ir_rcvTimeCntH++;
					if(ir_rcvTimeCntH>=25)//hig >=2.5MS error
					{
						return_byte(0);
					}
		    	}
		    	else
		    	{	
		    		
		    		if( ir_rcvTimeCntH <= 1 )
		    		{
			    		return_byte(0);//low<100us error
	    			}
    	            ir_rcvBuf <<= 1;
		    		if(ir_rcvTimeCntH >10 )
		    		{//1 ok
			    		ir_rcvBuf.0 = 1;
		    		}
		    		else 
		    		{//0 ok
			    		ir_rcvBuf.0 = 0;
		    		}
		    		ir_rcvTimeCnt++;
		    		if(ir_rcvTimeCnt>=8)
		    		{//recevie sucess a byte data
		    			ir_rcvTimeCnt = 0;
						array_set_u8_t(ir_rcvResult,ir_rcvIndex,ir_rcvBuf);
						ir_rcvIndex++;
						if(ir_rcvIndex >=4)
						{
							if(ir_rcvResult[0] != IR_ADRH)
							{
								return_byte(0);
							}
							if(ir_rcvResult[1] != IR_ADRL)
							{
								return_byte(0);
							}
							A = ~ir_rcvResult[2];
							if( A != ir_rcvResult[3])
							{
								return_byte(0);
							}
							return_byte(1);//recevie sucess return
						}
		    		}
    	           ir_rcvTimeCntL = 0;
		    	   ir_rcvTimeCntH = 0;
    	           ir_rcvLevel_flag = 0;
	    		}
    	   }
		}//2 end
		fun_pcall(delay_20us,10);100us 这个100us延时函数比较重要,一定要测试
		//MNOTB(DEBUG_OUT);

三 .解码说明

上面用到的fun_pcall(delay_20us,10); 只是一个延时函数,你可以改成你自己的。
return_byte(0); 相当于return 0;
A = ~ir_rcvResult[2];这里的A只是一个临时变量,你可以改成你自己的。
array_set_u8_t(ir_rcvResult,ir_rcvIndex,ir_rcvBuf); 保存一个数据。
有人说这里为什么要这样做,是因为应广单片机的编译器不支持函数带参调用和返回。
把上面的解码放在while(1){fun}下,做成函数形式,函数返回0表示接收错误或空闲,当函数返回1时表示接受到正确的数据,用户可以处理该数据了。
上面整个解码过程还是很简单,其中最重要的是容错的问题!!!!

四. 完整代码

代码连接如下:
https://download.csdn.net/download/wenyouren/12648084

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月影恋人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值