在单周期扫描模式下,A/D 转换通道依软件配置执行一遍,具体流程如下:
1、软件设置寄存器 ADC_ANY_CFG,ADC_CHANY0,ADC_CHANY1,将需要转换的通道、数量设置好,然后置位 CHANY_MDEN。
2、通过软件、外部触发置位 ADCR 寄存器的 ADST,外部触发可软件配置触发延时,A/D 转换方向从CHANY_SEL0 到 CHANY_SEL8 转换通道数量由 CHANY_NUM 配置, 且 CHANY_SEL0 到CHANY_SEL8 是任意配置的,可以完全相同,或完全不相同。
3、每路 A/D 转换完成时,A/D 转换的数据值将有序装载到相应通道的数据寄存器中,ADIF 转换结束标志被设置,若此时控制寄存器 ADCR 的 ADIE 位置 1,将产生 AD 转换结束中断请求。
4、A/D 转换结束后,ADST 位自动清 0,A/D 转换器进入空闲模式。
若在 A/D 转换过程中,软件更新 ADC_ANY_CFG, ADC_CHANY0, ADC_CHANY1,硬件不会立即更新这些配置,只会在当前设置的通道都转换结束时更新,然后等待下一次软件软件置位 ADST。
按照以上说明,我们使用库函数模式,编程测试这种模式下的ADC处理。使用PA3作为ADC的输入,设置ADC中断。每次转换完成后,通过OLED显示,并输出给串口2。根据功能服用,需要设置PA3用于ADC输入通道。
引脚说明:
为此在设置ADC时,需要设置ADC1的通道2,并使PA3作为输入口:
主要代码如下:
// 初始化ADC设备,此处只使用PA3作为输入通道
void ADC_Configure(void) {
ADC_InitTypeDef ADC_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
// 允许时钟
RCC_APB1PeriphClockCmd(RCC_APB1ENR_ADC1, ENABLE);
ADC_StructInit(&ADC_InitStruct);
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; // 设置分辨率
ADC_InitStruct.ADC_PRESCARE = ADC_PCLK1_PRESCARE_16; // 时钟分频
ADC_InitStruct.ADC_Mode = ADC_Mode_Scan; // 模式:单次周期
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐
ADC_Init(ADC1, &ADC_InitStruct);
ADC_SampleTimeConfig(ADC1, ADC_Samctl_240_5);
ADC_ClearFlag(ADC1, ADC_FLAG_EOC); // 清除比较标志
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE); // 允许转换中断
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
/* 配置输入通道:PA3(通道2) */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置ADC中断
NVIC_InitStruct.NVIC_IRQChannel = ADC1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 0x01;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// 使能ADEN位,即使能ADC转换
ADC_Cmd(ADC1, ENABLE);
}
// 获取ADC通道数据。ADC完成后会产生中断
float ADC_GetChannelVoltage(ADCCHANNEL_TypeDef Channel) {
uint16_t Value = 0;
float Voltage;
ADC_ANY_NUM_Config(ADC1, 0);
ADC_ANY_CH_Config(ADC1, 0, Channel);
ADC_ANY_Cmd(ADC1, ENABLE);
// 清除中断标志
ADC_InterruptFlag = 0;
// 启动转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 等待ADC转换完成后产生的中断标志
while (0 == ADC_InterruptFlag) {
}
// 取得转换结果
Value = ADC_GetConversionValue(ADC1);
adc_result = Value;
// 禁止中断
ADC_ANY_Cmd(ADC1, DISABLE);
// 转换为电压值
Voltage = (float)Value / (float)4096 * (float)3.3;
return (Voltage);
}中断处理:
void ADC1_IRQHandler(void) {
if (RESET != ADC_GetITStatus(ADC1, ADC_IT_EOC)) {
// 设置中断标志
ADC_InterruptFlag = 1;
// 清除状态标志:转换完成的中断标志
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}
}测试结果:


感觉误差还有稍微有点大,不知道是不是和我的测试环境有关。
程序源码:
我要赚赏金
