/*Copyright (C), 2024-2030
*文件名:	USER.c
*版  本:	Ver1.00
*日  期:	2025/04/30
*描  述:	常用函数定义
*备  注:     
**********************************************************/
#include "USER.h"
#include "BL51F003T.h"	
#include "stdio.h"
/*********************************************************/
#define 	ATMS 			0x07  /* 采样周期	*/
#define 	ACKS 			0x00  /* 分频 0-7 */





/*********************************************************/

xdata INT8U buff[24];
xdata INT8U ksign;
long int kdata;
/*********************************************************/
/**
	* @brief  延时函数
  * @param  
  * @retval None
	*/
static void delay(void)
{
	int j;
	for(j=0; j<40; ++j);
}
/**
	* @brief  NVR扇区读
  * @param  buf：待读入数据的数组指针
						SectorAddr: 起始地址
						len: 数据长度
  * @retval None
	*/
void read_nvr(unsigned char *buf,unsigned int SectorAddr,unsigned int len)
{
	INT16U i=0;

	FSCMD=NVR_READ;
	for(i=0; i<len; ++i)
	{
		FSPTSL =(SectorAddr&0xff);
		FSPTSH =((SectorAddr>>8)&0xff);
		++SectorAddr;
		buf[i] = FSDAT;
	}
}
/**********************************************************/

/**
	* @brief  读取采样到的ADC值，并求平均值。
  * @param  None
  * @retval ADC的平均值
	*/
#define		SMP_NUM		1 			/* 采样个数 */
#define		DIS_NUM		0	 		/* 丢弃最小的和最大的各DIS_NUM个 */
int read_adc()
{
	INT16S time_cnt;
	INT32S sum = 0;
	INT8S i, j, cnt = 0;
	xdata INT16S smp[SMP_NUM], min, avg = 0xffff;
	
	for(i=0; i<SMP_NUM; i++)
	{
		smp[i] = 0;
		time_cnt = 0xff;
		ADCON |= 0x80;
		while(ADCON & 0x80)
		{
			delay();
			time_cnt--;
			if(!time_cnt)
			{
				break;
			}
		}
		if((ADCON & 0x80) == 0)
		{
			smp[cnt] = (ADCDH<<4) | (ADCDL>>4);
			cnt++;
		}
	}

	for(i=0; i<cnt; i++)
	{
		min = smp[i];
		for(j=(i+1); j<cnt; j++)
		{
			if(smp[j] < min)
			{
				min = smp[j];
				smp[j] = smp[i];
				smp[i] = min;
			}
		}
	}

	if(cnt > (DIS_NUM*2))
	{
		for(i=DIS_NUM; i<(cnt-DIS_NUM); i++)
		{
			sum += smp[i];
		}
		avg = sum/(cnt-(DIS_NUM*2));
	}
	else if(cnt > 0)
	{
		avg = sum/cnt;
	}
	return avg;
}
/**
	* @brief  设置ADC通道
  * @param  None
  * @retval None
	*/
void adc_set_channel(ADC_CHN_ENUM chn)
{
	ADCHS = chn; 
}

/**
	* @brief  ADC的自校准步骤
  * @param  None
	* @retval 
	*/

#define		VSS_ADC_AIN		ADC_CHN_VSS 	//内部VSS通道，用于ADC校准测试，
void ADC_TRIM(unsigned char bgvs)			//
{
	bit OFS_flag;
	int adcval=0;
	int delta;
	int i;
	
	ADCON=0x00;						//不分频
	adc_set_channel(VSS_ADC_AIN);		//采样内部VSS通道
	
	ADCFG = 0x78; 				//采样保持128周期
	
	/*ADC基准选择*/
	if(bgvs == 1)
	{
		ADCBGP = 0xC0|buff[0x04];	//内部基准4.096V	
	}
	else if(bgvs == 2)
	{
		ADCBGP = 0x80|buff[0x09];	//内部基准3.072V					
	}
	else if(bgvs == 3)
	{
		ADCBGP = 0x40|buff[0x0e];	//内部基准2.048V			
	}
	else if(bgvs == 4)
	{		
		ADCBGP = buff[0x13];//内部基准1.024V	
	}
	else
	{
		ADCFG &= 0x3F; 								//VDD基准
	}	
	
	/*不同基准下ADCOFS测量*/
	for(i=0; i<128; i++)
	{	
		ADCOFS=i;
		adcval=read_adc();
	
		if((adcval == 0x00) || ((ADCOFS == 0x7f) && (adcval <= 2)))
		{
			OFS_flag = 0;
			break;
		}
		else 
			OFS_flag = 1;
	}		
	if(OFS_flag)
	{
		printf("ADC OPS NG \r\n");
		printf("ADC OPS NG \r\n");
		printf("ADC OPS NG \r\n");
		printf("-------------------- \r\n");
		while(1);
	}
	
	/*K值计算*/
	ADCHS=0x1F; 									//1/2基准通道 	
	adcval = read_adc(); 
	
	if(bgvs == 1)					//BGP=4.096
  {
		buff[0x05] = ADCOFS;
		if(adcval > 2048)			
		{
			ksign = 1;
			delta = adcval - 2048;
		}
		else
		{
			ksign = 0;
			delta = 2048 - adcval;
		}
		kdata = (delta<<13)/adcval;
		if(kdata > 0xff)
		{
			buff[0x06] = ksign | 0x80;
		}
		else
		{
			buff[0x06] = ksign;
		}
		buff[0x07] = (kdata & 0xff);
		buff[0x08] = (kdata >> 8);
	}
	else if(bgvs == 2)		//BGP=3.072
	{
		buff[0x0A] = ADCOFS;
		if(adcval > 2048)
		{
			ksign = 1;
			delta = adcval - 2048;
		}
		else
		{
			ksign = 0;
			delta = 2048 - adcval;
		}
		kdata = (delta<<13)/adcval;
		if(kdata > 0xff)
		{
			buff[0x0B] = ksign | 0x80;
		}
		else
		{
			buff[0x0B] = ksign;
		}		
		buff[0x0C] = (kdata & 0xff);
		buff[0x0D] = (kdata >> 8);
	}
	else if(bgvs == 3)		//BGP=2.048
	{
		buff[0x0F] = ADCOFS;
		if(adcval > 2048)
		{
			ksign = 1;				
			delta = adcval - 2048;
		}
		else 
		{
			ksign = 0;				
			delta = 2048 - adcval;
		}
		kdata = (delta<<13)/adcval;
		if(kdata > 0xff)
		{
			buff[0x10] = ksign | 0x80;
		}
		else
		{
			buff[0x10] = ksign;
		}				
		buff[0x11] = (kdata & 0xff);
		buff[0x12] = (kdata >> 8);
	}
	else if(bgvs == 4)		//BGP=1.024
	{
		buff[0x14] = ADCOFS;
		if(adcval > 2048)
		{
			ksign = 1;
			delta = adcval - 2048;
		}
		else
		{
			ksign = 0;
			delta = 2048 - adcval;
		}
		kdata = (delta<<13)/adcval;
		if(kdata > 0xff)
		{
			buff[0x15] = ksign | 0x80;
		}
		else
		{
			buff[0x15] = ksign;
		}					
		buff[0x16] = (kdata & 0xff);
		buff[0x17] = (kdata >> 8);
	}
	else	//VDD
	{
		buff[0x00] = ADCOFS;
		if(adcval > 2048)
		{
			ksign = 1;
			delta = adcval - 2048;
		}
		else
		{
			ksign = 0;
			delta = 2048 - adcval;				
		}
		kdata = (delta<<13)/adcval;
		if(kdata > 0xff)
		{
			buff[0x01] = ksign | 0x80;
		}
		else
		{
			buff[0x01] = ksign;
		}						
		buff[0x02] = (kdata & 0xff);
		buff[0x03] = (kdata >> 8);
	}		
}
/**
	* @brief  ADC的自校准
  * @param  None
	* @retval 0:未校准, 1:已校准
	*/

bit ADC_CHECK()
{
	
	INT8U i;
	printf("\ntrim val:\n");
	read_nvr(buff, NVR4_START_ADC_ADDR, 24);//读NVR4扇区 内部基准校准值
	printf("\nBGAP-4096:%bx",buff[0x04]);	//内部4.096 Bandgap
	printf("\nBGAP-3072:%bx",buff[0x09]);	//内部3.072 Bandgap	
	printf("\nBGAP-2048:%bx",buff[0x0E]);	//内部2.048 Bandgap
	printf("\nBGAP-1024:%bx",buff[0x13]); //内部1.024 Bandgap	
	
	if((buff[0x04]==0xff)&&(buff[0x09]==0xff)&&(buff[0x0E]==0xff)&&(buff[0x13]==0xff))
	{
		printf("\nadc is not trimed");//未校准芯片		
		printf("\nadc is not trimed");//未校准芯片	
		printf("\nadc is not trimed");//未校准芯片	
		while(1);
	}
	else
	{
		
		(*(unsigned char volatile xdata *)(0x8000 + VSS_ADC_AIN)) = 0x47;
		//ADC采用4.096V基准，采样内部VSS和1/2基准电压			
		//ADC采用3.072V基准，采样内部VSS和1/2基准电压	
		//ADC采用2.048V基准，采样内部VSS和1/2基准电压	
		//ADC采用1.024V基准，采样内部VSS和1/2基准电压	
		for (i = 0; i < 5; i++)
		{
			ADC_TRIM(i);			
		
		}	
		printf("\nadc is trimed");//已校准芯片	
		printf("\nadc is trimed");//已校准芯片	
		printf("\nadc is trimed");//已校准芯片	
		return 1;
	}
		
}
/**
	* @brief  ADC配置初始化
	* @param  None
	* @retval 
	*/

#define		CS_ADC_AIN		P02F_O 	//ADC通道IO初始化  
//#define		CS_ADC_AIN1		P03F_O 	//ADC通道IO初始化  
void ADC_INIT(INT8U i_model)
{	
	/* AIN 通道 */
	
 (*(unsigned char volatile xdata *)(0x8000 + CS_ADC_AIN)) = 0x07;
// (*(unsigned char volatile xdata *)(0x8000 + CS_ADC_AIN1)) = 0x07;

//	adc_set_channel(CS_ADC_AIN);		//采样通道选择为IO通道
//	adc_set_channel(CS_ADC_AIN1);		//采样通道选择为IO通道
//	adc_set_channel(ADC_CHN_OP);		//OPOUT通道，需要先开启OP初始化，可从例程复制粘贴
//	adc_set_channel(ADC_CHN_VSS);		//VSS通道
//	adc_set_channel(ADC_CHN_AVRF);		//1/4AVRF通道
//	adc_set_channel(ADC_CHN_VDD);		//1/4VDD通道
//	adc_set_channel(ADC_CHN_INNER);	//1/2内部基准通道
	
	switch(i_model)
	{
		case 0:/* VDD做参考电压 */			
				ADCON = (ACKS<<1); 
				ADCFG = (0x00<<6) | (ATMS<<3); 				//选择VDD作参考电压
				ADCOFS = buff[0x00];									//VDD基准的OFFSET
				kdata =  (buff[0x03]<<8)|buff[0x02];	//VDD基准的K值
				ksign = buff[0x01];										//VDD基准K值正负标志
			break;
			
		case 1:/* 内部基准4.096V做参考电压 */
				ADCON = (ACKS<<1); 
				ADCFG = (0x01<<6) | (ATMS<<3); 						//选择内部参考电压
				ADCBGP = buff[0x04] & 0x3F;								//内部4.096V基准的校准值
				ADCBGP |= (0x03<<6);											//基准电压选择内部4.096V		
				ADCOFS = buff[0x05];											//内部4.096V基准的OFFSET
				kdata = (buff[0x08]<<8)|buff[0x07];			//内部4.096V基准的K值
				ksign = buff[0x06];												//内部4.096V基准K值正负标志
			break;
			
		case 2:/* 内部基准3.072V做参考电压 */
				ADCON = (ACKS<<1); 
				ADCFG = (0x01<<6) | (ATMS<<3); 						//选择内部参考电压
				ADCBGP =  buff[0x09] & 0x3F;							//内部3.072V基准的校准值
				ADCBGP |= (0x02<<6);											//基准电压选择内部3.072V		
				ADCOFS = buff[0x0A];											//内部3.072V基准的OFFSET
				kdata = (buff[0x0D]<<8)|buff[0x0C];				//内部3.072V基准的K值
				ksign = buff[0x0B];												//内部3.072V基准K值正负标志	
			break;
			
		case 3:/* 内部基准2.048V做参考电压 */		
				ADCON = (ACKS<<1); 
				ADCFG = (0x01<<6) | (ATMS<<3); 						//选择内部参考电压
				ADCBGP = buff[0x0E] & 0x3F;								//内部2.048V基准的校准值
				ADCBGP |= (0x01<<6);											//基准电压选择内部2.048V		
				ADCOFS = buff[0x0F];											//内部2.048V基准的OFFSET
				kdata = (buff[0x12]<<8)|buff[0x11];				//内部2.048V基准的K值
				ksign = buff[0x10];												//内部2.048V基准K值正负标志
			break;
		
		case 4:/* 内部基准1.024V做参考电压 */		
				ADCON = (ACKS<<1); 
				ADCFG = (0x01<<6) | (ATMS<<3); 						//选择内部参考电压
				ADCBGP = buff[0x13] & 0x3F;								//内部2.048V基准的校准值
				ADCBGP |= (0x00<<6);											//基准电压选择内部2.048V		
				ADCOFS = buff[0x14];											//内部2.048V基准的OFFSET
				kdata = (buff[0x17]<<8)|buff[0x16];				//内部2.048V基准的K值
				ksign = buff[0x15];												//内部2.048V基准K值正负标志
			break;
	}
}
int read_trimed_adc(char sign, int k)
{
	int temp0;
	long int temp;

	if(sign & 0x80) //k值溢出
	{	
		AKCON = 0x00;
		temp0 = read_adc();
		if(sign & 0x01)
		{
			temp = temp0 - ((k * temp0)>>13);			
		}
		else
		{
			temp = temp0 + ((k * temp0)>>13);					
		}		
	}
	else
	{
		AKDAT = k & 0xFF;
		AKCON = 0x80 || (sign & 0x01);
		temp = read_adc();		
	}
	return temp;
}


xdata INT16U AD_TEMP=0,AD_BAT=0;
/**
	* @brief  ADC扫描采样
	* @param  None
	* @retval 
	*/
void ADC_SCAN(void)
{
	adc_set_channel(CS_ADC_AIN);		//第一路AD通道选择
	AD_TEMP = read_trimed_adc(ksign,kdata);	//读取ADC值，由串口打印输出
	printf("\nAD_TEMP:\%d",AD_TEMP);
								
	
//	adc_set_channel(CS_ADC_AIN1);		//第二路AD通道选择
//	AD_BAT = read_trimed_adc(sign,K_High); 	//读取ADC值	，由串口打印输出
//	printf("\nAD_BAT:\%d",AD_BAT);
		
}