当前位置:首页 > 技术 > 正文内容

STM32F103 模数转换功能架构与底层驱动设计

访客 技术 2026年7月7日 2

概述:模数转换基础

在嵌入式控制领域,ADC(Analog-to-Digital Converter,模拟-数字转换器)是连接物理世界与数字处理核心的关键桥梁。它负责将输入引脚上的连续模拟电压信号,量化为 MCU 内部存储器可处理的离散数字量。

  • 精度特性:采用 12 位逐次逼近(SAR)架构,单次转换耗时约为 1us。
  • 输入范围:支持 0 至 3.3V 的电压输入,对应的输出编码范围为 0 到 4095。
  • 通道资源:内部集成多达 18 个通道,涵盖 16 个外部管脚及 2 个内部基准信号。
  • 分组机制:设有规则序列组(Regular Group)和注入序列组(Injected Group),适用于不同优先级的数据采集。
  • 监控功能:内置模拟看门狗,可设定电压阈值,用于实时监测温度或光照等环境参数的异常波动。

针对常见的 STM32F103C8T6 核心板,其硬件配置包含两个独立的 ADC 实例(ADC1 和 ADC2),并提供 10 个可用的外部输入通道。

SAR 工作原理

逐次逼近型 ADC 的核心逻辑依赖于一个闭环反馈系统。如图所示:

SAR ADC 原理图

数据转换过程通过多路复用开关选定特定输入通道(IN0~IN7),送入比较器。比较器的一端接收待测电压,另一端则连接内部数模转换器(DAC)。系统通过调整 DAC 的数字输入值,产生相应的参考电压与待测电压进行比对。若 DAC 输出电压高于待测值,则下调 DAC 数据;反之则上调。此迭代过程持续直至两者近似相等,此时 DAC 内部的数字代码即代表最终的转换结果。

硬件架构与信号流

理解 STM32 的 ADC 框图对于配置寄存器至关重要:

STM32 ADC 框图

图中展示了数据流向与状态标志。其中 EOC(End Of Conversion)表示规则组转换完成,JEOC 代表注入组完成。这两个状态位均可在状态寄存器中查询,常配合 DMA 使用以实现对大数据流的无阻塞读取,避免缓冲区覆盖问题。

基本结构解析

ADC 基本结构

通道选择机制

输入通道选择

工作模式详解

根据扫描功能与触发方式的不同组合,ADC 拥有多种运行形态:

1. 单次模式(非扫描)

单次非扫描模式

设定规则序列仅包含一个通道(如 CH2)。触发后执行一次采样,结果存入数据寄存器并置位 EOC,随后停止等待下次触发。

2. 连续模式(非扫描)

连续非扫描模式

与单次模式的区别在于,一旦转换结束,硬件自动立即启动下一次对该通道的转换,形成不间断的数据流。

3. 扫描模式(单次)

单次扫描模式

启用序列表,依次对多个通道(例如 7 个)进行遍历采集。为防止寄存器数据丢失,通常需配合 DMA 传输。所有通道采完后生成 EOC 中断。

4. 扫描模式(连续)

连续扫描模式

在完成一轮多通道扫描后,自动从头开始下一轮扫描,适合需要周期性监测多个信号的场景。

关键参数配置

触发源控制

触发控制设置

转换可由软件直接启动,也可由定时器或其他外设的事件信号触发,具体取决于应用需求。

数据对齐方式

ADC 内部为 12 位精度,但数据寄存器为 16 位,因此存在两种填充策略:

  • 右对齐(推荐):右对齐。有效数据位于低 12 位,高位补零。
  • 左对齐左对齐。有效数据左移,低位补零。这种方式在处理高 8 位快速判断时有用,但会损失部分精度,一般情况下不建议使用。

时序与校准

完整的转换周期包括采样、保持、量化及编码四个阶段。总转换时间计算公式如下:
TCONV = 采样时间 + 12.5 个 ADC 时钟周期
假设 ADC 时钟频率为 14MHz,采样时间设定为 1.5 个周期,则单次转换耗时约 1μs。

此外,为消除内部电容阵列随时间和温度产生的误差,建议在系统上电初始化时强制执行自校准流程。校准前需确保 ADC 处于断电状态至少两个时钟周期。

外围硬件电路

外部模拟信号接入时需注意阻抗匹配与滤波处理,典型连接电路如下图所示:

ADC 硬件电路

驱动程序实现

示例一:单通道配置(优化版)

以下代码重构了初始化流程,强化了注释逻辑,并修正了部分配置顺序以提升稳定性。

#include "Stm32_AdcDriver.h"

// 定义 ADC 实例指针
static ADC_TypeDef* g_adc_instance = ADC1;

/**
 * @brief  初始化 ADC 驱动配置
 * @param  None
 * @retval None
 */
void Sys_ADC_Driver_Initialize(void)
{
    RCC_InitTypeDef rcc_conf;
    GPIO_InitTypeDef gpio_conf;
    ADC_InitTypeDef adc_settings;

    // 1. 开启总线时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 2. 设置 ADC 分频系数 (PCLK2 / 6 <= 14MHz)
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    // 3. 配置输入端口为模拟模式
    gpio_conf.GPIO_Mode = GPIO_Mode_AIN;
    gpio_conf.GPIO_Pin  = GPIO_Pin_0;
    gpio_conf.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_conf);

    // 4. 构建 ADC 主配置
    adc_settings.ADC_Mode = ADC_Mode_Independent;
    adc_settings.ADC_DataAlign = ADC_DataAlign_Right;
    adc_settings.ADC_ContinuousConvMode = ENABLE;  // 启用连续采样
    adc_settings.ADC_ScanConvMode = DISABLE;       // 单通道无需扫描
    adc_settings.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发
    adc_settings.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &adc_settings);

    // 5. 启动 ADC 外设
    ADC_Cmd(g_adc_instance, ENABLE);

    // 6. 执行复位校准 (必须步骤)
    ADC_ResetCalibration(g_adc_instance);
    while(ADC_GetResetCalibrationStatus(g_adc_instance));
    
    ADC_StartCalibration(g_adc_instance);
    while(ADC_GetCalibrationStatus(g_adc_instance));

    // 7. 开启软件触发转换
    ADC_SoftwareStartConvCmd(g_adc_instance, ENABLE);
}

/**
 * @brief  获取当前通道模拟值
 * @param  None
 * @retval unsigned short int
 */
uint16_t Acquire_Analog_Sample(void)
{
    // 由于开启了连续模式,可直接读取最新值
    return ADC_GetConversionValue(g_adc_instance);
}

示例二:多通道动态切换方案

针对不同通道的轮询读取,本方案展示了如何在运行时动态选择通道并进行同步采集。

#include "Stm32_AdcMultiChan.h"

/**
 * @brief  多通道 ADC 初始化框架
 * @param  None
 * @retval None
 */
void Adc_Multi_Channel_Setup(void)
{
    GPIO_InitTypeDef pin_cfg;
    ADC_InitTypeDef reg_config;
    uint8_t channel_pins = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;

    // 时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    // 端口配置
    pin_cfg.GPIO_Mode = GPIO_Mode_AIN;
    pin_cfg.GPIO_Speed = GPIO_Speed_50MHz;
    pin_cfg.GPIO_Pin = channel_pins;
    GPIO_Init(GPIOA, &pin_cfg);

    // ADC 参数设定
    reg_config.ADC_Mode = ADC_Mode_Independent;
    reg_config.ADC_DataAlign = ADC_DataAlign_Right;
    reg_config.ADC_ContinuousConvMode = DISABLE; // 单次触发,便于管理
    reg_config.ADC_ScanConvMode = DISABLE; 
    reg_config.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    reg_config.ADC_NbrOfChannel = 1; 
    ADC_Init(ADC1, ®_config);

    ADC_Cmd(ADC1, ENABLE);
    
    // 校准流程
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
}

/**
 * @brief  指定通道采样
 * @param  ch_idx : 通道索引 (0-17)
 * @retval uint16_t : 转换结果
 */
uint16_t Read_Specific_Channel(uint8_t ch_idx)
{
    // 动态配置规则序列通道
    ADC_RegularChannelConfig(ADC1, ch_idx, 1, ADC_SampleTime_55Cycles5);
    
    // 手动触发转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    
    // 轮询等待转换完成标志
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    
    // 清除标志位并返回数据
    ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
    return ADC_GetConversionValue(ADC1);
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。