//*****************************************************   
//Copyright (c) 2021, 苏州华芯微电子股份有限公司
//All rights reserved                                 
//
//文件名称: HS16F3211_IR_SEND
//摘    要: HS16F3211发送6122红外码演示代码
//  		PWM1映射到PB1口产生38KHZ方波用于IR发码的载波
//          TMR0用于6122码的窄脉宽控制，配合SendCtrl()函数发码.
//当前版本: 1.0                                      
//作    者: 华芯微MCU组
//完成日期: 2021.09.20
//*****************************************************   

#include 	<hs16f3211.h> 

//***********************宏定义*****************************
#define  unchar     unsigned char 
#define  unint      unsigned int
#define  unlong     unsigned long
#define  DemoPortOut	FPB0
#define  DemoPortOut1	FPB1          //38KHZ输出口

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

#define IRSend_HIGH_1   1  						// 560uS
#define IRSend_LOW_1    3 						// 1680uS

#define IRSend_HIGH_0   1  						// 560uS
#define IRSend_LOW_0    1  						// 560uS

#define IRSend_PIN_1   FPWM1EN = 1  		    // 发送数据  开启PWM
#define IRSend_PIN_0   FPWM1EN = 0 				// 关闭PWM

#define Status_NOSend	0						// 不发送的状态
#define Status_Head		1						// 发送引导码的状态
#define Status_Data		2						// 发送数据的状态

unchar IRSendStatus;							// 发送状态，是发送引导码还是数据
unchar IRSendData;								// 发送的数据中转变量
unchar  TxBit=0,TxTime=0; 						//临时变量
unchar Sendbit = 0;                             //发送第几位数据，临时变量
unchar level0,level1;							// 一位数据里发送与关闭的时间值
bit SendLastBit = 0;                            //发码结束标志
unchar SaveLastBit = 0;                         //临时变量
unchar IRData[4] = {0x00,0xff,0x45,0xba};		// 需要发送的4个数据,放在数组中
void SendCtrl(void);                            //发码函数


/*-------------------------------------------------
 *  函数名：GPIO_Init
 *	功能：  GPIO设置
 *  输入：  无
 *  输出：  无
 --------------------------------------------------*/	
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 = 0b00000000;	//PB输入输出 0-输出 1-输入
                        //PB口->全输出
}


//**************中断处理**********************************
void interrupt ISR(void)  //
{
   	if(FT0IF==1)
   	{	
   		FT0IF=0; //定时器中断标识，软件清零
   		SendCtrl();//发码控制函数
   		TMR0=0X74;//手动赋初值，保证每次进TIME0中断时间为650US	
   	}   
}

/*-------------------------------------------------
 *  函数名：SendCtrl
 *	功能：  发码控制函数，变量IRSendStatus赋值为1后，SendCtrl就会发送一帧6122码.
 *  输入：  无
 *  输出：  无
 *  要求：此函数发送6122码需要定时器配合，每调用一次的时间为 最小脉宽的时间，
 *  TIME0定时器650us触发一次中断，调用一次该函数，因此函数的窄脉宽为650US.
 --------------------------------------------------*/	
void SendCtrl(void)
{

	if (IRSendStatus == Status_NOSend)			// 不发送的状态
	{        
		IRSend_PIN_0;
        Sendbit = 0;
		TxTime = 0;
        
	}	 
	else if (IRSendStatus == Status_Head)		// 发送引导码
	{
    	TxTime++;
		if (TxTime < 17)   						// 发送9mS信号
		{
			IRSend_PIN_1;
		}
        else if (TxTime < 24)   				// 4.5mS不发送
		{
			IRSend_PIN_0;
		}
		else
		{
			TxTime = 0;
            IRSendStatus = Status_Data;
		}
        IRSendData = IRData[0];
        TxBit = 0x01;
	}
	else if(IRSendStatus == Status_Data)		// 发送数据
	{
		if (IRSendData & TxBit)  				// 1，是1:3的时间
		{
			level1 = IRSend_HIGH_1;
			level0 = IRSend_LOW_1;
		}
		else									// 0，是1:1的时间
		{
			level1 = IRSend_HIGH_0;
			level0 = IRSend_LOW_0;
		}
		TxTime++;
		if (TxTime <= level1)  					// 发送信号
		{
			IRSend_PIN_1;
		}
		else if (TxTime <= (level0+level1)) 	// 不发送信号
		{
			IRSend_PIN_0;
		}
		else if (Sendbit < 4)					// 发送4字节数据未完成
		{
			TxTime = 1;
            IRSend_PIN_1;
            SaveLastBit = IRSendData & TxBit;
			TxBit <<= 1;
			if (TxBit == 0x00)  				// 发送完一个字节
			{
				TxBit = 0x01;
                Sendbit++;
                IRSendData = IRData[Sendbit];
				if (Sendbit > 3)   				// 最后一位要注意，因为发送完了还要有一个脉冲
				{
                    SendLastBit = 1;
				}
			}
		}
        else									// 数据完成了，要补脉冲
        {
        	if(SendLastBit)
 		   	{
		    	TxTime++;
		    	if(SaveLastBit)
		        {
		        	if(TxTime < 3)
		            {
		            	IRSend_PIN_0;
		            }
		            else if(TxTime < 4)
		            {
		            	IRSend_PIN_1;
		            }
		            else
		            {
		            	IRSend_PIN_0;
						IRSendStatus = Status_NOSend;
		                IRSend_PIN_0;
		                SendLastBit = 0;
                        TxBit = 0;
                        TxTime = 0;
		            }
		        }
		        else
		        {
		        	if(TxTime < 5)
		            {
		            	IRSend_PIN_0;
		            }
		            else if(TxTime < 6)
		            {
		            	IRSend_PIN_1;
		            }
		            else
		            {
		            	IRSend_PIN_0;
						IRSendStatus = Status_NOSend;
		                IRSend_PIN_0;
		                SendLastBit = 0;
                        TxBit = 0;
                        TxTime = 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;    //开总中断
}

/*-------------------------------------------------
 *  函数名：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++);
	}
}

/*-------------------------------------------------
 *  函数名：TC0_PWM1_SET
 *	功能：  使用PWM1产生 38KHZ占空比50%方波,作为发送IR的载波,周期为1/38ms=26.3us   
 *  PWM占空比计算方法 ：Fcpu = 4M/2=2M;   TC0定时器选择2分频得：TC0的时钟为 1M; TC0R=(256-26)=230=0XE6        
             ：所以  计数器初值 TC0R=(256-26)=230=0XE6   
             ：TC0D1:计数初值+周期/2 = 230+26/2= 243 = 0XF3;   
 --------------------------------------------------*/	
void TC0_PWM1_SET(void) //配置500MS 唤醒一次睡眠 ，睡眠后 TC0时钟为16K ，我们选择32分频 
{  		                
		TC0M = 0xF1;//20;	//选择 8位计数器，2分频
						//0010 0000;//Fcpu 2'-8bit-   //定时器TC0时钟配置
		             	//Bit7 TC0TR, TC0启动控制位 0 禁止TC0定时器
                        //Bit6:4 TC0S[2:0], TC0分频选择位 011 32分频
                        //Bit3 TC0时钟信号选择位, 0 TC0时钟来自Fcpu
                        //BIT2 T16SEL,1  8/16位溢出位选择 0 低8位为溢出位
                        //BIT1 BUZ, BUZ输出使能位 0 关闭BUZ输出
                        //BIT0 PWM0, PWM0输出使能位 0 关闭PWM0输出

		TC0R= 0XE6;		//重装载值	                
		TC0D1 = 0XF2;  //高电平占空比
		
		PWMCON = 0X01;						
		FTC0TR=1; 		//开启TC0定时器   		                      			
}



//****主函数****//
void main(void) 
{
    GPIO_Init();
    time0_init();  //TIME0定时器初始化；
	TC0_PWM1_SET();// PWM1映射到PB1产生38KHZ用作RF发码的载波
    while(1)
    {
    	  IRSendStatus = Status_Head;  //500ms发送一次6122码, IRSendStatus赋一次1，发送一帧码
    	  delay_ms(500);	  
    }
}
