/*Copyright (C), 2024-2030
*文件名:	ADC.c
*版  本:	Ver1.00
*日  期:	2025/04/30
*描  述:	ADC配置
*备  注:     
**********************************************************/
#include "ADC.h"
#include "BL51F003T.h"	
#include "stdio.h"
#include "Nvr_Flash.h"

/*********************************************************/
#define 	ATMS 			0x03  /* 采样周期	*/
#define 	ACKS 			0x00  /* 分频 0-7 */
#define		BGVS			0x03  /* 内部基准选择 0-3 */




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

xdata INT8U buff[24];
INT16S K_High = 0;
INT8S sign;
/*********************************************************/
/**
	* @brief  延时函数
  * @param  
  * @retval None
	*/
static void delay(void)
{
	int j;
	for(j=0; j<40; ++j);
}

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

/**
	* @brief  读取采样到的ADC值，并求平均值。
  * @param  None
  * @retval ADC的平均值
	*/
#define		SMP_NUM		32  	/* 采样个数 */
#define		DIS_NUM		10	 		/* 丢弃最小的和最大的各DIS_NUM个 */
int read_adc()
{
	INT16S time_cnt;
	INT32S sum = 0;
	INT8S smpok = 0, 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();
			smpok = 1;
			time_cnt--;
			if(!time_cnt)
			{
				break;
			}
		}
		
		if(smpok)
		{
			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  读取NVR中的triming值
  * @param  None
	* @retval 0: 未校准, 1:已校准
	*/
INT8U Check_NG=0;
bit read_triming_val()
{
	xdata INT8U cnt=0;
	read_nvr(buff, NVR4_START_ADC_ADDR, 24);//读NVR4扇区
	for(cnt=0;cnt<=9;cnt++)//0x628-0x620
	{
		if(buff[cnt] == 0xff)	
		{	
			Check_NG++;//未校准
		}
		else
		{
			Check_NG--;//已校准
		}
	}
	if(Check_NG >= 8) 
		return 0;//未校准
	else	
		return 1;//已校准
}

/**
	* @brief  ADC的校准值获取
  * @param  None
	* @retval 0:未校准, 1:已校准
	*/
bit ADC_NVR_CHECK()
{
	bit ret = 0;
	
	ret = read_triming_val();	//读取NVR中校准值，0:未校准, 1:已校准
	if(ret == 0)
	{
		while(1);		
	}
	else
	{
	}
		
	return ret;
}
/**
	* @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
				K_High =  (buff[0x03]<<8)|buff[0x02];	//VDD基准的K值
				sign = buff[0x01];										//VDD基准K值正负标志
//				AKCON = 0x80|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
				K_High = (buff[0x08]<<8)|buff[0x07];				//内部4.096V基准的K值
				sign = buff[0x06];												//内部4.096V基准K值正负标志
//				AKCON = 0x80|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
				K_High = (buff[0x0D]<<8)|buff[0x0C];				//内部3.072V基准的K值
				sign = buff[0x0B];												//内部3.072V基准K值正负标志	
//				AKCON = 0x80|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
				K_High = (buff[0x12]<<8)|buff[0x11];				//内部2.048V基准的K值
				sign = buff[0x10];												//内部2.048V基准K值正负标志
//				AKCON = 0x80|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
				K_High = (buff[0x17]<<8)|buff[0x16];				//内部2.048V基准的K值
				sign = buff[0x15];												//内部2.048V基准K值正负标志
//				AKCON = 0x80|buff[0x15];								//内部2.048V基准K值正负标志
			break;
	}
}

int read_trimed_adc(char sign, int k)
{
	int temp0,temp1;
	long int temp;

	if(sign & 0x80) //k值溢出
	{
		temp0 = k;		
	}
	else
	{
		AKDAT = k & 0xFF;
	}

	if(!(sign & 0x80))//k值没溢出
	{
		AKCON = 0x80;
		temp = read_adc();
	}
	else
	{
		AKCON = 0x00;
		temp1 = read_adc();
	}			
	if(sign & 0x01)
	{
		if(sign & 0x80)
		{
			temp = temp1 - ((temp0 * temp1)>>14);
		}
	}
	else
	{
		if(sign & 0x80)
		{
			temp = temp1 + ((temp0 * temp1)>>14);				
		}
	}
	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(sign,K_High);	//读取ADC值，由串口打印输出
								
	
	adc_set_channel(CS_ADC_AIN1);		//第二路AD通道选择
	AD_BAT = read_trimed_adc(sign,K_High); 	//读取ADC值	，由串口打印输出
		
}