
1.
-
ADC:把外部的模拟电压,转换成 MCU 能处理的数字值。
-
DMA:不用 CPU 一次次手动搬数据,而是让硬件自动把数据从一个地方搬到另一个地方。
-
ADC + DMA:是嵌入式里非常经典的一组搭配。常见用法是:
- ADC 负责采样
- DMA 负责自动把采样结果搬到内存数组
- CPU 再去处理这一批数据
2. ADC 是什么
2.1 全称
ADC = Analog to Digital Converter,模数转换器。
2.2 解决什么问题
MCU 内部只能真正处理数字量 ,但现实世界里很多信号是模拟量,比如:
- 电位器电压
- 传感器输出电压
- 电池电压
- 麦克风信号
ADC 的作用就是把这些连续变化的电压,变成一个离散的数字值。
2.3 直观理解
假设 ADC 参考电压是 3.3V,分辨率是 12 位:
- 0V → 0
- 1.65V → 大约 2048
- 3.3V → 4095
也就是说,ADC 就像一个"电压翻译器":
- 输入:模拟电压
- 输出:数字值
2.4 要重点理解的 ADC 基本概念
(1)分辨率
比如 STM32F1 常见是 12 位 ADC。
12 位表示:
- 一共可以表示
2^12 = 4096个等级 - 数字范围通常是
0 ~ 4095
(2)参考电压
ADC 是拿输入电压和参考电压范围做比较。
最常见可先理解成:
- 输入范围:0 ~ 3.3V
- 输出范围:0 ~ 4095
(3)采样时间
ADC 不是"碰一下马上出结果",需要一定采样时间。
采样时间过短,输入信号来不及稳定,结果可能不准。
(4)通道
ADC 可以采多个输入脚,每个输入脚一般对应一个 ADC 通道。
例如:
- PA0 可能对应 ADC1_IN0
- PA1 可能对应 ADC1_IN1
(5)单次转换 / 连续转换
- 单次转换:采一次就停
- 连续转换:一直采样不停
(6)规则通道组 / 扫描模式
如果要采多个通道,比如同时采 PA0、PA1、PA2,就会涉及扫描模式。
3. DMA 是什么
3.1 全称
DMA = Direct Memory Access,直接存储器访问。
3.2 解决什么问题
没有 DMA 时,数据搬运通常这样做:
- 外设准备好一份数据
- CPU 去读出来
- CPU 再写到内存
这样 CPU 会一直忙于"搬箱子"。
DMA 的作用就是:
让硬件帮你搬数据,CPU 可以少参与。
3.3 直观理解
可以把它想成仓库搬运工:
- ADC 负责"生产数据"
- DMA 负责"搬数据到数组里"
- CPU 负责"看结果、做计算"
3.4 DMA 最常见的几个理解点

(1)源地址
数据从哪里来,比如:
- ADC 数据寄存器
- 串口接收寄存器
(2)目的地址
数据搬到哪里去,比如:
- RAM 中的数组
(3)传输长度
一共搬多少个数据。
(4)是否循环模式
- 普通模式:搬完这一次就停
- 循环模式:搬完又从头开始,适合持续采样
(5)为什么它很重要
因为很多外设都在不断产生数据,比如:
- ADC 连续采样
- UART 接收数据
- SPI 收发
如果每次都靠 CPU 读写,CPU 负担会很重。
DMA 可以明显减轻负担。
4. ADC 和 DMA 放在一起怎么理解
4.1 没有 DMA 的 ADC
流程通常是:
- 启动 ADC
- 等待转换完成
- CPU 读 ADC 结果寄存器
- 再启动下一次
这种方式适合:
- 入门学习
- 低频采样
- 只采一个值
4.2 有 DMA 的 ADC
流程通常是:
- 配 ADC
- 配 DMA
- 启动 ADC + DMA
- ADC 每转完一次,DMA 自动把结果搬进数组
- CPU 只在合适时机处理数组里的数据
这种方式适合:
- 连续采样
- 多通道采样
- 批量处理数据
- 降低 CPU 负担
5. 为什么嵌入式开发里要学 ADC 和 DMA
非常常用。
ADC 常见应用
- 采电位器,控制亮度/速度
- 采电池电压
- 采温度传感器
- 采压力/光敏/霍尔等模拟量传感器
- 音频前端采样(入门层面先概念理解)
DMA 常见应用
-
ADC 自动采样搬运
-
UART 接收缓存
-
SPI/I2C 大块数据搬运
-
DAC 波形输出
-
高速采样系统
-

STM32 入门阶段来说,ADC + DMA 是非常值得做成 demo 的学习主题。
6. 应该怎么学
不要一上来就"ADC+DMA+多通道+中断+滤波"全堆一起。
应该分层学。
第一层:先学 ADC 本身
目标:先搞清"采样"到底是怎么回事。
要学会的内容
- 什么是模拟量、数字量
- ADC 分辨率、参考电压、换算公式
- 单通道采样
- 轮询方式读取 ADC 值
- 把 ADC 原始值打印出来观察
- 把 ADC 值换算成电压
最适合第一个 demo
Demo 1:单通道 ADC 采样 + 串口打印数值
比如:
- 用一个电位器接到 ADC 输入脚
- 旋转电位器
- 串口打印 ADC 原始值和电压值
会直接看到:
- 电压变
- ADC 数值跟着变
这个 demo 很适合建立直觉。
第二层:学 ADC 的结果怎么用起来
目标:让 ADC 不只是"打印值",而是驱动功能。
最适合你的第二个 demo
Demo 2:ADC 采样控制 LED 亮度(PWM 占空比)
逻辑:
- ADC 采电位器
- 把 ADC 值映射成 PWM 比较值
- LED 亮度随旋钮变化
这个 demo 能把:
- GPIO
- 定时器 PWM
- ADC
串起来。
第三层:再学 DMA
目标:理解"自动搬运数据"这件事。
要学会的内容
- 为什么需要 DMA
- DMA 的源地址、目的地址、长度
- 正常模式和循环模式
- ADC 为什么常和 DMA 搭配
- DMA 传输完成中断的基本概念
第三个 demo
Demo 3:ADC + DMA,连续采样到数组
逻辑:
- ADC 连续采样
- DMA 自动把结果放到
adc_buf[] - 主循环定期读取
adc_buf[0] - 串口打印这个值
这个 demo 的重点不是花哨,而是确认:
我没有手动每次去读 ADC 数据寄存器,但数组里的值在自动更新。
这就是 DMA 的价值。
第四层:多通道 ADC + DMA
目标:理解"扫描采样"和"数组对应关系"。
适合的第四个 demo
Demo 4:两个 ADC 通道 + DMA 扫描采样
比如:
- 通道1:电位器 A
- 通道2:电位器 B
- DMA 把结果放进
adc_buf[2]
会看到:
adc_buf[0]对应通道1adc_buf[1]对应通道2
这是后面做传感器采集的重要基础。
第五层:数据处理
目标:别只会采,还要会用。
可以继续追加的内容
- 均值滤波
- 滑动平均
- 去抖动 / 去毛刺
- 电压换算
- 阈值判断
- 校准概念
适合的 demo
Demo 5:ADC + DMA + 平均滤波 + PWM 控灯
这就开始更像一个完整小项目了。
7. 先搞懂的几个问题
ADC 方向
- 什么是模拟量,为什么 MCU 不能直接"理解"它?
- 为什么 3.3V 会变成 4095?
- 分辨率越高意味着什么?
1 二分法的精度 - ADC 原始值怎么换算成电压?
- 为什么不同通道对应不同引脚?
DMA 方向
- 为什么说 DMA 能减轻 CPU 负担?
- DMA 到底搬的是什么?
- DMA 是从哪里搬到哪里?
- 什么叫循环模式?
- 为什么 ADC 连续采样时适合 DMA?
8. 推荐的实操路线
第 1 个学习输出
文档:ADC 基础原理学习笔记
内容包括:
- 什么是 ADC
- 12 位分辨率是什么意思
- 0~3.3V 和 0~4095 的关系
- 电压换算公式
第 2 个 demo
单通道 ADC 采样 + 串口打印
第 3 个 demo
ADC 控制 PWM 占空比,调节 LED 亮度
第 4 个学习输出
文档:DMA 基础原理学习笔记
内容包括:
- 什么是 DMA
- 为什么要 DMA
- 普通模式、循环模式
- ADC + DMA 的数据流
第 5 个 demo
ADC + DMA 单通道循环采样
第 6 个 demo
ADC + DMA 多通道采样 + 数据打印
第 7 个 demo
ADC + DMA + 平均滤波 + PWM 控灯
这条路线比较顺,而且每一步都能看到结果。
9. 学习时最容易踩的坑
ADC 常见坑
- GPIO 没配成模拟输入
- ADC 通道和引脚对不上
- 时钟没开
- 采样时间设置不合适
- 直接拿原始值当电压,不做换算
- 对参考电压理解不清
DMA 常见坑
- 源地址和目的地址搞反
- 数据宽度配置不匹配
- 缓冲区长度不对
- 没开循环模式却以为会自动刷新
- 以为 DMA 会"自动处理数据",其实 DMA 只负责搬运,不负责分析
11. 区分 ADC 和 DMA
ADC
负责"采"------把模拟电压变成数字值。
DMA
负责"搬"------把采到的数字值自动搬进内存。
ADC + DMA
一个负责生产数据,一个负责自动搬数据。