news 2026/10/18 6:06:06

【STM32C5教程】(9)DAC 模拟量信号输出实验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【STM32C5教程】(9)DAC 模拟量信号输出实验

欢迎关注 youcans@xidian【嵌入式软件AI编程】专栏
【STM32C5教程】(4)GPIO 外部中断实验
【STM32C5教程】(5)定时器周期中断实验
【STM32C5教程】(6)定时器 PWM 输出实验
【STM32C5教程】(7)TIM1 互补 PWM 输出实验
【STM32C5教程】(8)ADC 模拟量数据采集实验
【STM32C5教程】(9)DAC 模拟量信号输出实验


1. 项目简介

1.1 实验目标

本实验在 NUCLEO-C542RC 开发板上,使用 STM32C542RCT6 的 DAC1 通道 1 经 PA4 引脚输出模拟电压:周期性更新 DAC 转换值以生成锯齿波,并通过 PA5 引脚指示锯齿波的输出周期。

功能需求:

  • 使用 DAC1 通道 1 经 PA4 输出模拟电压(0 ~ 3.3 V,对应 12 位数值 0 ~ 4095)
  • 采用无触发(软件触发)方式,由程序周期性更新 DAC 转换值生成锯齿波
  • 通过 PA5 引脚指示锯齿波的输出周期:在锯齿波达到最大值(回绕)时翻转 PA5,输出与锯齿波同步的方波
  • 锯齿波与周期指示均为纯软件实现,无中断、无 DMA 参与

开发板和 MCU 型号:NUCLEO-C542RC 开发板,搭载 STM32C542RCT6 MCU。


1.2 实验条件

硬件:

  • NUCLEO-C542RC 开发板
  • 支持数据传输的 USB Type-C 线(用于连接 ST-LINK 接口)
  • 示波器(用于观测 PA4 与 PA5 的输出波形)

软件:

  • STM32CubeMX2(用于引脚、时钟、ADC 配置与代码生成)
  • VS Code + STM32Cube 插件(用于编译、烧录、调试)

2. 硬件说明

2.1 NUCLEO-C542RC 开发板

NUCLEO-C542RC 是 ST 基于 STM32C542RCT6 推出的 Nucleo-64 开发板。主要特性:

  • MCU:STM32C542RCT6,Arm Cortex-M33 内核,最高主频 144 MHz,256 KB Flash,64 KB RAM
  • 调试器:板载 STLINK-V3EC,支持大容量存储、虚拟串口和调试端口三种功能
  • 用户 LED:LD1,连接 PA5
  • 用户按键:B1,连接 PC13
  • 扩展接口:Arduino Uno V3 和 ST morpho 连接器

本实验使用 PA4 作为 DAC 模拟输出,PA5 作为周期指示信号,通过示波器观测。


2.2 引脚说明

引脚功能说明
PA4DAC1_OUT1DAC1 通道 1,模拟输出
PA5LD1板载用户 LED,GPIO 推挽输出,作为周期指示

PA4(DAC1_OUT1):配置为模拟输出。DAC1 通道 1 固定在 PA4 上,这是芯片引脚复用决定的。

PA5(LD1):配置为 GPIO 推挽输出。作为周期指示信号,与 DAC 输出是两路相互独立的信号。


3. STM32CubeMX2 工程配置

3.1 新建工程

本实验采用 MCU 方式创建工程,即以芯片型号 STM32C542RC 为起点,而非开发板方式。

  1. 进入 MCU 选择界面
    启动 STM32CubeMX2,在首页点击 MCU,进入芯片型号选择列表。

  2. 搜索并选中芯片
    在 MCU name 输入框中输入 STM32C542RC(或完整型号 STM32C542RCT6),从筛选出的列表中选择对应型号。

  1. 填写项目信息
    输入项目名称 DAC_Output 和项目保存路径。项目名称避免使用特殊字符,路径建议使用纯英文目录。

3.2 基础配置

工程创建后,软件自动进入 Pinout 视图。

时钟配置:本工程系统时钟为48 MHz(HSI ÷ 3),DAC 内核时钟为144 MHz(PSIS 时钟),预分频系数为 1。


3.3 GPIO 配置(PA5 输出)

  1. 在 Pinout 视图中找到PA5引脚。
  2. 右键点击 PA5,选择Assign signal→GPIO。
  3. 再次右键点击 PA5,选择Configure GPIO,进入 GPIO 详细配置界面。
  4. 将 PA5 的Mode设置为Output。
  5. 保持默认参数:Output level 为 Low,Output mode 为 Push Pull,Pull-up/Pull-down 为 No pull-up and no pull-down,Maximum output speed 为 Low。
  6. 在User Label输入框中填入LD1。

设置别名后,CubeMX2 会自动生成宏定义LD1_PORT和LD1_PIN。


3.4 DAC1 配置

(1)启用 DAC1

在左侧外设列表中找到Analog→DAC1,点击展开。将Channel 1设置为Connected to external pin only(仅连接到外部引脚)。

设置完成后,Pinout 视图中PA4自动分配为DAC1_OUT1(模拟模式)。

(2)配置 DAC 参数

在 DAC1 的Parameter Settings中设置:

参数值说明
Output BufferEnable输出缓冲开启,带负载能力更强
TriggerNone无触发(软件触发)
Data Alignment12 bits right12 位右对齐
Output ConnectionExternal输出连接到外部引脚
High Frequency ModeAuto高频模式自动选择

(3)确认引脚配置

回到 Pinout 视图,PA4 应显示为DAC1_OUT1(模拟模式)。


3.5 项目配置

  1. 点击Project Settings,进入工程设置页面。
  2. 在IDE Format下拉选项中选择CMake。
  3. 在CMake Toolchain下拉选项中选择GCC。
  4. 确认配置无误后,点击Generate Code。CubeMX2 会执行配置检查,如果没有错误,开始在指定路径下生成 CMake 工程文件。
  5. 生成完成后,项目路径下会出现标准 CMake 工程结构,包含Core/、Drivers/、CMakeLists.txt等。


4. 编程实现

4.1 实现思路

采用“DAC 无触发启动 + 主循环更新转换值 + PA5 同步翻转”的方案:

mx_system_init() // CubeMX2 生成:时钟、GPIO(PA4/PA5)、DAC1 初始化 │ ▼ mx_dac1_gethandle() // 获取 DAC1 句柄 │ ▼ HAL_DAC_SetChannelData() // 先写数据到 DHR(无触发模式要求) │ ▼ HAL_DAC_StartChannel() // 再使能通道,开始转换 │ ▼ 主循环:周期性地写入递增的转换值,形成锯齿波 │ ├─ dac_value += DAC_STEP_VALUE │ └─ dac_value >= DAC_MAX_VALUE? ├─ 是 → 回绕到最小值,翻转 PA5 └─ 否 → 继续 │ ▼ HAL_Delay(2) // 步进延时,决定锯齿波周期

无触发的启动时序:HAL_DAC_TRIGGER_NONE模式下,应先HAL_DAC_SetChannelData()写入初始值到 DHR,再HAL_DAC_StartChannel()使能通道。顺序不可颠倒。

写入立即生效:无触发模式下,HAL_DAC_SetChannelData()写入 DHR 后输出电压立即更新,无需等待任何触发事件。这正是能在主循环中“写一次、更新一次”生成锯齿波的原理。

各步骤使用的 HAL 函数:

步骤HAL 函数作用
获取 DAC1 句柄mx_dac1_gethandle()返回 CubeMX 生成的 DAC1 句柄
写入转换值HAL_DAC_SetChannelData()写入 DHR,无触发时立即生效
启动通道HAL_DAC_StartChannel()使能 DAC 通道 1
翻转 PA5HAL_GPIO_TogglePin(LD1_PORT, LD1_PIN)切换 PA5 输出电平

4.2 关键代码

在 VS Code 中打开生成的 CMake 工程,找到Core/Src/main.c,添加以下代码。

(1)文件头部添加宏定义与变量

/* Private define ------------------------------------------------------------*//* DAC1 channel 1 (12-bit, right-aligned) output value range */#defineDAC_MIN_VALUE0U#defineDAC_MAX_VALUE4095U#defineDAC_STEP_VALUE128U/* step per update -> sawtooth resolution *//* Private variables ---------------------------------------------------------*/statichal_dac_handle_t*hDAC1_handle=NULL;

(2)主函数

intmain(void){if(mx_system_init()!=SYSTEM_OK){return(-1);}/* Get the DAC1 handle initialized by mx_dac1_init() */hDAC1_handle=mx_dac1_gethandle();if(hDAC1_handle==NULL){return(-1);}/* Software (no hardware) trigger: set the initial value into DHR first, then enable the channel to start conversion. */if(HAL_DAC_SetChannelData(hDAC1_handle,HAL_DAC_CHANNEL_1,DAC_MIN_VALUE)!=HAL_OK){return(-1);}if(HAL_DAC_StartChannel(hDAC1_handle,HAL_DAC_CHANNEL_1)!=HAL_OK){return(-1);}/* Sawtooth generation: periodically update the DAC conversion value. PA5 (LD1) toggles at each period boundary to indicate the output period. */uint32_tdac_value=DAC_MIN_VALUE;while(1){/* Update the DAC data holding register -> immediate output update */(void)HAL_DAC_SetChannelData(hDAC1_handle,HAL_DAC_CHANNEL_1,dac_value);/* Next step of the rising ramp */dac_value+=DAC_STEP_VALUE;if(dac_value>=DAC_MAX_VALUE){/* End of the sawtooth period: wrap to the minimum value */dac_value=DAC_MIN_VALUE;/* Toggle PA5 to mark one full output period */HAL_GPIO_TogglePin(LD1_PORT,LD1_PIN);}/* Delay between two updates defines the sawtooth step period */HAL_Delay(2U);}}

代码说明:

  • mx_dac1_gethandle() 返回 CubeMX2 生成的 DAC1 句柄,返回 NULL 时需处理。
  • HAL_DAC_SetChannelData() 写入 DAC 数据保持寄存器(DHR),无触发模式下写入后立即生效。
  • HAL_DAC_StartChannel() 使能 DAC 通道 1,必须在 HAL_DAC_SetChannelData() 之后调用。
  • 主循环中写入 dac_value 后立即递增,形成锯齿波的上升沿。
  • 当 dac_value 超过 DAC_MAX_VALUE 时,回绕到 DAC_MIN_VALUE,形成锯齿波的回绕跳变。
  • 每次回绕时翻转 PA5(LD1),输出与锯齿波周期同步的方波。

5. 编译烧录与运行测试

5.1 编译与烧录

  1. 打开工程:用 VS Code 打开 CubeMX2 生成的 CMake 工程文件夹(如 DAC_Output_cmake)。
  2. 编译:点击 VS Code 底部状态栏的Build按钮,或使用命令面板执行 CMake 构建。编译完成后,终端应输出退出代码为 0,无报错提示。
  3. 连接开发板:用支持数据传输的 USB Type-C 线连接 NUCLEO-C542RC 的 ST-LINK USB 口(CN1)。
  4. 确认设备识别:打开设备管理器,在“端口 (COM 和 LPT)”下应能看到STLink COMx。
  5. 烧录:点击 VS Code 中的运行按钮,将固件下载到开发板。


5.2 运行与测试

烧录完成后,点击 VS Code 中的 Run 按钮,程序开始运行。使用双通道示波器观测 PA4 和 PA5 的波形。

测试方法:用示波器验证波形与同步关系

  1. 双通道示波器:CH1 接 PA4,CH2 接 PA5(共地,3.3 V 量程)。
  2. 观察 CH1:应观察到阶梯式上升后跳变回落的锯齿波。
  3. 观察 CH2:应观察到方波。
  4. 验证同步:以 PA5 的上升/下降沿为触发,观察 PA4 —— 每次 PA5 翻转的时刻,恰好对应 PA4 锯齿波达到最大值后回落的时刻。

测试结果:

☑ 编译通过,无错误
☑ 烧录成功
☑ PA4 输出锯齿波
☑ PA5 输出方波,占空比 50%
☑ PA5 在 PA4 达到最大值时翻转,与锯齿波周期边界完全同步

功能正常。


6. 小结

本实验通过 DAC1 通道 1 经 PA4 输出模拟电压,实现了周期性更新转换值生成锯齿波,并通过 PA5 输出与锯齿波同步的方波,掌握了 STM32C5 系列 DAC 的配置与使用方法。

核心逻辑可以概括为:“DAC 无触发启动 → 主循环更新转换值 → 生成锯齿波 → PA5 同步翻转”。


版权声明:

欢迎关注 youcans@xidian【嵌入式软件AI编程】专栏
转发必须注明原文链接:
【STM32C5教程】(9)DAC 模拟量信号输出实验
Copyright by ai4mcu@qq.com 2026
Crated:2026-10

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

page_alloc free_reserved_area

free_reserved_area() 是内核启动后期用于将保留内存(reserved memory)释放回伙伴系统的核心函数。它通常服务于 free_initmem()、free_initrd_mem() 等场景,把初始化代码段、initrd 等不再需要的物理内存归还给分配器。核心作用与设计意图它…

作者头像 李华
网站建设 2026/10/18 6:03:20

Matlab自动驾驶决策规划控制实战:从状态机到纯跟踪完整代码解析

自动驾驶决策规划控制Matlab代码实战,听起来又长又劝退,但我实际跑通之后发现,这其实是进入自动驾驶领域性价比最高的一条路。最近不少朋友来问我怎么入门,我的建议是别一上来就啃C、Linux那一套,先用Matlab把决策、规…

作者头像 李华
网站建设 2026/10/18 6:02:49

Playwright Trace Viewer:自动化测试的完整证据链

前两天帮一位校招阶段的朋友复盘自动化测试项目,代码写得挺干净,断言也覆盖了核心路径,但面试的时候被问住了一句话:跑挂了之后,你怎么证明不是环境问题?他想了想说,有截图。截图当然有&#xf…

作者头像 李华
网站建设 2026/10/18 6:02:17

大O表示法面试全攻略:从复杂度分析到数据结构性能优化

1. 为什么面试官总爱问大O表示法我在做技术面试官的时候,几乎每场技术面都会问候选人关于算法复杂度的问题。倒不是故意刁难,而是这一题能非常高效地把候选人的基础功底测出来。你想想,一个写了两三年业务代码的人,天天增删改查&a…

作者头像 李华
网站建设 2026/10/18 6:02:07

基于YOLOv5的钢轨缺陷检测:VOC转YOLO与训练避坑全流程

简介:基于YOLOv5的钢轨缺陷检测项目,面向铁路设施维护人员及计算机视觉学习者,目标是通过深度学习实现对钢轨裂纹、磨损、剥离等表面缺陷的自动定位与分类,提升巡检效率与安全性。该资源压缩包共2000个文件,其中1994个…

作者头像 李华
网站建设 2026/10/18 6:01:31

AI文档预处理:为什么Markdown化是提升大模型准确率的关键一步

1. 为什么“直接丢文件给AI”正在悄悄拖垮你的效率你有没有过这种经历:把一份20页的PDF产品说明书拖进对话框,等了半分钟,AI只回了一句“已收到”,再问具体问题,它却开始胡说八道?或者把Excel表格截图扔过去…

作者头像 李华