本篇总结
使用 DAC + DMA + TIM,输出连续正弦波形。
🔑 KEIL MDK、UART调试、DAC、DMA、TIM
W55MH32L 内置 2 个 12 位 DAC(数模转换器),可将数字值转换为模拟电压输出。本示例使用 DAC1 通道 1(PA4 引脚)配合 DMA 和 TIM2 定时器,通过 32 点正弦波查找表循环输出连续正弦波。TIM2 每次溢出触发 DAC 转换,DMA 自动将查表数据搬运到 DAC 数据寄存器,无需 CPU 干预。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口收发测试工具:点击下载
硬件连接
本例程使用 DAC1 的通道 1(PA4 引脚)输出模拟正弦波。PA4 配置为模拟输出模式(AIN),可通过示波器探头测量波形。USART1 用于输出调试信息。
| 引脚 | 功能 | 方向 | 模式 |
| PA4 | DAC1_OUT(正弦波输出) | 开发板 → 示波器 | 模拟输入 (AIN) |
| PA9 | USART1_TX | 开发板 → PC | 复用推挽输出 (AF_PP) |
| PA10 | USART1_RX | PC → 开发板 | 浮空输入 (IN_FLOATING) |
工程结构
工程位于 SDK 内 1.SDK\ModuleDemo\DAC\,核心文件如下:
DAC/
├── USER/
│ ├── main.c ← DAC配置 + DMA配置 + TIM触发 + 正弦查表
│ ├── w55mh32_conf.h ← 外设头文件集中包含
│ ├── w55mh32_it.c/h ← 中断服务函数
│ ├── system_w55mh32.c/h← 系统初始化(时钟配置)
│ └── startup_w55mh32.s ← 启动文件
└── SYSTEM/
└── delay/
└── delay.c/h ← SysTick 延时函数
步骤1:DAC 与 DMA 配置
函数:DAC_Configuration() — 配置 PA4 为模拟输出,DAC1 使用 TIM2 触发、12 位右对齐、使能 DMA,DMA2 Channel3 循环搬运 32 点正弦查表数据。
/* 正弦波查找表(32点,12位) */
const uint16_t Sine12bit[32] = {
2048, 2447, 2831, 3185, 3495, 3750, 3939, 4056,
4095, 4056, 3939, 3750, 3495, 3185, 2831, 2447,
2048, 1648, 1264, 910, 600, 345, 156, 39,
0, 39, 156, 345, 600, 910, 1264, 1648
};
void DAC_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
/* PA4: DAC1_OUT → 模拟输出 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* DAC1: DMA使能 + 定时器触发 + 12位右对齐 */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_4095;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
/* DMA配置:内存→DAC1,循环模式 */
DMA_DeInit(DMA2_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR12R1;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Sine12bit;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 32;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA2_Channel3, &DMA_InitStructure);
DMA_Cmd(DMA2_Channel3, ENABLE);
DAC_DMACmd(DAC_Channel_1, ENABLE);
DAC_Cmd(DAC_Channel_1, ENABLE);
}
32 点正弦查找表覆盖一个完整周期,每个点为 12 位值(0~4095)。DAC 使用 DAC_Trigger_T2_TRGO(TIM2 触发),DMA 循环模式保证数据连续输出。DAC_OutputBuffer_Enable 使能内部输出缓冲器,增强驱动能力。
如果你想自定义
- 改波形频率 → 修改 TIM2 的
TIM_Period,频率 = 72M / (Period+1) / 32
- 改波形类型 → 替换
Sine12bit[] 为三角波、方波等查表数据
- 改分辨率 → 修改查表点数(如 64 点、128 点),同时修改 DMA_BufferSize
步骤2:TIM2 定时触发配置
函数:TIM_Configuration() — TIM2 定时器溢出时产生 TRGO 信号触发 DAC 转换。
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* TIM2 定时触发 DAC 输出 */
/* DAC输出频率 = TIM_CLK / (Prescaler+1) / (Period+1) / 32(查表点数) */
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_Period = 225; /* 72MHz / 226 / 32 ≈ 9.95kHz */
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
TIM_Cmd(TIM2, ENABLE);
}
输出频率 = TIM_CLK / (Period+1) / 查表点数 = 72MHz / 226 / 32 ≈ 9.95kHz。TIM_TRGOSource_Update 表示每次定时器溢出(更新事件)时输出触发信号。
编译与下载
Keil MDK 中打开 DAC.uvprojx,F7 编译,确认 0 Error(s)。连接 DEBUG USB 口到 PC,F8 下载。
运行验证
下载固件并按 RESET 后,用示波器探头测量 PA4 引脚,可观察到连续的正弦波形,频率约 10kHz,峰峰值约 3.3V。串口打印系统时钟和测试提示信息。如无示波器,可用万用表测量 PA4 平均电压约为 1.65V(正弦波中点)。
由于 DAC 输出为模拟信号,需使用示波器观察波形。本例程无串口截图,请在 PA4 引脚连接示波器验证正弦波输出。
常见问题
Q: PA4 无波形输出
确认 PA4 配置为 GPIO_Mode_AIN(模拟输入模式,DAC 输出时使用此模式)。检查 DAC_Cmd(DAC_Channel_1, ENABLE) 和 DMA_Cmd(DMA2_Channel3, ENABLE) 是否调用。确认 TIM2 已使能。
Q: 波形频率不正确
输出频率 = TIM2_CLK / (Period+1) / 查表点数。TIM2 时钟为 APB1 时钟(默认 36MHz),若 APB1 预分频不为 1,则 TIM2 时钟为 APB1 × 2 = 72MHz。调整 TIM_Period 改变频率。
Q: 波形失真或有台阶
增加查表点数(如 64 点或 128 点)可提高波形精度。确保 DAC_OutputBuffer_Enable 已使能以增强驱动能力。查表数据应均匀覆盖一个完整正弦周期。
总结
本文基于 W55MH32L 的 DAC1 配合 DMA 和 TIM2 实现了正弦波输出:
- 32点正弦查表:12 位精度(0~4095),覆盖一个完整周期
- DMA2 Channel3 循环模式自动搬运查表数据到 DAC 数据寄存器,无需 CPU 干预
- TIM2 定时触发:每次溢出产生 TRGO 信号触发 DAC 转换,输出频率 ≈ 10kHz
- PA4 引脚输出连续正弦波,峰峰值约 3.3V,可通过示波器观察验证