资讯详情

STM32F407双ADC多通道+DMA同步采集与串口传输实战

📅 2026/10/14 1:12:29 | 华诺云谱 👁 阅读
STM32F407双ADC多通道+DMA同步采集与串口传输实战
简介本资源面向使用STM32F407芯片进行ADC开发的嵌入式工程师与学生提供一套可直接编译运行的多通道、多ADC同步采集方案。代码基于标准库编写重点解决双ADC多通道同时开启AD转换并通过DMA将数据高效传输至上位机的需求适合需要掌握ADC多通道扫描、DMA搬运及双ADC协同工作模式的开发者参考。压缩包共167个文件约3.93MB包含45个.c与45个.h源文件、20个.d与20个.o编译中间文件以及uvprojx工程文件、hex烧录文件、map映射文件、sct分散加载文件等覆盖从源码到工程配置的完整结构。目前已有1875人学习下载。代码内附详细注释便于修改与二次开发读者可从中理解ADC规则通道与注入通道配置、DMA循环传输、双ADC交替或同步触发等关键实现并借助完整工程快速验证采集效果缩短调试周期。1. 双 ADC 多通道 DMA这份 STM32F407 资源到底能解决什么如果你手头正卡在“ADC 采回来的数据总对不上、通道串了、CPU 被中断拖死”这类问题上这份基于 STM32F407 的双 ADC 多通道 DMA 传输资源大概率能帮你把整条采集链路一次性跑通。它解决的不是“点个灯”级别的入门问题而是把两个 ADC 同时开起来、各自扫多个通道、用 DMA 把结果搬到内存、再整包送到上位机这条完整数据通路。适合已经能点亮 STM32、但一上多通道就翻车的嵌入式从业者也适合做电机电流采样、多路传感器巡检、音频前端这类需要“同步 连续 不占 CPU”场景的人。单 ADC 单通道谁都会双 ADC 多通道 DMA 才是真正见功力的地方。2. 双 ADC 同步采集的原理与 CubeMX 配置落地先把“为什么要双 ADC”这件事说透再动手配。STM32F407 有两个独立的 12 位 ADC支持双重模式Dual Mode常见做法是让 ADC1 做主、ADC2 做从两者在同一触发源下同步启动。这样做的价值在于多路信号可以在同一时刻采样避免分时轮询带来的时间偏斜。如果你只是单 ADC 轮流扫 8 个通道通道之间天然存在采样时间差做功率计算或相位比对时这个偏差就是玄学误差的来源。2.1 双重模式的三种组合与选型理由双重模式不是只有一种玩法规则注入、规则规则、交替触发各有适用面。选错了模式后面 DMA 搬回来的数据顺序会让你怀疑人生。模式触发方式数据组织典型场景规则同步 规则同步同一触发ADC1/ADC2 各出各的结果双路独立信号同步采样交替触发同一触发交替结果交错排列等效采样率翻倍注入同步注入组触发注入寄存器与规则组错开的高优先级采样我一般推荐新手先用“规则同步 规则同步”因为数据在 DMA 缓冲区里的排布最直观ADC1 的通道结果和 ADC2 的通道结果按转换顺序依次落位。交替触发虽然能把等效采样率提上去但数据交错顺序一旦理解错解包时就会把通道 A 的值当成通道 B。2.2 CubeMX 关键参数逐项说明打开 CubeMXADC1 和 ADC2 都要开且必须开扫描模式Scan Conversion Mode否则多通道只转第一个。下面这些参数是翻车高发区Clock PrescalerADC 时钟不能超过 36MHzF407 主频 168MHz 时通常选 PCLK2/4 或 /6别贪快。Resolution12 位够用就别降降位宽换速度是最后手段。Scan Conversion ModeEnabled多通道必须开。Continuous Conversion Mode要连续采集就开单次触发就关。DMA Continuous RequestsEnabled让 DMA 循环搬运。Number Of Conversions填你实际要转的总通道数填错就少搬或多搬。External Trigger双重模式要选同一个触发源比如 TIM2 TRGO别一个软件触发一个定时器触发。ADC2 里要把“Mode”设成“Dual regular simultaneous mode only”或对应组合并且 ADC2 的触发源跟随 ADC1不要单独再配一个。2.3 DMA 配置与数据宽度对齐DMA 这一环最容易出“数据错位”和“只搬一半”的问题。ADC 结果是 12 位但寄存器是 16 位或 32 位对齐DMA 的源宽度、目标宽度、地址自增必须和你的缓冲区类型严格匹配。// DMA2 Stream0 通道0 对应 ADC1配置要点 hdma_adc1.Instance DMA2_Stream0; hdma_adc1.Init.Channel DMA_CHANNEL_0; hdma_adc1.Init.Direction DMA_PERIPH_TO_MEMORY; // 外设到内存 hdma_adc1.Init.PeriphInc DMA_PINC_DISABLE; // 外设地址不自增 hdma_adc1.Init.MemInc DMA_MINC_ENABLE; // 内存地址自增 hdma_adc1.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD; // ADC 数据寄存器 16 位 hdma_adc1.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD; // 缓冲区用 uint16_t hdma_adc1.Init.Mode DMA_CIRCULAR; // 循环模式连续采集 hdma_adc1.Init.Priority DMA_PRIORITY_HIGH;逻辑说明PeriphInc必须关因为 ADC 数据寄存器地址固定MemInc必须开否则所有数据都盖在缓冲区第一个元素上。Mode选循环DMA 搬完一轮自动回到起点配合连续转换就能一直采。参数上最容易错的是数据宽度如果你缓冲区定义成uint32_t但 DMA 配成 HALFWORD读出来的高 16 位就是垃圾。缓冲区类型和MemDataAlignment必须一致。3. 从寄存器到上位机数据打包与串口传输实现采集通了只是第一步把数据完整、可解析地送到上位机才算闭环。这一章讲数据怎么组织、怎么发、上位机怎么对号入座。3.1 缓冲区布局与通道映射双 ADC 同步模式下DMA 缓冲区里的数据顺序由“转换顺序”决定不是由通道号决定。假设 ADC1 扫通道 0、1、2ADC2 扫通道 3、4、5规则同步模式下常见排布是 ADC1 的三个结果在前、ADC2 的三个结果在后交替触发则是交错。你必须先确认自己用的是哪种再写解包代码。#define ADC_CH_NUM 6 uint16_t adc_dma_buf[ADC_CH_NUM]; // DMA 目标缓冲区 // 解包按实际排布映射回物理通道 void unpack_adc(uint16_t *raw, uint16_t *ch_val) { // 规则同步模式前 3 个是 ADC1后 3 个是 ADC2 ch_val[0] raw[0]; // ADC1_IN0 ch_val[1] raw[1]; // ADC1_IN1 ch_val[2] raw[2]; // ADC1_IN2 ch_val[3] raw[3]; // ADC2_IN3 ch_val[4] raw[4]; // ADC2_IN4 ch_val[5] raw[5]; // ADC2_IN5 }逻辑说明raw是 DMA 直接写入的原始顺序ch_val是按物理通道整理后的结果。参数上ADC_CH_NUM必须等于 CubeMX 里两个 ADC 的Number Of Conversions之和少一个就会越界读。如果你发现某个通道值一直是 0 或跳变先打印raw数组看顺序八成是模式选错导致排布和预期不一致。3.2 串口整包发送与帧头设计裸发二进制上位机很难对齐常见做法是加帧头 长度 校验。我一般用简单的“0xAA 0x55 长度 数据 校验和”结构解析端按帧头找起点容错性好。void send_adc_frame(uint16_t *ch_val, uint8_t n) { uint8_t frame[2 1 12 1]; uint8_t idx 0; frame[idx] 0xAA; // 帧头1 frame[idx] 0x55; // 帧头2 frame[idx] n; // 通道数 uint8_t sum n; for (uint8_t i 0; i n; i) { frame[idx] ch_val[i] 8; // 高字节在前 frame[idx] ch_val[i] 0xFF; sum frame[idx - 2] frame[idx - 1]; } frame[idx] sum; // 校验和 HAL_UART_Transmit(huart1, frame, idx, 100); }逻辑说明帧头用于上位机同步长度字段让解析端知道读几个通道校验和防串口误码。参数上n要和实际通道数一致HAL_UART_Transmit的超时别设 0否则发送阻塞时直接返回失败。波特率建议 115200 起步通道多、频率高时升到 460800 或 921600但要在上位机侧同步改。3.3 上位机解析与实时显示上位机用 Python 的 pyserial 就能快速搭一个解析脚本按帧头切分、校验、还原通道值。import serial import struct ser serial.Serial(COM3, 115200, timeout1) CH 6 def read_frame(): while True: if ser.read(1) b\xAA and ser.read(1) b\x55: n ser.read(1)[0] data ser.read(n * 2 1) payload, chk data[:-1], data[-1] if (n sum(payload)) 0xFF chk: vals struct.unpack( H * n, payload) return vals while True: v read_frame() print(v)逻辑说明struct.unpack(H)按大端解析和发送端高字节在前对应。参数上CH要和固件里的通道数一致串口号按实际改。如果一直读不到帧先确认波特率、数据位、停止位是否和固件一致再看帧头字节有没有被上位机当成文本处理。4. 避坑与排查双 ADC DMA 最常见的五个翻车点这一章是我踩过的坑合集每条按“现象 → 原因 → 解决”写照着排查能省下大量试错时间。现象一DMA 缓冲区只有第一个通道有值其余全是 0。原因MemInc没开或者Number Of Conversions填成了 1。 解决确认 DMA 内存地址自增使能CubeMX 里 ADC 的转换数改成实际通道总数。现象二通道数据整体错位通道 1 的值出现在通道 0 位置。原因双重模式选成了交替触发但解包按规则同步写。 解决要么改回规则同步模式要么按交错顺序重写解包映射两者必须一致。现象三采集一段时间后数据卡死不再更新。原因DMA 配成了 Normal 模式搬完一轮就停或者串口发送阻塞导致主循环卡住。 解决DMA 改 Circular 循环模式串口发送用中断或 DMA别在采集回调里死等。现象四ADC 值跳动大、噪声明显。原因采样时间太短或参考电压不稳或模拟地和数字地没处理好。 解决把 Sampling Time 调长如 84 或 144 周期VDDA 加去耦电容模拟部分远离数字走线。现象五上位机偶尔丢帧或校验失败。原因波特率不够导致发送溢出或帧头字节恰好出现在数据里造成误同步。 解决提高波特率帧头用双字节且数据区做转义或改用带长度和 CRC 的协议。提示排查顺序永远是“先看 DMA 缓冲区原始数据再看解包最后看传输”别一上来就怀疑上位机。5. 进阶技巧用定时器触发把采样率钉死前面用的是软件触发或默认触发采样率其实是不确定的受主循环和中断影响。要真正做等间隔采集得让定时器来当触发源把采样节奏从 CPU 手里拿走。以 TIM2 为例配置成 TRGO 更新事件输出ADC1 和 ADC2 的外部触发都选 TIM2 TRGO。这样每个定时器周期产生一次触发双 ADC 同步转换一次DMA 搬一次采样率完全由定时器频率决定。// TIM2 配置72MHz / (PSC1) / (ARR1) 采样率 // 目标 10kHzPSC0, ARR7199 htim2.Instance TIM2; htim2.Init.Prescaler 0; htim2.Init.Period 7199; htim2.Init.CounterMode TIM_COUNTERMODE_UP; HAL_TIM_Base_Init(htim2); TIM_MasterConfigTypeDef sMasterConfig {0}; sMasterConfig.MasterOutputTrigger TIM_TRGO_UPDATE; // 更新事件触发 ADC sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(htim2, sMasterConfig); HAL_TIM_Base_Start(htim2); // 只启动时基不产生中断逻辑说明MasterOutputTrigger选TIM_TRGO_UPDATE每次计数器溢出就发一个触发脉冲给 ADC。参数上采样率 定时器时钟 / ((PSC1) × (ARR1))改 ARR 就能改采样率不用动 ADC 配置。注意HAL_TIM_Base_Start不使能中断避免中断开销干扰采集节奏。验证采样率是否准确有个简单办法让 ADC 采一个已知频率的方波上位机做 FFT 或数过零点看实际采样间隔和理论值差多少。如果偏差大先查定时器时钟源是不是被改过再查 ADC 的采样时间是否超过了触发周期——采样时间加转换时间必须小于触发间隔否则会丢触发。从那以后我每次配双 ADC都强制先单独验证定时器触发频率再开 DMA最后接上位机一步不对就停下来查绝不三样一起上。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑