文章目录一、DAC 简介1、什么是 DAC2、DAC 工作原理3、STM32F103 DAC 核心参数4、DAC 核心特点5、DAC 典型应用场景二、DAC 模块详解1、DAC功能框图2、标号① 模拟电源基准区绿色引脚功能作用硬件注意3、标号② 数模转换输出单元橙色模块数字至转换器 x DAC_OUTx 引脚特性4、标号③ 数字控制逻辑区蓝色核心功能寄存器与模块拆解触发控制 TENxDMAENxDMA 使能内置波形发生器LFSRx /trianglex:DORxDAC 输出寄存器DAC 控制寄存器数据流流程5、标号④ 触发源选择区黄色 TSELx 多路选择器全部可选触发源TSELx [2:0] 寄存器位选择工作逻辑6、三种典型工作模式模式 1固定直流输出无 DMA、无硬件波形模式 2DMA 自动波形输出自定义正弦 / 方波表模式 3硬件内置三角 / 噪声波无需 DMA、无需波形表三、DAC编程模块1、DAC 结构体1.DAC_HandleTypeDefDAC 顶层句柄外设总控制器2.DAC_InitTypeDefDAC 通道初始化配置触发、波形、输出缓冲3.DAC_ChannelConfTypeDef通道独立配置多通道时分配置4.DAC_DMAHandleTypeDef配套 DMA 句柄DMA 波形输出专用2、HAL_DAC_API1.初始化/去初始化2.IO操作函数3.外围控制函数4.外设状态和错误功能5.专用回调函数中断 / DMA 完成事件用户重写四、DAC 应用实例1、静态可调电压输出1.CubeMX配置2.电压转换函数3.完整参考代码2、DACDMA 正弦波发生器1.CubeMX配置2.正弦波形表生成12 位中点 2048幅值 20470~40953.完整代码4.可选DMA中断回调动态修改波形 / 状态监测五、DAC 核心要点与避坑大全1、必考核心知识点2、高频坑点3、工程优化技巧4、工程万能搭配方案5、一句话总结六、全篇总结一、DAC 简介1、什么是 DACDACDigital-to-Analog Converter数模转换器是 ADC 的反向外设核心作用是将单片机内部离散的数字量转换成连续变化的模拟电压信号。单片机本身只能输出数字高低电平0V/3.3V依靠 DAC 可以输出任意中间电压、模拟波形实现信号生成、音量调节、模拟控制等功能。2、DAC 工作原理数字量寄存器赋值 → DAC 内核权重电阻网络转换 → 模拟电压输出 → 引脚输出连续电压信号。STM32 DAC 采用电阻权重网络数模转换原理12位精度分级输出电压数值越大输出电压越高。3、STM32F103 DAC 核心参数分辨率12位 DAC数字范围 0 ~ 4095。输出电压范围0V ~ VDDA默认0~3.3V。电压计算公式输出电压 DAC设定值 × 3.3 / 4095。通道数量2路独立DAC通道。输出速度高速转换支持波形快速刷新。对应引脚DAC1_OUT PA4、DAC2_OUT PA5。4、DAC 核心特点支持双通道独立输出可输出两路不同模拟电压。支持 DMA 自动刷新无需CPU干预生成连续波形。支持定时器触发采样精准生成正弦波、三角波、方波。支持噪声波形、三角波内置生成模式。输出电压线性度高模拟信号稳定。5、DAC 典型应用场景模拟电压输出、可调基准电压。信号发生器正弦波、三角波、方波输出。音响音量调节、音频信号播放。电机模拟调压控制、传感器模拟校准。配合ADC实现闭环模拟信号调试。二、DAC 模块详解1、DAC功能框图2、标号① 模拟电源基准区绿色引脚功能VDDA模拟电源 3.3V为 DAC 转换电路供电。VSSA模拟地。VREF参考电压输入决定 DAC 输出量程 0 ~ VREF。作用提供纯净模拟电压标尺DAC 输出电压计算公式硬件注意电源引脚就近并联 0.1μF 陶瓷滤波电容数字地与模拟地单点共地降低输出噪声。3、标号② 数模转换输出单元橙色模块数字至转换器 x DAC_OUTx 引脚输入 12 位数字信号内部电阻网络转换成连续模拟电压。片内集成输出缓冲运放可软件开关提升带载驱动能力。对外引脚DAC_OUT1 (PA4) / DAC_OUT2 (PA5)。特性输出单极性电压无法输出负压。输出阶梯波形可外接 RC 低通滤波平滑。4、标号③ 数字控制逻辑区蓝色核心功能寄存器与模块拆解DHRx数据保持寄存器CPU/DMA 写入 12 位目标数值暂存待转换支持 12 位左 / 右对齐。触发控制 TENx触发使能位打开触发更新通路。DMAENxDMA 使能开启后每次触发自动发起 DMA 请求DMA 自动刷新 DHRx实现波形全自动输出。内置波形发生器LFSRx /trianglex:WAVENx波形使能开关。MAMPx三角波幅值 / 噪声随机数掩码配置。LFSR伪随机噪声发生器trianglex硬件三角波生成无需 CPU 计算波形表。DORxDAC 输出寄存器触发到来时将 DHRx 数值锁存送入 DAC 转换单元避免转换中途数值突变。DAC 控制寄存器统一配置通道使能、缓冲、对齐、波形模式等全局参数。数据流流程DHRx → 触发锁存 → DORx → 12 位 DAC 转换单元 → DAC_OUTx.5、标号④ 触发源选择区黄色 TSELx 多路选择器全部可选触发源TSELx [2:0] 寄存器位选择SWTRIGx 软件触发寄存器置位手动更新输出。定时器 TRGO 事件TIM2/TIM4/TIM5/TIM6/TIM7/TIM8 更新事件精准定时刷新 DAC波形发生器首选。EXTI_9 外部引脚触发外部电平边沿触发更新输出。工作逻辑多路选择器仅选中一路触发信号送入控制逻辑每收到一次触发执行一次DHRx→DORx 更新 DMA 请求DMA 开启时。6、三种典型工作模式模式 1固定直流输出无 DMA、无硬件波形CPU 直接写 DHRx。软件触发 SWTRIGx 更新 DORx。DAC 转换输出恒定电压。通路CPU → DHRx → SWTRIG → DORx → DAC_OUTx。模式 2DMA 自动波形输出自定义正弦 / 方波表DMA 循环搬运波形表数据到 DHRx。TIMx_TRGO 定时触发更新。持续循环输出波形。通路内存波形表 → DMA → DHRx → TIM 触发 → DORx → DAC_OUTx。模式 3硬件内置三角 / 噪声波无需 DMA、无需波形表配置 WAVENx 开启硬件波形、MAMPx 设置幅值。TIM 定时触发硬件自动递增 / 随机生成数值覆盖 DHRx。通路硬件 LFSR/triangle 模块 → DHRx → TIM 触发 → DORx → DAC_OUTx。三、DAC编程模块1、DAC 结构体1.DAC_HandleTypeDefDAC 顶层句柄外设总控制器全局唯一外设句柄绑定寄存器、通道配置、DMA、状态锁。 typedef struct { DAC_TypeDef *Instance; // DAC寄存器基地址DAC DAC_InitTypeDef Init; // 通道全局初始化参数 DMA_HandleTypeDef *DMA_Handle1; // 通道1 DMA句柄DMAEN1 DMA_HandleTypeDef *DMA_Handle2; // 通道2 DMA句柄DMAEN2 HAL_LockTypeDef Lock; // 互斥锁多任务防冲突 __IO uint32_t State; // DAC运行状态机 __IO uint32_t ErrorCode; // 错误标志DMA溢出、硬件故障 } DAC_HandleTypeDef;2.DAC_InitTypeDefDAC 通道初始化配置触发、波形、输出缓冲控制触发源、硬件波形发生器、输出缓冲CubeMX 直接映射该结构体。 typedef struct { uint32_t DAC_Trigger; // TSELx触发源选择 uint32_t DAC_WaveGeneration; // WAVENx波形使能 uint32_t DAC_LFSRUnmask_TriangleAmplitude; // MAMPx幅值/噪声掩码 uint32_t DAC_OutputBuffer; // 输出缓冲运放开关 } DAC_InitTypeDef;3.DAC_ChannelConfTypeDef通道独立配置多通道时分配置STM32F1 有 DAC1_CH1 (PA4)、DAC1_CH2 (PA5) 双通道每个通道独立配置。 typedef struct { uint32_t DAC_Channel; // 选择通道1/2 uint32_t DAC_DataAlignment; // DHRx寄存器12位对齐方式 } DAC_ChannelConfTypeDef;4.DAC_DMAHandleTypeDef配套 DMA 句柄DMA 波形输出专用DMA 波形输出必备循环搬运波形表到 DHRx 寄存器。 typedef struct { DMA_TypeDef *Instance; DMA_InitTypeDef Init; HAL_LockTypeDef Lock; __IO uint32_t State; __IO uint32_t ErrorCode; } DMA_HandleTypeDef; // DMA_InitTypeDef 关键DAC配置 typedef struct { uint32_t Direction; // DMA_MEMORY_TO_PERIPH 内存→DAC外设 uint32_t PeriphInc; // DMA_PINC_DISABLE DHRx地址固定不变 uint32_t MemInc; // DMA_MINC_ENABLE 波形表内存自增 uint32_t PeriphDataAlignment; // DMA_PDATAALIGN_HALFWORD 16位 uint32_t MemDataAlignment; // DMA_MDATAALIGN_HALFWORD uint32_t Mode; // DMA_CIRCULAR 循环模式持续输出波形 uint32_t Priority; } DMA_InitTypeDef;2、HAL_DAC_API1.初始化/去初始化HAL_DAC_Init() 原型 HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef *hdac); 作用 上层外设初始化读取 hdac.Init 结构体配置写入 DAC 控制寄存器触发源、波形发生器、输出缓冲。 调用位置 CubeMX 自动生成在 MX_DAC_Init() 中先执行 HAL_DAC_MspInit 再执行本函数。 依赖 必须提前填充 DAC_InitTypeDef 全局配置。 HAL_DAC_DeInit() 原型 HAL_StatusTypeDef HAL_DAC_DeInit(DAC_HandleTypeDef *hdac); 作用 复位 DAC 所有控制寄存器关闭外设调用底层 HAL_DAC_MspDeInit 释放时钟与引脚资源。 使用场景 低功耗休眠前、动态切换功能时释放 DAC。2.IO操作函数HAL_DAC_Start() 原型 HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel); 功能 使能指定 DAC 通道模拟输出通路硬件上电就绪支持直流 / 硬件三角波 / 噪声波。 示例 HAL_DAC_Start(hdac, DAC_CHANNEL_1); HAL_DAC_SetValue(hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048); HAL_DAC_Trigger_Software(hdac, DAC_CHANNEL_1); HAL_DAC_Stop() 原型 HAL_StatusTypeDef HAL_DAC_Stop(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel); 功能 关闭通道输出断开数模转换通路输出变为高阻。 HAL_DAC_Start_DMA() 原型 HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel, uint32_t *pData, uint32_t Length, uint32_t Alignment); 核心 DMA 波形输出 API使能 DMAENx 通路循环搬运内存波形表到 DHRx。 参数 pData波形数组首地址。 Length采样点数量。 Alignment12 位左 / 右对齐。 HAL_DAC_Stop_DMA() 原型 HAL_StatusTypeDef HAL_DAC_Stop_DMA(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel); 功能 关闭 DMA 传输同时停止 DAC 通道输出。 HAL_DAC_SetValue() 原型 HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel, uint32_t Alignment, uint16_t Data); 功能 写入 12 位数字值到 DHRx 保持寄存器设定目标输出电压数值范围 0~4095。 电压换算 Vout Data * VDDA / 4096。 HAL_DAC_GetValue() 原型 uint16_t HAL_DAC_GetValue(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel); 功能 读取 DORx 锁存寄存器获取当前正在转换输出的 12 位数值。3.外围控制函数HAL_DAC_ConfigChannel() 原型 HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t DAC_Channel); 功能 单通道独立配置 API填充通道对齐方式、选择通道 1/2。 HAL_DAC_SetValue() 重复说明同时属于 IO 操作与外设控制负责写入输出数值是修改 DAC 输出的核心接口。4.外设状态和错误功能HAL_DAC_GetState() 原型 HAL_StateTypeDef HAL_DAC_GetState(DAC_HandleTypeDef *hdac); 返回 DAC 全局状态 HAL_DAC_STATE_RESET未初始化。 HAL_DAC_STATE_READY空闲就绪。 HAL_DAC_STATE_BUSYDMA / 转换运行中。 HAL_DAC_STATE_ERROR硬件故障。 HAL_DAC_GetError() 原型 uint32_t HAL_DAC_GetError(DAC_HandleTypeDef *hdac); 读取错误标志 HAL_DAC_ERROR_DMA、HAL_DAC_ERROR_TIMEOUT定位故障类型。5.专用回调函数中断 / DMA 完成事件用户重写HAL_DAC_ConvCpltCallbackCh1() 原型 void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac); DMA 整段波形传输完成、单次触发更新完成后进入用于一轮波形结束处理。 HAL_DAC_ConvHalfCpltCallbackCh1() 原型 void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac); DMA 缓冲区一半数据传输完成用于双缓冲实时刷新波形表无输出断层。 HAL_DAC_ErrorCallbackCh1() 原型 void HAL_DAC_ErrorCallbackCh1(DAC_HandleTypeDef *hdac); DMA 传输错误、外设硬件故障时触发用于故障告警处理。四、DAC 应用实例1、静态可调电压输出实现DAC固定输出、阶梯调压输出0~3.3V连续电压。1.CubeMX配置配置项参数值说明TriggerSoftware trigger软件触发手动更新输出电压Wave generation modeDisabled关闭硬件三角 / 噪声波纯自定义直流输出Output BufferEnable开启输出缓冲带载能力更强2.电压转换函数void Set_DAC_Voltage(float voltage) { // 确保输入电压在有效范围内 if (voltage 0) voltage 0; if (voltage 3.3) voltage 3.3; // 将目标电压转换为12位数字量 uint16_t dac_value (uint16_t)(voltage / 4095 * 3.3); // 设置DAC输出值12位右对齐 HAL_DAC_SetValue(hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_value); }3.完整参考代码#include main.h #include dac.h int main(void) { HAL_Init(); SystemClock_Config(); MX_DAC_Init(); // 使能DAC通道1输出 HAL_DAC_Start(hdac, DAC_CHANNEL_1); // 模式1固定静态电压输出示例1.65V Set_DAC_Voltage(1.65f); while(1) { // 保持恒定输出无需操作 } // 模式2阶梯连续调压 0~3.3V循环 float vol_step 0.1f; // 阶梯步长0.1V float current_vol 0.0f; while(1) { DAC_Set_Voltage(current_vol); current_vol vol_step; // 到达3.3V重置归零 if(current_vol V_REF) { current_vol 0.0f; } HAL_Delay(500); // 每500ms升一档 } }2、DACDMA 正弦波发生器预先存储正弦波数据表DMA自动刷新输出连续正弦波形。1.CubeMX配置1外设与引脚开启DAC开启DAC1自动占用 PA4DAC1_OUT1引脚模式为Analog。TIM 触发源选择TIM6基础定时器无 IO 占用推荐用于 DAC 触发。DMA添加 DAC1 Channel1 DMA 请求DMA1_Channel3。RCC系统时钟 72MHz开启 APB1、APB2、DMA1 时钟。2DAC Parameter Settings核心配置参数项设置值说明DAC TriggerTIM6 Triggr OuteventTIM6 更新事件定时触发 DAC 刷新电压Wave generation modeDisabled关闭硬件三角波使用 DMA 自定义正弦表Output BufferEnable开启输出缓冲提升带载能力3DMA Settings 配置DAC1_CH1ModeCircular 循环模式波形循环不间断。DirectionMemory To Peripheral 内存波形表→DAC 外设。PeriphIncDisableDHR 寄存器地址固定。MemIncEnable波形数组自动递增读取。Periph Data WidthHalf Word。Memory Data WidthHalf Word。PriorityMedium。4TIM6 定时触发配置控制正弦波频率Prescaler71Counter Period999。定时器时钟 APB172MHz分频后计数时钟 72M/(711)1MHz。更新事件 TRGO 周期 (9991)/1MHz 1msDAC 每 1ms 刷新一次波形点。Trigger OutputUpdate Event更新事件作为 TRGO 触发 DAC。关闭 TIM6 输出通道仅内部触发使用。5NVIC 设置可选开启 DMA2 Channel3 中断用于波形半满 / 全满回调无动态波形修改可关闭中断。2.正弦波形表生成12 位中点 2048幅值 20470~4095代码 #define WAVE_POINT_NUM 64 // 一个周期64个采样点 // 正弦表偏移2048范围0~4095对应0~3.3V const uint16_t sin_wave_table[WAVE_POINT_NUM] { 2048,2248,2444,2630,2796,2937,3048,3127,3170,3174,3140,3068, 2964,2834,2683,2518,2344,2169,1997,1834,1684,1551,1438,1347, 1283,1247,1240,1263,1315,1393,1494,1616,1754,1905,2048,2190, 2339,2477,2598,2698,2774,2823,2844,2836,2799,2736,2648,2539, 2414,2277,2132,1984,1840,1703,1577,1468,1378,1312,1270,1249, 1249,1271,1314,1376,1456,1551 }; 频率计算公式 单周期刷新总时间 WAVE_POINT_NUM × TIM6_TRGO周期。 本例64 × 1ms 64ms / 周期 → 正弦波频率 ≈ 15.625Hz。 修改 TIM 预分频 / 重载值可调整输出频率。3.完整代码#include main.h #include dac.h #include dma.h #include tim.h extern DAC_HandleTypeDef hdac; extern TIM_HandleTypeDef htim6; #define WAVE_POINT_NUM 64 const uint16_t sin_wave_table[WAVE_POINT_NUM] { 2048,2248,2444,2630,2796,2937,3048,3127,3170,3174,3140,3068, 2964,2834,2683,2518,2344,2169,1997,1834,1684,1551,1438,1347, 1283,1247,1240,1263,1315,1393,1494,1616,1754,1905,2048,2190, 2339,2477,2598,2698,2774,2823,2844,2836,2799,2736,2648,2539, 2414,2277,2132,1984,1840,1703,1577,1468,1378,1312,1270,1249, 1249,1271,1314,1376,1456,1551 }; int main(void) { HAL_Init(); SystemClock_Config(); MX_DMA_Init(); MX_DAC_Init(); MX_TIM6_Init(); // 1. 启动DAC DMA循环传输绑定正弦表 HAL_DAC_Start_DMA(hdac, DAC_CHANNEL_1, (uint32_t*)sin_wave_table, WAVE_POINT_NUM, DAC_ALIGN_12B_R); // 2. 启动TIM6输出TRGO定时触发DAC刷新波形 HAL_TIM_Base_Start(htim6); while (1) { // 硬件全自动输出正弦波CPU无占用无需处理 } }4.可选DMA中断回调动态修改波形 / 状态监测开启 DMA 中断后重写回调函数实现双缓冲更新波形 // DMA缓冲区一半传输完成 void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) { if(hdac-Instance DAC) { // 前32点传输完成可修改前半段波形数据 } } // 完整一轮波形传输完成 void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) { if(hdac-Instance DAC) { // 64点全部输出完毕可修改后半段波形数据 } } // DMA传输错误处理 void HAL_DAC_ErrorCallbackCh1(DAC_HandleTypeDef *hdac) { Error_Handler(); }五、DAC 核心要点与避坑大全1、必考核心知识点DAC是ADC反向外设12位精度输出范围0~3.3V。核心公式输出电压 DAC值 × 3.3 / 4095。F103 DAC双通道PA4、PA5模拟输出。静态电压用软件赋值动态波形用 TIMDMA 组合。DAC无驱动能力仅输出信号需运放放大驱动负载。2、高频坑点直接用DAC驱动喇叭、电机等负载导致输出失真、烧坏引脚。未开启HAL_DAC_Start赋值后无电压输出。波形输出未配定时器波形频率紊乱、抖动严重。DMA缓冲区使用局部变量导致波形错乱死机。忽略VDDA电源波动导致输出电压精度偏差。3、工程优化技巧DAC输出后端增加 RC 滤波电路平滑波形、减少毛刺。大功率负载搭配运算放大器、功率放大电路。高频波形采用多点数据表提升波形平滑度。固定基准电压输出可配合ADC做硬件校准。4、工程万能搭配方案静态调压单纯HAL_DAC_SetValue软件赋值。动态波形TIM触发 DMA循环 波形数据表。高精度基准DAC输出RC滤波运放跟随。5、一句话总结DAC是STM32数模转换外设可将04095数字量转为03.3V模拟电压支持静态电压输出和TIMDMA动态波形生成是模拟信号输出、波形发生器、电压基准校准的核心外设。六、全篇总结DAC 是嵌入式模拟信号输出的唯一核心外设与ADC成对互补。掌握DAC静态调压、DMA动态波形输出、定时器触发配置即可完成信号发生器、模拟调压、音频输出、闭环校准等高级项目功能是进阶嵌入式开发的必备技能。
HAL_DAC
发布时间:2026/6/26 3:51:20
文章目录一、DAC 简介1、什么是 DAC2、DAC 工作原理3、STM32F103 DAC 核心参数4、DAC 核心特点5、DAC 典型应用场景二、DAC 模块详解1、DAC功能框图2、标号① 模拟电源基准区绿色引脚功能作用硬件注意3、标号② 数模转换输出单元橙色模块数字至转换器 x DAC_OUTx 引脚特性4、标号③ 数字控制逻辑区蓝色核心功能寄存器与模块拆解触发控制 TENxDMAENxDMA 使能内置波形发生器LFSRx /trianglex:DORxDAC 输出寄存器DAC 控制寄存器数据流流程5、标号④ 触发源选择区黄色 TSELx 多路选择器全部可选触发源TSELx [2:0] 寄存器位选择工作逻辑6、三种典型工作模式模式 1固定直流输出无 DMA、无硬件波形模式 2DMA 自动波形输出自定义正弦 / 方波表模式 3硬件内置三角 / 噪声波无需 DMA、无需波形表三、DAC编程模块1、DAC 结构体1.DAC_HandleTypeDefDAC 顶层句柄外设总控制器2.DAC_InitTypeDefDAC 通道初始化配置触发、波形、输出缓冲3.DAC_ChannelConfTypeDef通道独立配置多通道时分配置4.DAC_DMAHandleTypeDef配套 DMA 句柄DMA 波形输出专用2、HAL_DAC_API1.初始化/去初始化2.IO操作函数3.外围控制函数4.外设状态和错误功能5.专用回调函数中断 / DMA 完成事件用户重写四、DAC 应用实例1、静态可调电压输出1.CubeMX配置2.电压转换函数3.完整参考代码2、DACDMA 正弦波发生器1.CubeMX配置2.正弦波形表生成12 位中点 2048幅值 20470~40953.完整代码4.可选DMA中断回调动态修改波形 / 状态监测五、DAC 核心要点与避坑大全1、必考核心知识点2、高频坑点3、工程优化技巧4、工程万能搭配方案5、一句话总结六、全篇总结一、DAC 简介1、什么是 DACDACDigital-to-Analog Converter数模转换器是 ADC 的反向外设核心作用是将单片机内部离散的数字量转换成连续变化的模拟电压信号。单片机本身只能输出数字高低电平0V/3.3V依靠 DAC 可以输出任意中间电压、模拟波形实现信号生成、音量调节、模拟控制等功能。2、DAC 工作原理数字量寄存器赋值 → DAC 内核权重电阻网络转换 → 模拟电压输出 → 引脚输出连续电压信号。STM32 DAC 采用电阻权重网络数模转换原理12位精度分级输出电压数值越大输出电压越高。3、STM32F103 DAC 核心参数分辨率12位 DAC数字范围 0 ~ 4095。输出电压范围0V ~ VDDA默认0~3.3V。电压计算公式输出电压 DAC设定值 × 3.3 / 4095。通道数量2路独立DAC通道。输出速度高速转换支持波形快速刷新。对应引脚DAC1_OUT PA4、DAC2_OUT PA5。4、DAC 核心特点支持双通道独立输出可输出两路不同模拟电压。支持 DMA 自动刷新无需CPU干预生成连续波形。支持定时器触发采样精准生成正弦波、三角波、方波。支持噪声波形、三角波内置生成模式。输出电压线性度高模拟信号稳定。5、DAC 典型应用场景模拟电压输出、可调基准电压。信号发生器正弦波、三角波、方波输出。音响音量调节、音频信号播放。电机模拟调压控制、传感器模拟校准。配合ADC实现闭环模拟信号调试。二、DAC 模块详解1、DAC功能框图2、标号① 模拟电源基准区绿色引脚功能VDDA模拟电源 3.3V为 DAC 转换电路供电。VSSA模拟地。VREF参考电压输入决定 DAC 输出量程 0 ~ VREF。作用提供纯净模拟电压标尺DAC 输出电压计算公式硬件注意电源引脚就近并联 0.1μF 陶瓷滤波电容数字地与模拟地单点共地降低输出噪声。3、标号② 数模转换输出单元橙色模块数字至转换器 x DAC_OUTx 引脚输入 12 位数字信号内部电阻网络转换成连续模拟电压。片内集成输出缓冲运放可软件开关提升带载驱动能力。对外引脚DAC_OUT1 (PA4) / DAC_OUT2 (PA5)。特性输出单极性电压无法输出负压。输出阶梯波形可外接 RC 低通滤波平滑。4、标号③ 数字控制逻辑区蓝色核心功能寄存器与模块拆解DHRx数据保持寄存器CPU/DMA 写入 12 位目标数值暂存待转换支持 12 位左 / 右对齐。触发控制 TENx触发使能位打开触发更新通路。DMAENxDMA 使能开启后每次触发自动发起 DMA 请求DMA 自动刷新 DHRx实现波形全自动输出。内置波形发生器LFSRx /trianglex:WAVENx波形使能开关。MAMPx三角波幅值 / 噪声随机数掩码配置。LFSR伪随机噪声发生器trianglex硬件三角波生成无需 CPU 计算波形表。DORxDAC 输出寄存器触发到来时将 DHRx 数值锁存送入 DAC 转换单元避免转换中途数值突变。DAC 控制寄存器统一配置通道使能、缓冲、对齐、波形模式等全局参数。数据流流程DHRx → 触发锁存 → DORx → 12 位 DAC 转换单元 → DAC_OUTx.5、标号④ 触发源选择区黄色 TSELx 多路选择器全部可选触发源TSELx [2:0] 寄存器位选择SWTRIGx 软件触发寄存器置位手动更新输出。定时器 TRGO 事件TIM2/TIM4/TIM5/TIM6/TIM7/TIM8 更新事件精准定时刷新 DAC波形发生器首选。EXTI_9 外部引脚触发外部电平边沿触发更新输出。工作逻辑多路选择器仅选中一路触发信号送入控制逻辑每收到一次触发执行一次DHRx→DORx 更新 DMA 请求DMA 开启时。6、三种典型工作模式模式 1固定直流输出无 DMA、无硬件波形CPU 直接写 DHRx。软件触发 SWTRIGx 更新 DORx。DAC 转换输出恒定电压。通路CPU → DHRx → SWTRIG → DORx → DAC_OUTx。模式 2DMA 自动波形输出自定义正弦 / 方波表DMA 循环搬运波形表数据到 DHRx。TIMx_TRGO 定时触发更新。持续循环输出波形。通路内存波形表 → DMA → DHRx → TIM 触发 → DORx → DAC_OUTx。模式 3硬件内置三角 / 噪声波无需 DMA、无需波形表配置 WAVENx 开启硬件波形、MAMPx 设置幅值。TIM 定时触发硬件自动递增 / 随机生成数值覆盖 DHRx。通路硬件 LFSR/triangle 模块 → DHRx → TIM 触发 → DORx → DAC_OUTx。三、DAC编程模块1、DAC 结构体1.DAC_HandleTypeDefDAC 顶层句柄外设总控制器全局唯一外设句柄绑定寄存器、通道配置、DMA、状态锁。 typedef struct { DAC_TypeDef *Instance; // DAC寄存器基地址DAC DAC_InitTypeDef Init; // 通道全局初始化参数 DMA_HandleTypeDef *DMA_Handle1; // 通道1 DMA句柄DMAEN1 DMA_HandleTypeDef *DMA_Handle2; // 通道2 DMA句柄DMAEN2 HAL_LockTypeDef Lock; // 互斥锁多任务防冲突 __IO uint32_t State; // DAC运行状态机 __IO uint32_t ErrorCode; // 错误标志DMA溢出、硬件故障 } DAC_HandleTypeDef;2.DAC_InitTypeDefDAC 通道初始化配置触发、波形、输出缓冲控制触发源、硬件波形发生器、输出缓冲CubeMX 直接映射该结构体。 typedef struct { uint32_t DAC_Trigger; // TSELx触发源选择 uint32_t DAC_WaveGeneration; // WAVENx波形使能 uint32_t DAC_LFSRUnmask_TriangleAmplitude; // MAMPx幅值/噪声掩码 uint32_t DAC_OutputBuffer; // 输出缓冲运放开关 } DAC_InitTypeDef;3.DAC_ChannelConfTypeDef通道独立配置多通道时分配置STM32F1 有 DAC1_CH1 (PA4)、DAC1_CH2 (PA5) 双通道每个通道独立配置。 typedef struct { uint32_t DAC_Channel; // 选择通道1/2 uint32_t DAC_DataAlignment; // DHRx寄存器12位对齐方式 } DAC_ChannelConfTypeDef;4.DAC_DMAHandleTypeDef配套 DMA 句柄DMA 波形输出专用DMA 波形输出必备循环搬运波形表到 DHRx 寄存器。 typedef struct { DMA_TypeDef *Instance; DMA_InitTypeDef Init; HAL_LockTypeDef Lock; __IO uint32_t State; __IO uint32_t ErrorCode; } DMA_HandleTypeDef; // DMA_InitTypeDef 关键DAC配置 typedef struct { uint32_t Direction; // DMA_MEMORY_TO_PERIPH 内存→DAC外设 uint32_t PeriphInc; // DMA_PINC_DISABLE DHRx地址固定不变 uint32_t MemInc; // DMA_MINC_ENABLE 波形表内存自增 uint32_t PeriphDataAlignment; // DMA_PDATAALIGN_HALFWORD 16位 uint32_t MemDataAlignment; // DMA_MDATAALIGN_HALFWORD uint32_t Mode; // DMA_CIRCULAR 循环模式持续输出波形 uint32_t Priority; } DMA_InitTypeDef;2、HAL_DAC_API1.初始化/去初始化HAL_DAC_Init() 原型 HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef *hdac); 作用 上层外设初始化读取 hdac.Init 结构体配置写入 DAC 控制寄存器触发源、波形发生器、输出缓冲。 调用位置 CubeMX 自动生成在 MX_DAC_Init() 中先执行 HAL_DAC_MspInit 再执行本函数。 依赖 必须提前填充 DAC_InitTypeDef 全局配置。 HAL_DAC_DeInit() 原型 HAL_StatusTypeDef HAL_DAC_DeInit(DAC_HandleTypeDef *hdac); 作用 复位 DAC 所有控制寄存器关闭外设调用底层 HAL_DAC_MspDeInit 释放时钟与引脚资源。 使用场景 低功耗休眠前、动态切换功能时释放 DAC。2.IO操作函数HAL_DAC_Start() 原型 HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel); 功能 使能指定 DAC 通道模拟输出通路硬件上电就绪支持直流 / 硬件三角波 / 噪声波。 示例 HAL_DAC_Start(hdac, DAC_CHANNEL_1); HAL_DAC_SetValue(hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048); HAL_DAC_Trigger_Software(hdac, DAC_CHANNEL_1); HAL_DAC_Stop() 原型 HAL_StatusTypeDef HAL_DAC_Stop(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel); 功能 关闭通道输出断开数模转换通路输出变为高阻。 HAL_DAC_Start_DMA() 原型 HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel, uint32_t *pData, uint32_t Length, uint32_t Alignment); 核心 DMA 波形输出 API使能 DMAENx 通路循环搬运内存波形表到 DHRx。 参数 pData波形数组首地址。 Length采样点数量。 Alignment12 位左 / 右对齐。 HAL_DAC_Stop_DMA() 原型 HAL_StatusTypeDef HAL_DAC_Stop_DMA(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel); 功能 关闭 DMA 传输同时停止 DAC 通道输出。 HAL_DAC_SetValue() 原型 HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel, uint32_t Alignment, uint16_t Data); 功能 写入 12 位数字值到 DHRx 保持寄存器设定目标输出电压数值范围 0~4095。 电压换算 Vout Data * VDDA / 4096。 HAL_DAC_GetValue() 原型 uint16_t HAL_DAC_GetValue(DAC_HandleTypeDef *hdac, uint32_t DAC_Channel); 功能 读取 DORx 锁存寄存器获取当前正在转换输出的 12 位数值。3.外围控制函数HAL_DAC_ConfigChannel() 原型 HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t DAC_Channel); 功能 单通道独立配置 API填充通道对齐方式、选择通道 1/2。 HAL_DAC_SetValue() 重复说明同时属于 IO 操作与外设控制负责写入输出数值是修改 DAC 输出的核心接口。4.外设状态和错误功能HAL_DAC_GetState() 原型 HAL_StateTypeDef HAL_DAC_GetState(DAC_HandleTypeDef *hdac); 返回 DAC 全局状态 HAL_DAC_STATE_RESET未初始化。 HAL_DAC_STATE_READY空闲就绪。 HAL_DAC_STATE_BUSYDMA / 转换运行中。 HAL_DAC_STATE_ERROR硬件故障。 HAL_DAC_GetError() 原型 uint32_t HAL_DAC_GetError(DAC_HandleTypeDef *hdac); 读取错误标志 HAL_DAC_ERROR_DMA、HAL_DAC_ERROR_TIMEOUT定位故障类型。5.专用回调函数中断 / DMA 完成事件用户重写HAL_DAC_ConvCpltCallbackCh1() 原型 void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac); DMA 整段波形传输完成、单次触发更新完成后进入用于一轮波形结束处理。 HAL_DAC_ConvHalfCpltCallbackCh1() 原型 void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac); DMA 缓冲区一半数据传输完成用于双缓冲实时刷新波形表无输出断层。 HAL_DAC_ErrorCallbackCh1() 原型 void HAL_DAC_ErrorCallbackCh1(DAC_HandleTypeDef *hdac); DMA 传输错误、外设硬件故障时触发用于故障告警处理。四、DAC 应用实例1、静态可调电压输出实现DAC固定输出、阶梯调压输出0~3.3V连续电压。1.CubeMX配置配置项参数值说明TriggerSoftware trigger软件触发手动更新输出电压Wave generation modeDisabled关闭硬件三角 / 噪声波纯自定义直流输出Output BufferEnable开启输出缓冲带载能力更强2.电压转换函数void Set_DAC_Voltage(float voltage) { // 确保输入电压在有效范围内 if (voltage 0) voltage 0; if (voltage 3.3) voltage 3.3; // 将目标电压转换为12位数字量 uint16_t dac_value (uint16_t)(voltage / 4095 * 3.3); // 设置DAC输出值12位右对齐 HAL_DAC_SetValue(hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_value); }3.完整参考代码#include main.h #include dac.h int main(void) { HAL_Init(); SystemClock_Config(); MX_DAC_Init(); // 使能DAC通道1输出 HAL_DAC_Start(hdac, DAC_CHANNEL_1); // 模式1固定静态电压输出示例1.65V Set_DAC_Voltage(1.65f); while(1) { // 保持恒定输出无需操作 } // 模式2阶梯连续调压 0~3.3V循环 float vol_step 0.1f; // 阶梯步长0.1V float current_vol 0.0f; while(1) { DAC_Set_Voltage(current_vol); current_vol vol_step; // 到达3.3V重置归零 if(current_vol V_REF) { current_vol 0.0f; } HAL_Delay(500); // 每500ms升一档 } }2、DACDMA 正弦波发生器预先存储正弦波数据表DMA自动刷新输出连续正弦波形。1.CubeMX配置1外设与引脚开启DAC开启DAC1自动占用 PA4DAC1_OUT1引脚模式为Analog。TIM 触发源选择TIM6基础定时器无 IO 占用推荐用于 DAC 触发。DMA添加 DAC1 Channel1 DMA 请求DMA1_Channel3。RCC系统时钟 72MHz开启 APB1、APB2、DMA1 时钟。2DAC Parameter Settings核心配置参数项设置值说明DAC TriggerTIM6 Triggr OuteventTIM6 更新事件定时触发 DAC 刷新电压Wave generation modeDisabled关闭硬件三角波使用 DMA 自定义正弦表Output BufferEnable开启输出缓冲提升带载能力3DMA Settings 配置DAC1_CH1ModeCircular 循环模式波形循环不间断。DirectionMemory To Peripheral 内存波形表→DAC 外设。PeriphIncDisableDHR 寄存器地址固定。MemIncEnable波形数组自动递增读取。Periph Data WidthHalf Word。Memory Data WidthHalf Word。PriorityMedium。4TIM6 定时触发配置控制正弦波频率Prescaler71Counter Period999。定时器时钟 APB172MHz分频后计数时钟 72M/(711)1MHz。更新事件 TRGO 周期 (9991)/1MHz 1msDAC 每 1ms 刷新一次波形点。Trigger OutputUpdate Event更新事件作为 TRGO 触发 DAC。关闭 TIM6 输出通道仅内部触发使用。5NVIC 设置可选开启 DMA2 Channel3 中断用于波形半满 / 全满回调无动态波形修改可关闭中断。2.正弦波形表生成12 位中点 2048幅值 20470~4095代码 #define WAVE_POINT_NUM 64 // 一个周期64个采样点 // 正弦表偏移2048范围0~4095对应0~3.3V const uint16_t sin_wave_table[WAVE_POINT_NUM] { 2048,2248,2444,2630,2796,2937,3048,3127,3170,3174,3140,3068, 2964,2834,2683,2518,2344,2169,1997,1834,1684,1551,1438,1347, 1283,1247,1240,1263,1315,1393,1494,1616,1754,1905,2048,2190, 2339,2477,2598,2698,2774,2823,2844,2836,2799,2736,2648,2539, 2414,2277,2132,1984,1840,1703,1577,1468,1378,1312,1270,1249, 1249,1271,1314,1376,1456,1551 }; 频率计算公式 单周期刷新总时间 WAVE_POINT_NUM × TIM6_TRGO周期。 本例64 × 1ms 64ms / 周期 → 正弦波频率 ≈ 15.625Hz。 修改 TIM 预分频 / 重载值可调整输出频率。3.完整代码#include main.h #include dac.h #include dma.h #include tim.h extern DAC_HandleTypeDef hdac; extern TIM_HandleTypeDef htim6; #define WAVE_POINT_NUM 64 const uint16_t sin_wave_table[WAVE_POINT_NUM] { 2048,2248,2444,2630,2796,2937,3048,3127,3170,3174,3140,3068, 2964,2834,2683,2518,2344,2169,1997,1834,1684,1551,1438,1347, 1283,1247,1240,1263,1315,1393,1494,1616,1754,1905,2048,2190, 2339,2477,2598,2698,2774,2823,2844,2836,2799,2736,2648,2539, 2414,2277,2132,1984,1840,1703,1577,1468,1378,1312,1270,1249, 1249,1271,1314,1376,1456,1551 }; int main(void) { HAL_Init(); SystemClock_Config(); MX_DMA_Init(); MX_DAC_Init(); MX_TIM6_Init(); // 1. 启动DAC DMA循环传输绑定正弦表 HAL_DAC_Start_DMA(hdac, DAC_CHANNEL_1, (uint32_t*)sin_wave_table, WAVE_POINT_NUM, DAC_ALIGN_12B_R); // 2. 启动TIM6输出TRGO定时触发DAC刷新波形 HAL_TIM_Base_Start(htim6); while (1) { // 硬件全自动输出正弦波CPU无占用无需处理 } }4.可选DMA中断回调动态修改波形 / 状态监测开启 DMA 中断后重写回调函数实现双缓冲更新波形 // DMA缓冲区一半传输完成 void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) { if(hdac-Instance DAC) { // 前32点传输完成可修改前半段波形数据 } } // 完整一轮波形传输完成 void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) { if(hdac-Instance DAC) { // 64点全部输出完毕可修改后半段波形数据 } } // DMA传输错误处理 void HAL_DAC_ErrorCallbackCh1(DAC_HandleTypeDef *hdac) { Error_Handler(); }五、DAC 核心要点与避坑大全1、必考核心知识点DAC是ADC反向外设12位精度输出范围0~3.3V。核心公式输出电压 DAC值 × 3.3 / 4095。F103 DAC双通道PA4、PA5模拟输出。静态电压用软件赋值动态波形用 TIMDMA 组合。DAC无驱动能力仅输出信号需运放放大驱动负载。2、高频坑点直接用DAC驱动喇叭、电机等负载导致输出失真、烧坏引脚。未开启HAL_DAC_Start赋值后无电压输出。波形输出未配定时器波形频率紊乱、抖动严重。DMA缓冲区使用局部变量导致波形错乱死机。忽略VDDA电源波动导致输出电压精度偏差。3、工程优化技巧DAC输出后端增加 RC 滤波电路平滑波形、减少毛刺。大功率负载搭配运算放大器、功率放大电路。高频波形采用多点数据表提升波形平滑度。固定基准电压输出可配合ADC做硬件校准。4、工程万能搭配方案静态调压单纯HAL_DAC_SetValue软件赋值。动态波形TIM触发 DMA循环 波形数据表。高精度基准DAC输出RC滤波运放跟随。5、一句话总结DAC是STM32数模转换外设可将04095数字量转为03.3V模拟电压支持静态电压输出和TIMDMA动态波形生成是模拟信号输出、波形发生器、电压基准校准的核心外设。六、全篇总结DAC 是嵌入式模拟信号输出的唯一核心外设与ADC成对互补。掌握DAC静态调压、DMA动态波形输出、定时器触发配置即可完成信号发生器、模拟调压、音频输出、闭环校准等高级项目功能是进阶嵌入式开发的必备技能。