//*****************************************************   
//Copyright (c) 2021, 苏州华芯微电子股份有限公司
//All rights reserved                                 
//
//文件名称: HS16F3211_IR_RECEIVE
//摘    要: HS16F3211接收6122/NEC红外码演示
//  		芯片PB7口接收6122码，接收成功PB0反转一次
//          PB1设置为IR红外接收脚，使能PB1端口外部中断1，通过端口变化中断来开关TMR0,通过TMR0的计时来判断接收到的数据是1还是0来解码，详见中断函数注释
//当前版本: 1.0                                      
//作    者: 华芯微MCU组
//完成日期: 2021.09.13
//*****************************************************   

#include 	<hs16f3211.h> 

//***********************宏定义*****************************
#define  unchar     unsigned char 
#define  unint      unsigned int
#define  unlong     unsigned long
#define  DemoPortOut	FPB0
#define  DemoPortOut1	FPB2

#define  DemoPortIn7	FPB1


#define	NOP()		asm("NOP")    
#define	CLRWDT()	asm("clrwdt")    
#define	SLEEP()		asm("sleep")    

unchar IRbitNum = 0;		//用于记录接收到第几位数据了
unchar IRbitTime = 0;		//用于计时一位的时间长短
unchar IRDataTimer[4];		//存出来的4个数据
unchar bitdata=0x01;	    //用于按位或的位数据
unchar ReceiveFinish = 0;	//用于记录接收完成

/*-------------------------------------------------
 *  函数名：GPIO_Init
 *	功能：  GPIO设置
 *  输入：  无
 *  输出：  无
 *  PB7口配置为输入上拉模式
 --------------------------------------------------*/	
void GPIO_Init(void) 
{ 
	OPTION= 0b00000010; //Bit7 INT1EDG, 外部中断1触发方式 0 INT1引脚下降沿触发
                        //Bit6 INTEDG, 外部中断 触发方式 0 INT引脚下降沿触发
                        //Bit5 T0CS, TMR0时钟源选择位 0 内部指令时钟
                        //Bit4 T0SE, TMR0时钟源边沿选择位 0 T0CKI引脚下降沿触发计数
                        //Bit1 PSA, 预分频分配位 0 预分频器分配给TMR0
                        //Bit2:0 PS[2:0], 预分频配置 010 '8分频
    PORTA = 0b00000000;	
    IOSTA = 0b00000000;	//PA输入输出 0-输出 1-输入
                        //PA口->全输出

    PORTB = 0b00000000;	
    IOSTB = 0b10000010;	//PB输入输出 0-输出 1-输入
                        //PB口->全输出
                        
    PHCON = 0b11111111;	//输入状态下配置PB端口上拉
						//1111 1111 :1-DIS;0-EN                                                            
}


//**************中断处理******************
void interrupt ISR(void)	
{
//-------------------------------定时器TMR0中断
   if(FT0IF==1)
   	{	
   		FT0IF=0; //定时器中断标识，软件清零
   		TMR0=0X74;//手动赋初值，保证每次进TIME0中断时间为650US	
   		IRbitTime++;
   		
        if(IRbitTime > 50)  //50
        {
        	FT0IE = 0;
            IRbitTime = 0;
                        
        }	
   	}   
//---------------------------------端口变化中断   
   if(FINT1IF==1)
   {
   		FINT1IF=0;
		
		
        if(DemoPortIn7 == 0)
        {
			INTEDG1=1;
        	FT0IE = 1;
        	if(IRbitTime > 21)   //低电平+高电平的时间超过 11.7MS,认为是引导码
            {
            	IRDataTimer[0] = 0;
                IRDataTimer[1] = 0;
                IRDataTimer[2] = 0;
                IRDataTimer[3] = 0;
                IRbitNum = 0;
                bitdata = 0x00;
            }
            else if(IRbitTime >= 3)   //低电平+高电平的时间大于560*3=1680US,认为是高电平
            {
            	IRDataTimer[IRbitNum-1] |= bitdata;  //对应位和bitdata进行或运算
            }
            IRbitTime = 0;
            bitdata<<=1;
            if(bitdata == 0)           //刚开始接收数据，或接收8位数据结束，对保存在数组内的数据地址++
            {
            	bitdata = 0x01;
                IRbitNum++;
            }
            if(IRbitNum > 4)          //4个字节数据接收完毕,
            {
            	IRbitNum = 0;
                FT0IE = 0;  
                ReceiveFinish = 1;	 //接收结束标志位	
            }

        }else{
			INTEDG1=0;
		}
  
   }
     
}

/*-------------------------------------------------
 *  函数名：time0_init
 *	功能：  TIME0定时器初始化，560US进一次中断，用于设定发送6122码的最小脉宽, 进一次中断调用一次SendCtrl();发码函数。
 *  输入：  无
 *  输出：  无
 *  Fcpu=4M/2 = 1M;   TIME0使用8分频 ,得时钟为1/4M   计时为560US
 *  计数值=560/4 = 140;   所以计数初值 = 256-140 = 116
 --------------------------------------------------*/	
void time0_init(void)
{
	OPTION = 0b00000010;    // 8分频
	TMR0=0X74;  //116
	FT0IE=1;   //定时器使能
	FT0IF=0;   //定时器中断标识清零
	FGIE=1;    //开总中断
}

/*-------------------------------------------------
 *  函数名：PB_CHANGE_INIT
 *	功能：  PB端口输入状态变化中断初始化 
 *          PB对应端口需要设置成输入(切记不让端口处于浮空输入状态)；
 *  输入：  无
 *  输出：  无
 *          PB口开启中断功能时，对应WUCON位设置为 1     //   PB7设置为变化触发中断  WUCON.7=1;
 --------------------------------------------------*/	
void PB_CHANGE_INIT(void)  //PB7端口变化中断设置	
{
	IOSTB = 0b00000000;	//PB输入输出 0-输出 1-输入 对应端口配置为输入
	WUCON = 0b00000000;	//输入状态下配置PORTB输入状态变化/唤醒控制寄存器
						//对应PB口置1，设置对应的PB口变化检测功能
	                    //0000 0000	:1-EN;0=DIS                   
	                                                             
	FPBIF = 0;	        //PBIF: PB端口变化中断标志位，软件复位
	FPBIE = 1;	        //PBIE: PB端口变化中断使能位(1=EN,0=DIS)		                                  
	FGIE  = 1;	        //GIE:全局中断使能位       	                    
}


//****EXIT1_INT设置****//
//PB1-外部中断引脚INT1-PB1：设置成输入带上拉 
void EXIT1_INT_INIT(void)
{

	OPTION= 0b00000010;  
	

	PCON  = 0b10100000;	 

//INTIF: 外部中断标志位，软件复位
	FINT1IF = 0;	//INTFLAG.bit2
	
//INTIE: 外部中断使能位(1=EN,0=DIS)	
	FINT1IE = 1;	//INTEN.bit2
	
//GIE:全局中断使能位
	FGIE  = 1;	//INTEN.bit7
}
/*-------------------------------------------------
 *  函数名：delay_ms
 *	功能：  写入参数 x,可以延时xMS
 *  输入参数：  x
 --------------------------------------------------*/	
void delay_ms(unint x)
{
	unint i,j;
	for(i=0;i<x;i++)
	{	
		for(j=0;j<140;j++);
	}
}


//****主函数****//
void main(void) 
{
	unchar rdata1,rdata2;
    GPIO_Init();   //端口初始化
    time0_init();
	EXIT1_INT_INIT();
    // PB_CHANGE_INIT();//PB端口变化中断初始化
    while(1)
    {
	   if(ReceiveFinish) //接收数据成功
        {  
        	ReceiveFinish = 0;       	
            rdata2 = 0xFF^IRDataTimer[2];
            if((rdata2 == IRDataTimer[3]))
            {
            	DemoPortOut = ~DemoPortOut; //数据校验成功，PB0端口电平变化一次
            }
                            
        }
	      
    }
}
