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

#include 	<hs16p1880.h> 

//***********************宏定义*****************************
#define  unchar     unsigned char 
#define  unint      unsigned int
#define  unlong     unsigned long

#define  DemoPortOut	PB0
#define  DemoPortIn7	PB1


  

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

/*-------------------------------------------------
 *  函数名：GPIO_Init
 *	功能：  GPIO设置
 *  输入：  无
 *  输出：  无
 --------------------------------------------------*/	
void GPIO_Init(void) 
{ 
	OPTION= 0b00000000; //;Bit7：INT1EDG：外部中断1触发方式选择位（PB1）;0-falling edge, 1-rising edge
			//;Bit6：INTEDG：外部中断触发方式选择位（PB0）	;0-falling edge, 1-rising edge

	PCON  = 0b10100000;	 		
			//;Bit7：WDTE: WDT（看门狗定时器）使能位	;0-DIS, 1-EN
	
			//;Bit5：LVREN: 低电压复位使能位

    //PORTB //----------------------------------------------------------------------
	PORTB = 0b00000000;	//0000 0000 :PORTB数据寄存器
	TRISB = 0b00000010;	//0000 0010 :PORTB输入输出配置寄存器 (0-OUT;1-IN) 	
				//PB0输出 PB1输入 
				
	WUCON = 0b00000000;	//0000 0000	:PORTB变化中断唤醒寄存器 (1-EN;0=DIS)
	ODCON = 0b00000000;	//--00 0000 :PORTB开漏寄存器 (1-EN;0-DIS)
	PHCON = 0b11111111;	//1111 1111 :PORTB上拉寄存器 (1-DIS;0-EN)
				  
	
	PDCON = 0b11111111;	//1111 ---- :bit7:4 PORTB3:0下拉寄存器;1-DIS;0-EN
				
	
	PDCON1= 0b11111111;	//---- --11 :bit1:0 PORTB5:4下拉寄存器;1-DIS;0-EN
	//------                                                            
}

void System_Init(void)
{
	INTEN = 0B00000000;		  
					  //Bit7 GIE 使能全局中断     1-使能 0-禁止	
					  //Bit6 空 
					  //Bit5 INT1IE 使能外部中断1 1-使能 0-禁止
					  //Bit4 TP0IE 使能T2溢出中断 1-使能 0-禁止
					  //Bit3 TC0IE 使能T1溢出中断 1-使能 0-禁止
					  //Bit2 INTIE 使能外部中断0  1-使能 0-禁止
					  //Bit1 PBIE 使能端口变化中断1-使能 0-禁止 
					  //Bit0 空 
	INTFLAG=0B00000000;	
					  //Bit7 空	
					  //Bit6 空 
					  //Bit5 INT1IF 外部中断1标志位
					  //Bit4 TP0IF T2溢出中断标志位	
					  //Bit3 TC0IF TC1溢出中断标志位		
					  //Bit2 INTIF 外部中断0标志位		
					  //Bit1 PBIF PA/PB输入状态变化中断标志位	
					  //Bit0 空 

	INTEN1 = 0B00000000;	
			                  //Bit7 空	
					  //Bit6 空
					  //Bit5 空
					  //Bit4 空	
					  //Bit3 空	
					  //Bit2 空 
					  //Bit1 COMINTEN  端口比较器中断使能位
					  //Bit0 空 		
	INTFLAG1=0B00000000;	
					  //Bit7 空	
					  //Bit6 空
					  //Bit5 空
					  //Bit4 空	
					  //Bit3 空	
					  //Bit2 空 
					  //Bit1 COMINTF 端口比较器翻转标志位， 软件复位
					  //Bit0 空 
}

//**************中断处理******************
void interrupt ISR(void)	
{
//-------------------------------定时器TC0中断
   if(TC0IF==1)
   	{	
   		TC0IF=0; //定时器中断标识，软件清零
   		TC0L=0X74;//手动赋初值，保证每次进TC0中断时间为560US	
   		IRbitTime++;
   		
        if(IRbitTime > 50)  //50
        {
        	TC0IE = 0;
            IRbitTime = 0;
                        
        }	
   	}   
//---------------------------------INT1中断   
   if(INT1IF==1)
   {
   		INT1IF=0;
		
		
        if(DemoPortIn7 == 0)
        {
			INTEDG1=1;
        	TC0IE = 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;
                TC0IE = 0;  
                ReceiveFinish = 1;	 //接收结束标志位	
            }

        }else{
			INTEDG1=0;
		}
  
   }
     
}

/*-------------------------------------------------
 *  函数名：tC0_init
 *	功能：  TC0定时器初始化，560US进一次中断，用于设定发送6122码的最小脉宽, 进一次中断调用一次SendCtrl();发码函数。
 *  输入：  无
 *  输出：  无
 *  Fcpu=4M/2;   TC0使用8分频 ,得时钟为1/4M   计时为560US
 *  计数值=560/4 = 140;   所以计数初值 = 256-140 = 116
 --------------------------------------------------*/	
void tC0_init(void)
{
	 
	TC0M=0XD0; //1101 0000
		//Bit7 	TC0 启动控制位 1-开启 0-禁止
		//Bit6~Bit4：101  Fcpu/8 	
		//Bit3  TC0 时钟信号控制位   0 = Fcpu    1 = Fosc	
	
	
	
	TC0L=0X74;  //116
	TC0IE=1;   //定时器使能
	TC0IF=0;   //定时器中断标识清零
	GIE=1;    //开总中断
}

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

	OPTION= 0b00000000;  
	

	PCON  = 0b10100000;	 

//INTIF: 外部中断标志位，软件复位
	INT1IF = 0;	//INTFLAG.bit2
	
//INTIE: 外部中断使能位(1=EN,0=DIS)	
	INT1IE = 1;	//INTEN.bit2
	
//GIE:全局中断使能位
	GIE  = 1;	//INTEN.bit7
}

//****************************************************  
//清除所有ram 
//C中嵌入ASM，指令操作特殊寄存器前面需要加下划线“_”;
//****************************************************    
void clr_all_ram(void)
{
	STATUS &= 0x1F;
#asm  
	MOVLW	0X3F
	MOVWF	040H
	MOVLW	0X7F
	MOVWF	_FSR
	
BANK0_RAM_CLR_LOOP:	
	CLRF	_INDF
	DECF	_FSR,F
	DECFSZ	040H,F
	GOTO	BANK0_RAM_CLR_LOOP		
#endasm	   	   
}

/*-------------------------------------------------
 *  函数名：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();   //端口初始化
	System_Init();	 //系统初始化	
	tC0_init();	//tc0初始化
	EXIT1_INT_INIT();//INT1初始化
	clr_all_ram();   //清所有ram
    while(1)
    {
	   CLRWDT; 
	   if(ReceiveFinish) //接收数据成功
        {  
        	ReceiveFinish = 0;       	
            rdata2 = 0xFF^IRDataTimer[2];
            if((rdata2 == IRDataTimer[3]))
            {
            	DemoPortOut = ~DemoPortOut; //数据校验成功，PB0端口电平变化一次
            }
                            
        }
	      
    }
}
