前言
TLSR825X集成了一个逐次逼近型(SAR)ADC模块,可以应用在电池电压、温度、单声道或立体声音频信号的采样
本章主要讲解下差分ADC模拟信号采样的功能,如有异议,欢迎留言指正
功能与参数
- ADC时钟通过外部24MHz晶体时钟源通过分频因子分频后获得,公式如下
Fadc_clk = 24MHz/(adc_clk_div+1)
- 如下支持ADC的10个管脚输入通道
GPIO_PinTypeDef ADC_GPIO_tab[10] = {
GPIO_PB0,GPIO_PB1,
GPIO_PB2,GPIO_PB3,
GPIO_PB4,GPIO_PB5,
GPIO_PB6,GPIO_PB7,
GPIO_PC4,GPIO_PC5
};
- ADC仅支持差分模式(differential mode),测量电池电压时可将负端配置到GND
- ADC支持 Left、Right、Misc三个通道,无法同时工作,必须通过状态机切换来运行采样
- 三个通道都包含一个设置
set
状态和捕获Capture
状态
- 三个通道都包含一个设置
代码实例
初始化
- 参考例程
app_adc.c
,初始化adc代码如下
void app_adc_test_init(void)
{
/******关闭adc电源********/
adc_power_on_sar_adc(0);
/****** 使能adc 24nhz时钟源********/
adc_enable_clk_24m_to_sar_adc(1);
/******采用时钟 4MHz******/
adc_set_sample_clk(5); //采样时钟 = 24M/(1+5)=4M
/******配置左右增益偏置,电池检测可以不用配置******/
adc_set_left_gain_bias(GAIN_STAGE_BIAS_PER100);
adc_set_right_gain_bias(GAIN_STAGE_BIAS_PER100);
Step 3: Config adc settings as needed /
#if (TEST_ADC_SELECT == TEST_ADC_GPIO)
adc_gpio_ain_init();
#elif (TEST_ADC_SELECT == TEST_ADC_VBAT)
adc_vbat_detect_init();
#endif
/******开启adc电源********/
adc_power_on_sar_adc(1);
}
设置参数
- 配置使能adc通道参数与映射管脚
void adc_gpio_ain_init(void)
{
//set misc channel en, and adc state machine state cnt 2( "set" stage and "capture" state for misc channel)
adc_set_chn_enable_and_max_state_cnt(ADC_MISC_CHN, 2); //使能MISC通道与状态数
//set "capture state" length for misc channel: 240
//set "set state" length for misc channel: 10
//adc 状态机执行周期 = 24M/250 = 96K, T = 10.4 uS
adc_set_state_length(240, 0, 10); //设置 R_max_mc,R_max_c,R_max_s ,这里仅配置MISC通道的set与capture状态
//PB4差分正端 GND为差分负端
gpio_set_func(GPIO_PB4, AS_GPIO);
gpio_set_input_en(GPIO_PB4, 0);
gpio_set_output_en(GPIO_PB4, 0);
gpio_write(GPIO_PB4, 0);
adc_set_ain_channel_differential_mode(ADC_MISC_CHN, B4P, GND);
//采样分辨率14位;差分模式下最高位为符号位(bit13)
adc_set_resolution(ADC_MISC_CHN, RES14); //set resolution
//参考电压1.2V
adc_set_ref_voltage(ADC_MISC_CHN, ADC_VREF_1P2V); //set channel Vref
//配置6个时钟周期为一次采样 6/4M = 1.5
adc_set_tsample_cycle(ADC_MISC_CHN, SAMPLING_CYCLES_6); //Number of ADC clock cycles in sampling phase
//设置模拟输入缩放比例1/8,可支持输入0~9.6V
adc_set_ain_pre_scaler(ADC_PRESCALER_1F8);
}
读取数据
- 通过接口
adc_sample_and_get_result
读取转换结果
u32 tick_adc_sample = 0;
void app_adc_test_start(void)
{
if(clock_time_exceed(tick_adc_sample, 200000)){//200ms读取一次
tick_adc_sample = clock_time();
Adc_cur_rawData = adc_sample_and_get_result();//获取采样数据
Adc_raw_data[Adc_raw_datIndex ++] = Adc_cur_rawData;
#if 1 //debug 显示使用
Adc_cur_vol_oct = (Adc_cur_rawData/1000)<<12 | ((Adc_cur_rawData/100)%10)<<8 \
| ((Adc_cur_rawData%100)/10)<<4 | (Adc_cur_rawData%10);
Adc_cal_vol_oct[Adc_cal_vol_octIndex ++] = Adc_cur_vol_oct; //用作显示
#endif
}
}
采样接口解读
- 采样读取接口代码,内部会进行8次读取并取平均,最终返回电压值;这里强调下adc_vol_mv换算需要根据自己实际配置来做相对应的修改
- ADC采样数据的获取使用了Dfifo mode,默认采样8byte数据,adc采样周期为10.4uS,总数据获取时长为83uS
- 例程中仅配置了Misc,Td时间计算公式为 Td = (1r_max_s + 1max_mc)/24M = (240+10)/24 ≈ 10.4uS
- 例程中仅配置了Misc,Td时间计算公式为 Td = (1r_max_s + 1max_mc)/24M = (240+10)/24 ≈ 10.4uS
#define ADC_SAMPLE_NUM 8 //一次采集8个数据
/**
* @brief This function serves to set adc sampling and get results.
* @param[in] none.
* @return the result of sampling.
*/
unsigned int adc_sample_and_get_result(void)
{
unsigned short temp;
volatile signed int adc_data_buf[ADC_SAMPLE_NUM]; //size must 16 byte aligned(16/32/64...)
int i,j;
unsigned int adc_vol_mv = 0;
unsigned short adc_sample[ADC_SAMPLE_NUM] = {0};//数据缓存
unsigned short adc_result=0;
adc_reset_adc_module();//复位adc模块
unsigned int t0 = clock_time();
for(i=0;i<ADC_SAMPLE_NUM;i++){ //清缓存数据
adc_data_buf[i] = 0;
}
while(!clock_time_exceed(t0, 25)); //等待至少2个采样周期 wait at least 2 sample cycle(f = 96K, T = 10.4us)
//buf缓存地址映射dfifo setting will lose in suspend/deep, so we need config it every time
adc_config_misc_channel_buf((unsigned short *)adc_data_buf, ADC_SAMPLE_NUM<<2); //size: ADC_SAMPLE_NUM*4
dfifo_enable_dfifo2();//使能dfifo
get adc sample data and sort these data
for(i=0;i<ADC_SAMPLE_NUM;i++){
/*wait for new adc sample data, When the data is not zero and more than 1.5 sampling times (when the data is zero),
The default data is already ready.*/
while((!adc_data_buf[i])&&(!clock_time_exceed(t0,25)));//通过判断数据非0与等待1.5个采样时间
t0 = clock_time();
if(adc_data_buf[i] & BIT(13)){ //判断符号位 14 bit resolution, BIT(13) is sign bit, 1 means negative voltage in differential_mode
adc_sample[i] = 0;
}
else{
adc_sample[i] = ((unsigned short)adc_data_buf[i] & 0x1FFF); //BIT(12..0) is valid adc result
}
//排序 insert sort
if(i){
if(adc_sample[i] < adc_sample[i-1]){
temp = adc_sample[i];
adc_sample[i] = adc_sample[i-1];
for(j=i-1;j>=0 && adc_sample[j] > temp;j--){
adc_sample[j+1] = adc_sample[j];
}
adc_sample[j+1] = temp;
}
}
}
//
dfifo_disable_dfifo2(); //禁用dfifo misc channel data dfifo disable
/ get average value from raw data(abandon some small and big data ), then filter with history data //
#if (ADC_SAMPLE_NUM == 4) //use middle 2 data (index: 1,2)
unsigned int adc_average = (adc_sample[1] + adc_sample[2])/2;
#elif(ADC_SAMPLE_NUM == 8) //use middle 4 data (index: 2,3,4,5)
unsigned int adc_average = (adc_sample[2] + adc_sample[3] + adc_sample[4] + adc_sample[5])/4; //均值滤波
#endif
adc_code=adc_result = adc_average;
adc sample data convert to voltage(mv)
// (Vref, 1/8 scaler) (BIT<12~0> valid data)
// = adc_result * Vref * 8 / 0x2000
// = adc_result * Vref >>10
adc_vol_mv = (adc_result * adc_vref_cfg.adc_vref)>>10; //换算电压值
return adc_vol_mv;
}
PS:adc寄存器可查看数据手册第11章11.4节