学习建议:推荐搭配 江协科技 AD单通道 AD多通道一起食用!!!!
【STM32入门教程-2023版 细致讲解 中文字幕】https://www.bilibili.com/video/BV1th411z7sn?p=22&vd_source=66c03c3ecc640bbe982dc3d48bfd8841
AD单通道(实验)
- 初始化流程:
开启时钟 → 配置 GPIO 为模拟输入 → 配置规则组通道 → 初始化 ADC 结构体 → 开启 ADC 电源 → 校准 ADC。 - 单次转换流程:
软件触发转换 → 等待EOC
标志位 → 读取转换结果。
有关配置的库函数
1. RCC_ADCCLKConfig
- 功能:配置 ADC 的时钟分频器,确定 ADC 工作时钟(ADCCLK)。
- 参数:可选分频系数为 2、4、6、8,输入时钟为 APB2 的 72MHz 时钟。
- 示例:若选择 6 分频,ADCCLK = 72MHz / 6 = 12MHz。
- 作用:确保 ADC 工作在合适的时钟频率下,保证转换精度和稳定性。
- 在RCC库函数中,配置ADC工作时钟。
2.电源与校准函数
ADC_Cmd
- 功能:开启或关闭 ADC 电源。
- 参数:
ENABLE
启动 ADC,DISABLE
关闭。
- 校准函数组(需按顺序调用):
ADC_ResetCalibration
:复位校准寄存器。ADC_GetResetCalibrationStatus
:等待复位校准完成(通过循环检测标志位)。ADC_StartCalibration
:启动校准。ADC_GetCalibrationStatus
:等待校准完成(通过循环检测标志位)。- 作用:减小 ADC 转换误差,需在初始化后调用。
3.中断与 DMA 相关函数
ITConfig
:开启或关闭 ADC 中断(如模拟看门狗中断)。NVIC_Init
:配置中断优先级(需结合ITConfig
使用)。DMA_Cmd
:开启 DMA 传输(用于多通道数据搬运,会议中未深入讲解)。
4.触发与转换控制函数
ADC_SoftwareStartConvCmd
- 功能:软件触发 ADC 开始转换(适用于单次转换模式)。
- 参数:
ENABLE
触发转换,DISABLE
关闭。
- ADC_GetSoftwareStartConvStatus
- 不能获取软件触发转换状态,因为当有软件触发标志时,一旦开始转化就会将软件触发标志位清零,不会通过该函数获得是否转化完成。
ADC_GetFlagStatus
- 功能:获取转换状态标志位。
- 关键参数
ADC_FLAG_EOC
:规则组转换完成标志位(转换结束后硬件置 1)。
- 用途:通过检测
EOC
标志位判断转换是否完成,而非使用ADC_GetSoftwareStartConvStatus
(该函数仅返回触发状态,与转换完成无关)。
5.配置间断模式函数
- ADC_DiscModeChannelCountConfig
- 每隔几个通道间断一次
- ADC_DiscModeCmd
- 是否开启间断模式
6.规则组通道配置
- ADC_RegularChannelConfig
- 功能:配置规则组通道参数,如通道号、序列位置、采样时间。
- 参数
ADCx
:ADC 外设(如ADC1
)。ADC_Channel
:通道编号(如 PA0 对应ADC_Channel_0
)。Rank
:序列位置(1~16,非扫描模式下仅需设为 1)。ADC_SampleTime
:采样时间(影响转换速度和稳定性,可选短 / 中 / 长周期)。
7.其他
-
ADC_ExternalTrigConvCmd
- 外部触发转换控制 ,就是是否允许外部触发转换
-
ADC_GetConversionValue
- 功能:读取规则组通道的转换结果(16 位无符号整数)。
- 返回值:转换后的数字量,需结合参考电压计算实际模拟值。
-
ADC_GetDualModeConversionValue
- ADC获取双模式转换值,双ADC模式读取转化结果的函数
-
ADC_TempSensorVrefintCmd
- ADC温度传感器,内部参考电压控制,用来开启内部的两个通道。
8.注入组与模拟看门狗函数
-
注入组函数:带
Injected
前缀的函数(如ADC_InjectedChannelConfig
),用于配置紧急通道(会议中未使用)。 -
模拟看门狗函数
ADC_AnalogWatchdogCmd
:启动模拟看门狗,监测输入电压是否超出阈值。ADC_AnalogWatchdogThresholdsConfig
:设置电压阈值(高 / 低阈值)。
-
ADC_AnalogWatchdogSingleChannelConfig
- 配置看门的通道
AD单通道部分主要代码
// AD.c
#include "stm32f10x.h" // Device headervoid AD_Init(void)
{//1.开始时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//2. 配置ADC时钟信号//只能使用6 或者 8 分频,因为有限制RCC_ADCCLKConfig(RCC_PCLK2_Div6);//3.配置gpio口 //初始化gpioinit参数中的结构体GPIO_InitTypeDef GPIO_InitStructure;//将gpio口设置为模拟输入模式,就是io口不起作用不会影响数据转化GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//4.配置规则组通道ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//5.初始化ADC模块ADC_InitTypeDef ADC_InitStruct;//是否连续转化ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//对齐方式ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//外部触发方式,使用软件触发,所以配置为ADC_ExternalTrigConv_NoneADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;ADC_InitStruct.ADC_NbrOfChannel = 1;//配置连续扫描ADC_InitStruct.ADC_ScanConvMode = DISABLE;ADC_Init(ADC1, &ADC_InitStruct);//6. 开启ADC总开关ADC_Cmd(ADC1, ENABLE);//7.校准ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1) == SET);}
//启动转换,获取结果函数
uint16_t AD_GetValve(void)
{//内部软件启动转换ADC_SoftwareStartConvCmd(ADC1, ENABLE);//查看是否转化完成//查看标志位,转化完成会将EOC标志位置一while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//读取数据return ADC_GetConversionValue(ADC1);
}
AD多通道实现
多通道采集实现思路探讨
- 扫描模式结合 DMA :利用列表填充四个通道触发转换可实现多通道,但存在数据覆盖问题,最好配合 DMA 实现,讲完 DMA 后再尝试。
- 手动转运数据问题 :扫描模式下单个通道转换完成无标志位和中断,只有整个列表转换完才有 EOC 标志位和中断,易造成数据覆盖丢失;且 AD 转换快,手动转运数据对程序要求高,操作困难。
- 间断模式手动转运 :可使用间断模式,每转换一个通道暂停,手动转运数据后再继续,但因无标志位需靠 delay 延时保证转换完成,不省心且效率低,暂不推荐。
单次转换非扫描模式实现AD多通道
- 具体实现方式 :每次触发转换前手动更改列表第一个位置的通道,如依次写入通道 0、1、2、3 等,触发转换等待读值,就能实现多通道转换。
AD多通道部分代码
//AD.c
#include "stm32f10x.h" // Device headervoid AD_Init(void)
{//1.开始时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//2. 配置ADC时钟信号//只能使用6 或者 8 分频,因为有限制RCC_ADCCLKConfig(RCC_PCLK2_Div6);//3.配置gpio口 //初始化gpioinit参数中的结构体GPIO_InitTypeDef GPIO_InitStructure;//将gpio口设置为模拟输入模式,就是io口不起作用不会影响数据转化GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//5.初始化ADC模块ADC_InitTypeDef ADC_InitStruct;//是否连续转化ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//对齐方式ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//外部触发方式,使用软件触发,所以配置为ADC_ExternalTrigConv_NoneADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;ADC_InitStruct.ADC_NbrOfChannel = 1;//配置连续扫描ADC_InitStruct.ADC_ScanConvMode = DISABLE;ADC_Init(ADC1, &ADC_InitStruct);//6. 开启ADC总开关ADC_Cmd(ADC1, ENABLE);//7.校准ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1) == SET);}
//使用单次转化,非扫描模式实现AD多通道
//启动转换,获取结果函数
uint16_t AD_GetValve(uint8_t ADC_Channel)
{//配置规则组通道ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);//内部软件启动转换ADC_SoftwareStartConvCmd(ADC1, ENABLE);//查看是否转化完成//查看标志位,转化完成会将EOC标志位置一while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//读取数据return ADC_GetConversionValue(ADC1);
}
//main.c#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t value0;
uint16_t value1;
uint16_t value2;
uint16_t value3;int main(void)
{OLED_Init();AD_Init();OLED_ShowString(1, 1, "V0:");OLED_ShowString(2, 1, "V1:");OLED_ShowString(3, 1, "V2:");OLED_ShowString(4, 1, "V3:");while(1){value0 = AD_GetValve(ADC_Channel_0);value1 = AD_GetValve(ADC_Channel_1);value2 = AD_GetValve(ADC_Channel_2);value3 = AD_GetValve(ADC_Channel_3);OLED_ShowNum(1, 4, value0, 4);OLED_ShowNum(2, 4, value1, 4);OLED_ShowNum(3, 4, value2, 4);OLED_ShowNum(4, 4, value3, 4);Delay_ms(100);}
}