在单周期扫描模式下,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); } }
测试结果:
感觉误差还有稍微有点大,不知道是不是和我的测试环境有关。
程序源码: