STM32 AD单通道与多通道实战指南

发布于:2025-06-04 ⋅ 阅读:(40) ⋅ 点赞:(0)


学习建议:推荐搭配 江协科技 AD单通道 AD多通道一起食用!!!!
【STM32入门教程-2023版 细致讲解 中文字幕】https://www.bilibili.com/video/BV1th411z7sn?p=22&vd_source=66c03c3ecc640bbe982dc3d48bfd8841

AD单通道(实验)

在这里插入图片描述
在这里插入图片描述

  1. 初始化流程
    开启时钟 → 配置 GPIO 为模拟输入 → 配置规则组通道 → 初始化 ADC 结构体 → 开启 ADC 电源 → 校准 ADC。
  2. 单次转换流程
    软件触发转换 → 等待 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);
   }
}


网站公告

今日签到

点亮在社区的每一天
去签到