news 2026/4/22 3:55:13

STM32F103 DAC双通道输出不同幅度三角波:一个定时器触发两个波形的实战配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F103 DAC双通道输出不同幅度三角波:一个定时器触发两个波形的实战配置

STM32F103 DAC双通道独立控制实战:用定时器触发实现高精度三角波输出

在工业控制、测试测量和音频处理等领域,经常需要同时生成多路独立可控的模拟信号。STM32F103系列MCU内置的双通道DAC配合定时器触发功能,为这类需求提供了经济高效的解决方案。本文将深入探讨如何利用单个定时器同步触发两个DAC通道,实现相位同步但幅度可调的三角波输出,这种技术在电机驱动测试、传感器激励信号生成等场景中尤为实用。

1. 硬件架构与工作原理

STM32F103的DAC模块包含两个独立的12位数字模拟转换器,每个转换器对应一个输出通道(PA4对应DAC1,PA5对应DAC2)。其核心特性包括:

  • 双通道独立控制:每个通道可单独配置幅度、波形和触发方式
  • 内置波形发生器:支持噪声波和三角波生成,减轻CPU负担
  • 灵活触发源:支持定时器、外部引脚和软件触发
  • 同步更新功能:确保多通道输出时序一致性

三角波生成原理如下图所示:

DAC工作流程: 定时器触发 → 三角波计数器增减 → 与DHRx值相加 → 输出到DORx → 模拟输出

关键寄存器配置要点:

寄存器关键位域配置说明
DAC_CRWAVEx[1:0]10=三角波模式
MAMPx[3:0]设置三角波峰值幅度
TENx必须置1使能触发
DAC_DHR12RDDACC1DHR/DACC2DHR双通道12位右对齐数据保持寄存器

注意:MAMPx必须在DAC使能前配置,否则无法修改。三角波实际输出值为(DHRx + 三角波计数器值) mod (MAMPx+1)

2. 工程环境搭建与基础配置

2.1 硬件连接准备

典型的最小系统连接方式:

  • PA4(DAC1_OUT) → 示波器通道1
  • PA5(DAC2_OUT) → 示波器通道2
  • 确保VREF+引脚接入稳定参考电压(通常3.3V)

2.2 软件初始化流程

以下是完整的初始化代码框架:

#include "stm32f10x.h" void DAC_TriWave_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; DAC_InitTypeDef DAC_InitStruct; TIM_TimeBaseInitTypeDef TIM_InitStruct; // 1. 时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 2. GPIO配置(模拟输入模式) GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStruct); // 3. 定时器基础配置(TIM2作为触发源) TIM_InitStruct.TIM_Period = 71; // 决定波形频率 TIM_InitStruct.TIM_Prescaler = 0; TIM_InitStruct.TIM_ClockDivision = 0; TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_InitStruct); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // 4. DAC通道配置 DAC_InitStruct.DAC_Trigger = DAC_Trigger_T2_TRGO; DAC_InitStruct.DAC_WaveGeneration = DAC_WaveGeneration_Triangle; DAC_InitStruct.DAC_OutputBuffer = DAC_OutputBuffer_Disable; // 通道1配置(全幅度) DAC_InitStruct.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_4095; DAC_Init(DAC_Channel_1, &DAC_InitStruct); // 通道2配置(半幅度) DAC_InitStruct.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_2047; DAC_Init(DAC_Channel_2, &DAC_InitStruct); // 5. 使能模块 DAC_Cmd(DAC_Channel_1, ENABLE); DAC_Cmd(DAC_Channel_2, ENABLE); TIM_Cmd(TIM2, ENABLE); }

关键参数计算公式:

  • 输出频率 = TIM2时钟 / (TIM_Period * (TIM_Prescaler+1))
  • 幅度分辨率 = VREF+ / 4095(12位模式)

3. 高级配置技巧与实战优化

3.1 双通道相位同步控制

要实现严格的相位同步,必须注意:

  1. 使用DAC_DualSoftwareTriggerCmd()同时触发双通道
  2. 或者通过TIM_SelectOutputTrigger()确保两个通道使用相同的硬件触发源
  3. 在初始化最后一步才使能定时器,避免配置过程中的误触发

3.2 动态幅度调整方案

通过修改MAMPx值实时改变波形幅度:

void Set_DAC_Amplitude(DAC_Channel_TypeDef channel, uint32_t amplitude) { DAC_InitTypeDef DAC_InitStruct; // 必须先禁用DAC才能修改MAMP DAC_Cmd(channel, DISABLE); // 重新初始化配置 DAC_InitStruct.DAC_Trigger = DAC_Trigger_T2_TRGO; DAC_InitStruct.DAC_WaveGeneration = DAC_WaveGeneration_Triangle; DAC_InitStruct.DAC_OutputBuffer = DAC_OutputBuffer_Disable; DAC_InitStruct.DAC_LFSRUnmask_TriangleAmplitude = amplitude; DAC_Init(channel, &DAC_InitStruct); DAC_Cmd(channel, ENABLE); }

可用幅度常量(对应MAMP[3:0]):

DAC_TriangleAmplitude_1 // 2^1-1 DAC_TriangleAmplitude_3 // 2^2-1 ... DAC_TriangleAmplitude_4095 // 2^12-1 (全幅度)

3.3 输出频率精确控制

通过TIM2参数调整输出频率时需考虑:

  • APB1时钟通常为36MHz(系统时钟72MHz二分频)
  • 实际波形周期 = (TIM_Period+1) * (TIM_Prescaler+1) / APB1_clock
  • 最小间隔需大于3个APB1周期(DAC硬件限制)

示例频率配置表:

目标频率TIM_PrescalerTIM_Period实际频率
100kHz0359100kHz
10kHz0359910kHz
1kHz359991kHz

4. 常见问题排查与性能优化

4.1 典型问题诊断

  1. 无输出信号

    • 检查GPIO是否配置为模拟输入模式
    • 确认TIM2和DAC时钟已使能
    • 测量VREF+电压是否正常
  2. 波形失真

    • 确保TIM_Period值≥3(满足DAC硬件要求)
    • 尝试启用输出缓冲(DAC_OutputBuffer_Enable)
    • 检查电源稳定性,必要时增加滤波电容
  3. 通道间相位差

    • 使用DAC_DualSoftwareTriggerCmd()强制同步
    • 检查是否意外修改了DAC_CR的TENx位

4.2 性能优化建议

  • 降低CPU干预:配置DMA自动更新DHR寄存器
  • 提高精度:校准VREF+电压,使用12位右对齐模式
  • 多通道扩展:通过外部运放组合多个DAC输出
  • 低功耗设计:在波形稳定后关闭TIM2时钟

实际项目中,我在电机测试平台上使用这种配置时发现,当需要生成高频信号(>50kHz)时,建议:

  1. 将TIM_Prescaler设为0以获得最高定时器分辨率
  2. 适当降低MAMP值可以提高三角波斜率
  3. 禁用所有未使用的外设时钟以减少噪声干扰
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 3:54:46

Agent决策系统设计:如何确保AI做出可靠选择

Agent决策系统设计:如何确保AI做出可靠选择 核心概念 在当今人工智能快速发展的时代,Agent决策系统已经成为AI领域的研究热点和应用核心。从自动驾驶汽车的实时路况判断,到智能客服的对话策略选择,再到金融风控系统的风险评估,Agent决策系统无处不在。 Agent决策系统是…

作者头像 李华
网站建设 2026/4/22 3:36:46

新手易懂!如何修改excel表格创建的时间,6种实测方法

一、Excel创建时间的小知识在办公场景中,Excel文件的创建时间是很重要的记录信息,比如提交财务报表、项目资料归档时,系统或领导可能会检查这个时间是否符合规范。不过有时候我们会遇到创建时间提前、拖延导致不符合要求的情况,这…

作者头像 李华
网站建设 2026/4/22 3:36:38

兔抗MLL1抗体亲和纯化,批次间稳定,低背景,高信噪比

一、产品概述由艾美捷Bethyl Laboratories推出的MLL1抗体(货号A300-374A)是一款针对人MLL1(混合谱系白血病蛋白1,亦称KMT2A)的兔源多克隆抗体,由美国制造,采用抗原亲和纯化工艺制备。该抗体以未…

作者头像 李华
网站建设 2026/4/22 3:33:34

为什么 ArrayList 的 elementData 加上 transient修饰?

文章目录1. 核心矛盾:空间浪费2. 为什么加 transient?3. 如何“理解”图片中的 writeObject 代码?4. 这样做的好处(总结)5. 额外的一点:那行 modCount ! expectedModCount这是一个关于 “性能优化” 和 “精…

作者头像 李华