概述
本章描述12位逐次逼近寄存器(SAR)型模数转换器(ADC)的使用方法,ADC转换结果存储在结果寄存器中,支持按需读取。
ADC的相关参数如下:
分辨率:
12
位ENOB:
10
位采样频率:
31.25
kHz ~250
kHz,建议值为166.67
kHz(默认)采样电容:
2.4
pF ~2.93
pF参考电压:固定,不可外供
内部阻抗:
500
kΩ左右FIFO:
64
*16
位通道切换列表长度:
1
~16
通道参数如下表所示:
通道 |
通道号 |
引脚 |
输入电压(V) |
---|---|---|---|
常规通道 |
CH0~CH6 |
PB13~PB19 |
0 ~ 3.3 |
电池测量通道 |
CH7 |
BAT_MEAS |
0 ~ 5 |
通道 |
通道号 |
引脚 |
输入电压(V) |
---|---|---|---|
常规通道 |
CH0~CH5 |
PB5~PB0 |
0 ~ 3.3 |
通道 |
通道号 |
引脚 |
输入电压(V) |
---|---|---|---|
常规通道 |
CH0~CH5 |
PB5~PB0 |
0 ~ 3.3 |
通道 |
通道号 |
引脚 |
输入电压(V) |
---|---|---|---|
常规通道 |
CH0~CH5 |
PA0 ~ PA5 |
0 ~ 1.8 |
电池测量通道 |
CH6 |
BAT_MEAS |
0 ~ 5 |
备注
ADC多通道采样分时复用同一个ADC采样电路。上述采样频率是针对单个通道的参数,当通道切换列表中设置多个不同的通道时,对单个通道的采样频率会同比成倍降低。
ADC采样模式
ADC仅支持 连续采样模式。该模式下,ADC不间断地按序对通道列表的通道进行采样,开关均可控,适合短时间内对电压连续采样。
ADC支持 多通道采样,用户可以配置 通道切换列表 ,参数包括 采样通道数量 和 采样通道切换顺序。
ADC采样顺序为:每当触发信号产生,ADC会对通道列表中的所有通道按序进行采样。
使用ADC连续采样模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
备注
BAT_MEAS
引脚为专用引脚,不需要执行该步骤。设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_AUTO_MODE; // 设置采样模式为连续采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
通过轮询模式或中断模式读取ADC采样数据
轮询模式:
ADC_ReceiveBuf(u16 *pBuf, u32 len);
中断模式:
ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, ENABLE); InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, NULL, INT_PRI_MIDDLE); InterruptEn(ADC_IRQ, INT_PRI_MIDDLE); ADC_AutoCSwCmd(ENABLE);
其中, ADCIrqHandle 的定义为:
u32 ADCIrqHandle(void *para) { (void *)para; u32 status = ADC_GetISR(); if (status & ADC_BIT_IT_FIFO_FULL_STS) { while (ADC_Readable()) { u32 sample_value = ADC_Read(); // 读出采样值 if (sample_cnt ++ > MAX_SAMPLE_CNT) { // 读到足够多的采样值 ADC_AutoCSwCmd(DISABLE); ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, DISABLE); InterruptDis(ADC_IRQ); break; } } } ADC_INTClearPendingBits(status); return 0; }
ADC支持以下采样模式:
连续采样模式:ADC不间断地按序对通道列表中的通道进行采样,开关均可控,适合短时间内对电压连续采样。
软件触发采样模式:软件每触发一次采样,ADC输出一组数据。
定时器触发采样模式:通过设置基础定时器周期,定时触发ADC采样,ADC输出一组数据。
ADC支持 多通道采样,用户可以配置 通道切换列表 ,参数包括 采样通道数量 和 采样通道切换顺序。
ADC采样顺序为:
首次触发采样时,ADC对通道列表中的第一个通道进行采样。
每当新的触发信号产生,ADC将自动切换到下一个通道。
当通道列表中最后一个通道采样完成,ADC会在下一次触发信号产生后,对通道列表中的第一个通道进行采样。
使用ADC连续采样模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_AUTO_MODE; // 设置采样模式为连续采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
通过轮询模式或中断模式读取ADC采样数据
轮询模式:
ADC_ReceiveBuf(u16 *pBuf, u32 len);
中断模式:
ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, ENABLE); InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, NULL, INT_PRI_MIDDLE); InterruptEn(ADC_IRQ, INT_PRI_MIDDLE); ADC_AutoCSwCmd(ENABLE);
其中, ADCIrqHandle 的定义为:
u32 ADCIrqHandle(void *para) { (void *)para; u32 status = ADC_GetISR(); if (status & ADC_BIT_IT_FIFO_FULL_STS) { while (ADC_Readable()) { u32 sample_value = ADC_Read(); // 读出采样值 if (sample_cnt ++ > MAX_SAMPLE_CNT) { // 读到足够多的采样值 ADC_AutoCSwCmd(DISABLE); ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, DISABLE); InterruptDis(ADC_IRQ); break; } } } ADC_INTClearPendingBits(status); return 0; }
使用ADC软件触发模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_SW_TRI_MODE; // 设置采样模式为软件触发采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
读取ADC采样数据
ADC_SWTrigCmd(ENABLE); while(ADC_Readable() == 0); ADC_SWTrigCmd(DISABLE); u32 sample_data = ADC_Read();
使用ADC定时器触发模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_TIM_TRI_MODE; // 设置采样模式为定时器触发采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
确定基本定时器序号tim_idx并设置周期period,通过中断处理函数读取ADC采样数据
ADC_INTConfig(ADC_BIT_IT_CV_END_EN | ADC_BIT_IT_CVLIST_END_EN, ENABLE); InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, tim_idx, INT_PRI_MIDDLE); InterruptEn(ADC_IRQ, INT_PRI_MIDDLE); ADC_TimerTrigCmd(tim_idx, period, ENABLE);
其中, ADCIrqHandle 的定义如下:
u32 ADCIrqHandle(void *para) { u32 tim_idx = (u32)para; u32 status = ADC_GetISR(); u32 value; if (status & ADC_BIT_IT_CV_END_STS) { while (ADC_Readable() == 0); value = ADC_Read(); printf("ch:%d, data:%d\n", ADC_GET_CH_NUM_GLOBAL(value), ADC_GET_DATA_GLOBAL(value)); } if (status & ADC_BIT_IT_CVLIST_END_STS) { ADC_TimerTrigCmd(tim_idx, 0, DISABLE); printf("All conversion finished in channel list\n"); } ADC_INTClearPendingBits(status); return 0; }
ADC支持以下采样模式:
连续采样模式:ADC不间断地按序对通道列表中的通道进行采样,开关均可控,适合短时间内对电压连续采样。
软件触发采样模式:软件每触发一次采样,ADC输出一组数据。
定时器触发采样模式:通过设置基础定时器周期,定时触发ADC采样,ADC输出一组数据。
ADC支持 多通道采样,用户可以配置 通道切换列表 ,参数包括 采样通道数量 和 采样通道切换顺序。
ADC采样顺序为:
首次触发采样时,ADC对通道列表中的第一个通道进行采样。
每当新的触发信号产生,ADC将自动切换到下一个通道。
当通道列表中最后一个通道采样完成,ADC会在下一次触发信号产生后,对通道列表中的第一个通道进行采样。
使用ADC连续采样模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_AUTO_MODE; // 设置采样模式为连续采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
通过轮询模式或中断模式读取ADC采样数据
轮询模式:
ADC_ReceiveBuf(u16 *pBuf, u32 len);
中断模式:
ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, ENABLE); InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, NULL, INT_PRI_MIDDLE); InterruptEn(ADC_IRQ, INT_PRI_MIDDLE); ADC_AutoCSwCmd(ENABLE);
其中, ADCIrqHandle 的定义为:
u32 ADCIrqHandle(void *para) { (void *)para; u32 status = ADC_GetISR(); if (status & ADC_BIT_IT_FIFO_FULL_STS) { while (ADC_Readable()) { u32 sample_value = ADC_Read(); // 读出采样值 if (sample_cnt ++ > MAX_SAMPLE_CNT) { // 读到足够多的采样值 ADC_AutoCSwCmd(DISABLE); ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, DISABLE); InterruptDis(ADC_IRQ); break; } } } ADC_INTClearPendingBits(status); return 0; }
使用ADC软件触发模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_SW_TRI_MODE; // 设置采样模式为软件触发采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
读取ADC采样数据
ADC_SWTrigCmd(ENABLE); while(ADC_Readable() == 0); ADC_SWTrigCmd(DISABLE); u32 sample_data = ADC_Read();
使用ADC定时器触发模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_TIM_TRI_MODE; // 设置采样模式为定时器触发采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
确定基本定时器序号tim_idx并设置周期period,通过中断处理函数读取ADC采样数据
ADC_INTConfig(ADC_BIT_IT_CV_END_EN | ADC_BIT_IT_CVLIST_END_EN, ENABLE); InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, tim_idx, INT_PRI_MIDDLE); InterruptEn(ADC_IRQ, INT_PRI_MIDDLE); ADC_TimerTrigCmd(tim_idx, period, ENABLE);
其中, ADCIrqHandle 的定义如下:
u32 ADCIrqHandle(void *para) { u32 tim_idx = (u32)para; u32 status = ADC_GetISR(); u32 value; if (status & ADC_BIT_IT_CV_END_STS) { while (ADC_Readable() == 0); value = ADC_Read(); printf("ch:%d, data:%d\n", ADC_GET_CH_NUM_GLOBAL(value), ADC_GET_DATA_GLOBAL(value)); } if (status & ADC_BIT_IT_CVLIST_END_STS) { ADC_TimerTrigCmd(tim_idx, 0, DISABLE); printf("All conversion finished in channel list\n"); } ADC_INTClearPendingBits(status); return 0; }
ADC支持以下采样模式:
连续采样模式:ADC不间断地按序对通道列表中的通道进行采样,开关均可控,适合短时间内对电压连续采样。
软件触发采样模式:软件每触发一次采样,ADC输出一组数据。
定时器触发采样模式:通过设置基础定时器周期,定时触发ADC采样,ADC输出一组数据。
ADC支持 多通道采样,用户可以配置 通道切换列表 ,参数包括 采样通道数量 和 采样通道切换顺序。
ADC采样顺序为:
首次触发采样时,ADC对通道列表中的第一个通道进行采样。
每当新的触发信号产生,ADC将自动切换到下一个通道。
当通道列表中最后一个通道采样完成,ADC会在下一次触发信号产生后,对通道列表中的第一个通道进行采样。
使用ADC连续采样模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
备注
BAT_MEAS
引脚为专用引脚,不需要执行该步骤。设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_AUTO_MODE; // 设置采样模式为连续采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
通过轮询模式或中断模式读取ADC采样数据
轮询模式:
ADC_ReceiveBuf(u16 *pBuf, u32 len);
中断模式:
ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, ENABLE); InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, NULL, INT_PRI_MIDDLE); InterruptEn(ADC_IRQ, INT_PRI_MIDDLE); ADC_AutoCSwCmd(ENABLE);
其中, ADCIrqHandle 的定义为:
u32 ADCIrqHandle(void *para) { (void *)para; u32 status = ADC_GetISR(); if (status & ADC_BIT_IT_FIFO_FULL_STS) { while (ADC_Readable()) { u32 sample_value = ADC_Read(); // 读出采样值 if (sample_cnt ++ > MAX_SAMPLE_CNT) { // 读到足够多的采样值 ADC_AutoCSwCmd(DISABLE); ADC_INTConfig(ADC_BIT_IT_FIFO_OVER_EN | ADC_BIT_IT_FIFO_FULL_EN, DISABLE); InterruptDis(ADC_IRQ); break; } } } ADC_INTClearPendingBits(status); return 0; }
使用ADC软件触发模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
备注
BAT_MEAS
引脚为专用引脚,不需要执行该步骤。设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_SW_TRI_MODE; // 设置采样模式为软件触发采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
读取ADC采样数据
ADC_SWTrigCmd(ENABLE); while(ADC_Readable() == 0); ADC_SWTrigCmd(DISABLE); u32 sample_data = ADC_Read();
使用ADC定时器触发模式的步骤如下:
启用ADC模块的时钟与功能
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE); RCC_PeriphClockCmd(APBPeriph_CTC, APBPeriph_CTC_CLOCK, ENABLE);
根据Pinmux映射表配置ADC引脚复用
例如:调用以下函数来使用ADC0通道。
Pinmux_Config(ADC_CH0_PIN, PINMUX_FUNCTION_xxx); // 参考pinmux table配置function ID PAD_InputCtrl(ADC_CH0_PIN, DISABLE); PAD_PullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL); PAD_SleepPullCtrl(ADC_CH0_PIN, GPIO_PuPd_NOPULL);
备注
BAT_MEAS
引脚为专用引脚,不需要执行该步骤。设置默认参数,并修改ADC工作模式。默认ADC对所有通道按序采样
ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct); ADC_InitStruct->ADC_OpMode = ADC_TIM_TRI_MODE; // 设置采样模式为定时器触发采样
如有需要,修改ADC_InitStruct结构体,调整通道列表及其他参数
例如:用户设置通道切换列表的长度为 3 ,分别对通道0、通道2和通道4进行采样。
ADC_InitStruct->ADC_CvlistLen = 3 - 1; // 设置通道列表长度 ADC_InitStruct->ADC_Cvlist[0] = ADC_CH0; // 设置第一个通道号 ADC_InitStruct->ADC_Cvlist[1] = ADC_CH2; // 设置第二个通道号 ADC_InitStruct->ADC_Cvlist[2] = ADC_CH4; // 设置第三个通道号
初始化ADC,并启用ADC
ADC_Init(ADC_InitTypeDef *ADC_InitStruct); ADC_Cmd(ENABLE);
确定基本定时器序号tim_idx并设置周期period,通过中断处理函数读取ADC采样数据
ADC_INTConfig(ADC_BIT_IT_CV_END_EN | ADC_BIT_IT_CVLIST_END_EN, ENABLE); InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, tim_idx, INT_PRI_MIDDLE); InterruptEn(ADC_IRQ, INT_PRI_MIDDLE); ADC_TimerTrigCmd(tim_idx, period, ENABLE);
其中, ADCIrqHandle 的定义如下:
u32 ADCIrqHandle(void *para) { u32 tim_idx = (u32)para; u32 status = ADC_GetISR(); u32 value; if (status & ADC_BIT_IT_CV_END_STS) { while (ADC_Readable() == 0); value = ADC_Read(); printf("ch:%d, data:%d\n", ADC_GET_CH_NUM_GLOBAL(value), ADC_GET_DATA_GLOBAL(value)); } if (status & ADC_BIT_IT_CVLIST_END_STS) { ADC_TimerTrigCmd(tim_idx, 0, DISABLE); printf("All conversion finished in channel list\n"); } ADC_INTClearPendingBits(status); return 0; }
备注
采样结果由4位通道号和12位采样值组成。用户可以分别通过以下宏获取:
ADC_GET_CH_NUM_GLOBAL(sample_data):获取4位通道号
ADC_GET_DATA_GLOBAL(sample_data):获取12位采样值
ADC校准
ADC电压校准
为了改善ADC输入/输出特性的线性度,将在工厂阶段对芯片进行ADC非线性校准。通过非线性校准,可以减小ADC的增益误差与偏移误差。
ADC校准采用5点曲线拟合法,按照最小方差原则计算得到校准参数A/B/C。校准完成后,每颗芯片将获得专属参数A/B/C,并将其存储于 OTP 中。
在得到ADC数值采样之后,按下列公式计算当前电压(单位:mV),其中参数 \(x\) 为ADC采样值:
\[\begin{split}\begin{aligned} y &= ax^2 + bx + c \\ &= \frac{A}{2^{26}}x^2 + \frac{B}{2^{15}}x + \frac{C}{2^{6}} \end{aligned}\end{split}\]常规通道与电池测量通道的校对参数不同,用户可分别通过以下API获取校准电压:
ADC_GetVoltage(u32 chan_data):获取常规电压
ADC_GetVBATVoltage(u32 vbat_data):获取电池电压
ADC内部电阻校准
不同芯片的ADC内部电阻
R
存在差异,此差异直接影响测量精度:ADC 内部电阻
理想电压:\(V_{理想} = \frac{V_{cc} \times R_{2}}{R_{1} + R_{2}}\)
实际电压:\(V_{实际} = \frac{V_{cc} \times R_{2}//R}{R_{1} + R_{2}//R}\)
电压关系:由于内部电阻分压效应,\(V_{实际} < V_{理想}\)
误差规律:阻值比 \(\frac{R_{1} \times R_{2}}{R}\) 越大,实际电压与理想电压偏差越大
用户可直接通过
ADC_GetInterR()
获取内部电阻
ADC数字比较器
ADC包含数字比较器,如果指定通道的采样数值在设置的范围内,会产生对应中断,用户可以在中断处理程序中进行特定的操作,如读取当前电压等。
数字比较器在ADC的所有采样模式下都可以工作。
数字比较器支持以下 比较模式 :
小于低阈值
大于高阈值
大于等于低阈值 且 小于等于高阈值
小于低阈值 或 大于高阈值
备注
低阈值和高阈值的取值范围为 0 ~ 4095
,建议低阈值不要超过高阈值。
以连续采样模式为例,如果要使用ADC数字比较器,请按照以下步骤操作:
启用ADC模块的时钟与功能,同上。
根据Pinmux映射表配置ADC引脚复用,同上。
指定通道并设置比较器的低阈值、高阈值和比较模式。
例如:调用以下函数来设置ADC0通道的比较模式,当采样值大于等于2000且小于等于3000时会有中断产生。
ADC_SetComp(ADC_CH0, 3000, 2000, ADC_COMP_WITHIN_THL_AND_THH); InterruptRegister((IRQ_FUN)ADCIrqHandle, ADC_IRQ, NULL, INT_PRI_MIDDLE); InterruptEn(ADC_IRQ, INT_PRI_MIDDLE);
其中, ADCIrqHandle 的定义如下:
u32 ADCIrqHandle(void *para) { (void)para; u32 status = ADC_GetISR(); u32 value; if (status & ADC_BIT_IT_COMP_ALL_STS) { printf("ISR:0x%x, Comp status:0x%x\n", status, ADC->ADC_COMP_STS); // ADC在指定通道的采样值落在设置范围内 while (ADC_Readable() == 0); value = ADC_Read(); } ADC_INTClearPendingBits(status); return 0; }
设置默认参数,并修改ADC工作模式,同上。
如有需要,修改
ADC_InitStruct
结构体,调整通道列表及其他参数,同上。初始化ADC,并启用ADC,同上。
建议通过轮询模式读取ADC采样数据。
ADC常见问题排查
采样电压偏移
现象 |
采样电压偏移 |
原因 |
|
解决方法 |
|
备注
如果条件满足,可以考虑将应用电路一起校准。
参考硬件设计手册,获取ADC内部阻抗值。
通道间串扰
现象 |
通道间串扰 |
原因 |
|
解决方法 |
|
采样电压干扰
现象 |
采样电压干扰,信噪比低 |
原因 |
PCB布局不合理 |
解决方法 |
|