8位单片机只用一个定时器T0进行红外解码,包括短按、长按处理,模拟串口打印数据

最近自己在网上搜了很多资料,发现很多的红外解码,关于重码的处理的代码很少,分享一下红外解码包括重码的处理。
使用单片机:EN8F156
功能说明:红外遥控器解码,只使用定时器T0定时100us进行按键解码,处理按键短按与长按,将解码的数据通过串口打印。

/***************************************
功能说明:红外遥控器解码,定时器T0定时100us进行按键解码,处理按键短按与长按,串口打印解码数据。
****************************************/
#include "SYSCFG.h"
#define  uchar     unsigned char 
#define  uint      unsigned int

#define 	IR_PIN 	PA2	//红外输入
#define 	PIN_TX 	PC0 //串口发射


//IR接收变量
#define	IR_Long_Time	20			//110*20 = 2200ms
uchar	Receive_Count = 0;  		//红外接收计位数
uchar	Low_Level_Time = 0;			//低电平时间
uchar	High_Level_Time = 0;		//高电平时间
uchar   UserCode_High = 0;
uchar	UserCode_Low = 0;			//存放用户码1
uchar	Data_Code = 0;				//存放数据码
uchar	IR_Temp = 0;				//存放数据码反码
uchar   Repeat_Count = 0;			//重码计数   
//IR接收标志
bit	Data_Receive_Flag = 0;       	//数据接收标志
bit	Begin_Flag = 0;        			//同步码标志
bit Receive_Error_Flag = 0;         //接收失败
bit Start_Receive_Flag = 0;     	//开始标志 
bit Receive_Over_Flag = 0;			//键码解码完毕
bit Repeat_Flag = 0;				//重码标志
bit Ready_Repeat_Det_Flag = 0;		//准备接受重码  


/*-------------------------------------------------
 *  函数名:POWER_INITIAL
 *	功能:  上电系统初始化 系统时钟4MhZ/2 = 2MhZ
 *  输入:  无
 *  输出:  无
 --------------------------------------------------*/	
void MCU_INIT(void) 
{ 
	OSCCON = 0B01010001;//WDT 32KHZ IRCF=101=4MHZ/2=2MHZ,0.5US/T
					 //Bit0=1,系统时钟为内部振荡器
					 //Bit0=0,时钟源由FOSC<2:0>决定即编译选项时选择
	OPTION = 0B00001000;//Bit4=1 WDT MODE,PS=000=1:1 WDT RATE
					 //Bit7(RAPU)=0 ENABLED PULL UP PA
		
	TRISA = 0x04;		//PA2输入
	TRISC = 0x00;		//
	PORTA = 0B00000000;		//	
	PORTC = 0B00000000;		//
	WPUA = 0B00000000;     //PA端口上拉控制 1-开上拉 0-关上拉
	WPUC = 0B00000000;     //PC端口上拉控制 1-开上拉 0-关上拉
	MSCKCON = 0B00000000;//6B->0,禁止PA4,PC5稳压输出
					  //5B->0,TIMER2时钟为Fosc
					  //4B->0,禁止LVR       
	CMCON0 = 0B00000111; //关闭比较器,CxIN为数字IO口
	ANSEL = 0B00000000;   //关闭模拟输入
	PAIF =0;   //清 PA INT中断标志位   
	PAIE =0;   //关闭 PA INT中断

	GIE = 1;
}

//**************中断处理**********************************
void interrupt ISR(void)//PIC_HI-TECH使用
{   
  //定时器0的中断处理**********************
	if(T0IE && T0IF)//100us
	{
		TMR0 = 76; //注意:对TMR0重新赋值TMR0在两个周期内不变化			
		if(IR_PIN==0) 													//低电平期间。
		{  
			if(Data_Receive_Flag==1) 									//是否找到同步头?如果找到同步头就由低到高开始接收
			{				
				  if(High_Level_Time>=13&&High_Level_Time<=20)			//是高电平 1690us
				  {
					   Receive_Count++; 	  
					   IR_Temp>>=1; 									//右移动一位
					   IR_Temp=IR_Temp|0x80;							//高位补1
				  }
				  else if(High_Level_Time>=2&&High_Level_Time<=8)  		//是低电平    560us
				  {
					   Receive_Count++; 	   
					   IR_Temp>>=1; 				 					//右移一位,高位补0							
				  } 
				  else	
						Receive_Error_Flag=1;				
				 if(Receive_Error_Flag==1)								//数据错误,重新解码
				 {
					 Begin_Flag=0; 	   
					 Receive_Count=0;
				 }
				 else
				 {
					 if(Receive_Count==8)
						UserCode_High=IR_Temp;							//用户码高
					 if(Receive_Count==16)		   						//用户码低
						UserCode_Low=IR_Temp;	
					 if(Receive_Count==24)		   						//键码
						Data_Code=IR_Temp;			   
				 }
				 if(Receive_Count==32)									//32位数据接收完毕
				 {
					 Begin_Flag=0;
					 Receive_Over_Flag = 1;
				 }
			}	 
			if(High_Level_Time>30&&High_Level_Time<60)					//判断同步头 4.5ms
			 {														
				 Begin_Flag=1; 		 									//检测正确的同步头 					
				 Receive_Count=0;										//接收位数,清除0 
				 Data_Code = 0;											//收到正确的引导码将上一次的键码清零
				 Ready_Repeat_Det_Flag = 0;
				 Repeat_Flag = 0;
				 Repeat_Count = 0;
			 }
			 if(Ready_Repeat_Det_Flag)									//重码检测
			 {
				 if(High_Level_Time>15&&High_Level_Time<=30)			//收到 低脉冲8ms+高脉冲2.5ms 认为是重码 每隔110ms收到重码
				 {				 										
				 	Repeat_Count++;
				 	if(Repeat_Count >= IR_Long_Time)					//长按时间设置110*20 = 2200ms
				 	{
				 		Repeat_Count = IR_Long_Time-1;
				 		Repeat_Flag = 1;								//长按标志 需手动清标志
				 	}
				 }
			 }
			Low_Level_Time++;											//低脉冲计数											
			High_Level_Time=0;
			Data_Receive_Flag=0;
			Receive_Error_Flag=0;		    							//接收失败标志
			Start_Receive_Flag=1;			 							//开始接收
		}
		if(Start_Receive_Flag==1)		  		
		{
		   if(IR_PIN==1)  												//高电平期间
		   {			   
				High_Level_Time++;		 								//高脉冲计数
				if(Begin_Flag==1) 										//收到正确的引导码 低9ms+高4.5ms 准备接收32位数据
					 Data_Receive_Flag=1;   							//数据接收标志
				else
				{
					if(Low_Level_Time>80&&Low_Level_Time<110)
					{					
						Ready_Repeat_Det_Flag = 1;						//准备重码检测			
					}
					Low_Level_Time = 0;									//清低脉冲计数
				}
		   }
		}
		T0IF = 0;
	}
}

/*-------------------------------------------------
 *	函数名称:TIMER0_INITIAL
 *	功能:初始化设置定时器v
 *	相关寄存器:
 *	设置TMR0定时时长100us                    
 -------------------------------------------------*/
void TIMER0_INITIAL (void)  
{
	//OPTION = 0B00000111;	
						    //Bit5 T0CS Timer0时钟源选择 
								//1-外部引脚电平变化T0CKI 0-内部时钟(FOSC/2)
							//Bit4 T0CKI引脚触发方式 1-下降沿 0-上升沿
							//Bit3 PSA 预分频器分配位 0-Timer0 1-WDT 
							//Bit2:0 PS2 8个预分频比 000 - 1:2
	TMR0 = 56;
	T0IF = 0;//清空T0软件中断
	T0IE = 1;//开定时器/计数器0中断
}

/*------------------------------------------------- 
 *	函数名称:100us延时
 *	功能:    
 *	输入参数:Time  延时时间长度   延时时长TimeUs
 *	返回参数:无 
 -------------------------------------------------*/

void delay100us(void)
{
	unsigned char Time;
	Time = 26;
	while(Time--)
	{
		//NOP();
	}
}
/*-------------------------------------------------
 *	函数名称:DelayMs
 *	功能:    短延时函数
 *	输入参数:Time  延时时间长度   延时时长Timems
 *	返回参数:无 
 -------------------------------------------------*/
void DelayMs(unsigned char Time)
{
	unsigned char a,b;
	for(a=0;a<Time;a++)
	{
		for(b=0;b<10;b++)
		{
		 	delay100us(); //快1%
		}
	}
}
/*-------------------------------------------------
 *	函数名称:IO口模拟串口发射
 *	功能:    
 *	输入参数:
 *	返回参数:无 
 -------------------------------------------------*/
void TxSend(uchar dat)//发送八位数据
{
	uchar	i;
	GIE = 0;
	PIN_TX = 0;
	delay100us();
	for(i=0; i<8; i++)
	{
		if(dat & 1)		PIN_TX = 1;
		else			PIN_TX = 0;
		dat >>= 1;
		delay100us();
	}
	PIN_TX = 1;
	GIE = 1;
	delay100us();
	delay100us();
}

/*-------------------------------------------------
 *	函数名称:红外按键处理
 *	功能:   	处理键码和重复码
 *	输入参数:
 *	返回参数: 
 -------------------------------------------------*/

 void IR_HANDLE(void)
 {
 	if(Receive_Over_Flag)		//短按处理
	{
		Receive_Over_Flag = 0;
		TxSend(Data_Code);		//将短按的键码打印
	}	
	if(Repeat_Flag)				//长按处理
	{
		Repeat_Flag = 0;
		if(Data_Code == 0x45)	//键码=0x45
		{
			TxSend(0xaa);		//如果是0x45长按 发送0xaa
		}
	}
 }
 /*********************************************************
  * @说明 main
  * @参数   无
  * @返回   无
  * @注意   
  ******************************************************/
void main(void)
{
	MCU_INIT();
	TIMER0_INITIAL();
	while(1)
	{
		IR_HANDLE();
	}
}
发布了1 篇原创文章 · 获赞 1 · 访问量 19

猜你喜欢

转载自blog.csdn.net/kevin_pj/article/details/105292983