学习建议:推荐搭配 江协科技 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 header
void 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_None
ADC_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 header
void 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_None
ADC_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);
}
}