news 2026/9/12 22:34:53

STM32 DAC 实战:用 DMA 把定时器表变成波形,自制信号发生器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32 DAC 实战:用 DMA 把定时器表变成波形,自制信号发生器

想用 STM32 出个正弦波、三角波、或者可调频的方波,最常用的笨办法是在主循环里一步步算好值、写进 DAC 数据寄存器。CPU 被这事儿占满不说,频率稍微高点波形就锯齿得没法看。

正确的玩法是让 DAC 自己按节奏出数:定时器当节拍器,每隔固定时间触发一次 DAC 转换,DMA 把一张预先算好的波形表自动搬过去。CPU 只管生成那张表,之后彻底脱手。这篇文章把 DAC + 定时器触发 + DMA 波形发生讲清楚,以及那些让波形失真、频率算错的坑。

DAC 到底在干什么

DAC(数模转换器)把一个数字量变成模拟电压。STM32 多数型号带 1~2 路 DAC,分辨率 12 位,输出 0 到 VREF 之间的电压。最基础用法是HAL_DAC_SetValue写一个值,输出立刻变。

但手动写值的瓶颈在 CPU:你想出 1kHz 正弦波,一个周期至少几十个点,每秒就得写几万次,主循环啥也别干了。解法是用定时器触发DMA

  • 定时器按你设定的频率产生触发事件(比如溢出)
  • 每次触发让 DAC 转换下一个数据
  • DMA 自动从波形表取下一个值送进 DAC 寄存器,取完一圈自动回绕

整个过程 CPU 不参与数据搬运,只偶尔更新一下波形表或频率参数。

波形表和定时器触发

先在内存里放一张正弦波表,比如 256 个点,值是 12 位范围内按正弦算好的:

#defineN256uint16_tsine[N];for(inti=0;i<N;i++){// 12位 DAC,中点 2048,幅度 2047sine[i]=(uint16_t)(2048+2047*sin(2*PI*i/N));}

配置定时器触发 DAC。以 TIM6 作触发源,它的溢出频率决定每个点间隔,进而决定输出波形频率:

波形频率 = 定时器触发频率 / 表长 N = (TIM_CLK / (PSC+1) / (ARR+1)) / N

比如表长 256,想出 1kHz 波形,触发频率就得是 256kHz。反过来用这个公式去算 PSC 和 ARR。

启动:

HAL_TIM_Base_Start(&htim6);// 定时器开始产触发HAL_DAC_Start_DMA(&hdac,DAC_CHANNEL_1,(uint32_t*)sine,N,DAC_ALIGN_12B_R);// DMA 自动送表

DAC_ALIGN_12B_R是右对齐 12 位格式,波形表就按这个对齐准备。DMA 在 Circular 模式下自动回绕,波形就持续不断地出。

输出缓冲和幅度

DAC 内部有输出缓冲放大器,开启后驱动能力强、带负载稳,但会吃掉一点电压余量(到不了轨)。关闭缓冲直接输出,摆幅更满,但源阻抗高,后面不接运放就带不动负载。

想要任意幅度和偏移,单靠 DAC 不够。常见做法是 DAC 出 0~3.3V 的波形,再经过一级运放做缩放和电平平移。比如要 ±5V 输出,DAC 先出 0~3.3V 中点 1.65V,运放做 2 倍增益、减去偏置,得到 ±5V。

十个坑,波形丑基本都在这

  1. 触发源没配对。DAC 的触发源要在 CubeMX 里选成对应定时器(比如 TIM6 TRGO),没选或选错,DAC 不转,输出一直是上次的值。

  2. 波形表对齐格式错。DMA 送的是DAC_ALIGN_12B_R(右对齐)还是12B_L(左对齐),要和表的数据格式一致。左对齐的表用右对齐送进去,波形直接被砍半或移位。

  3. 表长 N 和频率公式搞反。以为改 N 就能调频,其实 N 是分辨率、ARR 才是频率主旋钮。频率 = 触发频率 / N,调频动定时器,调波形平滑度动 N。

  4. DMA 没开 Circular 模式。Normal 模式送完一圈就停,波形只出一次。波形发生器必须 Circular,让它自动回绕。

  5. 定时器触发频率太高超 DAC 建立时间。DAC 转换和建立需要时间,触发太快,前一个值还没稳下一个又来了,波形台阶化、失真。查手册建立时间,别逼太狠。

  6. 输出缓冲没开带不动负载。直接驱动长线或低阻负载,电压被拉垮、波形变形。轻载可以关缓冲换满摆幅,重载必须开缓冲或后级加运放。

  7. 波形表没算对幅度和偏置。算出来的值超 0~4095 被截断,正弦顶部削平;没加直流偏置,纯交流表送进去负半周全丢。表值夹在范围内,交流波要加中点偏置。

  8. 两路 DAC 抢同一个触发源。部分型号两路 DAC 共用一个定时器触发,想两路不同频率做不到,得错开或用其他触发。需要独立波形时确认型号是否支持分触发。

  9. 更新波形表时和 DMA 读冲突。正 Circular 搬运时你改表,可能半新半旧拼成一个怪波形。更新前先HAL_DAC_Stop_DMA或双缓冲切换,别边读边写。

  10. VREF 不稳波形带电源噪声。DAC 参考电压取自 VREF 脚,电源纹波直接叠到输出。参考源加旁路、用独立基准,波形才干净,尤其小信号时明显。

把这件事收一下

DAC 出波形,核心是「定时器定节拍、DMA 搬数据、CPU 只备表」。这三件套搭起来,正弦、三角、任意波形都是同一张表的区别,频率交给定时器算。坑大多在触发源配对、对齐格式、还有缓冲和参考电压这些模拟侧的细节,数字部分反而省心。调好了,一个 STM32 就是台可编程信号源。

DAC 出波靠的是「定时器打拍、DMA 搬表、CPU 备料」。频率动定时器、平滑动表长,对齐格式和参考电压卡死,波形才干净不乱。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 12:57:07

AI安全评估独立性为何关键?谷歌组织调整背后的模型治理启示

谷歌这次调整组织归属&#xff0c;本质上动的是“AI 安全评估独立性”这根神经。公开报道显示&#xff0c;谷歌将原本与 DeepMind 研究体系同侧的 AI 责任团队&#xff0c;划入集团层面的信任与安全部门。组织架构一变&#xff0c;DeepMind 内部立刻有人担心&#xff1a;评估结…

作者头像 李华
网站建设 2026/9/11 4:43:59

Python+CNN+OpenCV+PyQt5:驾驶员疲劳检测与人脸识别系统实战

简介&#xff1a;本资源是一套面向本科毕业设计与人工智能课程实践的完整项目方案&#xff0c;聚焦驾驶员疲劳驾驶识别与人脸识别双重功能&#xff0c;适用于计算机、人工智能、智能交通等方向的学生及初学者。系统基于Python3.6开发&#xff0c;融合PyQt5构建图形界面、OpenCV…

作者头像 李华
网站建设 2026/9/1 19:12:55

AI编码时代:可靠性成为新瓶颈,工程师如何重新定义工作?

先说一个最近在项目里反复出现的情景&#xff1a;我用 AI 生成一段功能代码&#xff0c;耗时不到十秒&#xff0c;但接下来为了确认它是否符合接口约定、异常处理是否足够、输入边界到底该由调用方负责还是由服务端兜底&#xff0c;我和同事花了一个多小时争论。代码本身没有问…

作者头像 李华
网站建设 2026/9/11 13:25:18

网易云音乐Java实习笔试复盘:基础语法、集合与并发考点全解析

网易云音乐的实习生招聘&#xff0c;说到底考的是你有没有真正动手写过Java代码。这套2018年的题目我印象很深&#xff0c;它不搞偏题怪题&#xff0c;也不考什么特别冷门的框架&#xff0c;所有考点都扎在Java基本功上&#xff1a;运算符、集合、排序、JVM、多线程。这套题的筛…

作者头像 李华
网站建设 2026/9/12 11:52:21

Linux PipeWire深度解析之pw_thread_loop_wait调用流程与实战(八十八)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》作者 博主新书推荐&#xff1a;《Android系统多媒体进阶实战》&#x1f680; Android Audio工程师专栏地址&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; Android多媒体专栏地址&a…

作者头像 李华