STM32F103 DAC实战:不写一行循环代码,用CubeMX配置双通道正弦波发生器

在嵌入式开发领域,STM32系列微控制器因其强大的性能和丰富的外设资源而广受欢迎。其中,数字模拟转换器(DAC)作为连接数字世界与模拟世界的重要桥梁,在音频处理、信号生成等场景中扮演着关键角色。本文将展示如何利用STM32CubeMX这一强大的图形化配置工具,在不编写任何底层驱动代码的情况下,快速实现双通道正弦波发生器的开发。

1. 环境准备与项目创建

首先确保已安装STM32CubeMX和对应的IDE(如Keil MDK或IAR Embedded Workbench)。打开CubeMX后,选择STM32F103系列芯片型号(如STM32F103C8T6),系统会自动加载该芯片的外设资源视图。

提示:建议使用最新版本的STM32CubeMX,以获得最完整的功能支持和最佳的代码生成体验。

创建新项目时,需要注意几个关键配置点:

  • 时钟配置 :确保系统时钟设置正确,这将影响后续定时器和DAC的工作频率
  • 调试接口 :通常选择SWD模式,便于后续程序下载和调试
  • 引脚分配 :PA4和PA5默认对应DAC通道1和通道2,避免与其他功能冲突

2. DAC外设图形化配置

在CubeMX的Pinout & Configuration界面中,找到DAC外设进行配置:

  1. 启用DAC通道

    • 勾选DAC Channel1和Channel2
    • 设置输出缓冲(Output Buffer)为Disable,以获得更精确的输出
  2. 触发源配置

    • 选择TIM6作为触发源(后续会配置定时器)
    • 触发模式选择为Timer Trigger
  3. DMA设置

    • 为DAC Channel2添加DMA请求
    • 配置DMA为循环模式(Circular),方向为内存到外设(Memory to Peripheral)
    • 数据宽度选择Word(32位)
// CubeMX自动生成的DAC初始化代码片段
static void MX_DAC_Init(void)
{
  DAC_ChannelConfTypeDef sConfig = {0};

  hdac.Instance = DAC;
  if (HAL_DAC_Init(&hdac) != HAL_OK)
  {
    Error_Handler();
  }
  
  sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
  
  if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  
  if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
}

3. 定时器与DMA配置

定时器负责以固定频率触发DAC转换,而DMA则负责自动将波形数据从内存传输到DAC数据寄存器。

3.1 定时器配置

  1. 启用TIM6(基本定时器)

  2. 设置预分频器(Prescaler)和周期(Counter Period)值

    • 假设系统时钟为72MHz,若希望生成1kHz正弦波(32点采样)
    • 定时器频率 = 1kHz × 32 = 32kHz
    • 预分频器 = 0(不分频)
    • 自动重装载值 = (72MHz / 32kHz) - 1 = 2249
  3. 启用定时器触发输出(Trigger Output)

// 定时器配置示例
static void MX_TIM6_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 0;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 2249;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler();
  }
  
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

3.2 DMA配置

在CubeMX的DMA配置界面中,为DAC Channel2添加DMA通道:

参数 说明
Direction Memory to Peripheral 数据从内存传输到外设
Increment Address Memory 内存地址自动递增
Data Width Word 32位数据传输
Mode Circular 循环模式,自动重复传输

4. 正弦波数据准备与工程集成

4.1 生成正弦波数据

可以使用Python、MATLAB或在线工具生成正弦波采样数据。以下是一个Python示例:

import numpy as np

points = 32  # 采样点数
amplitude = 2047  # 12位DAC最大值4095的一半
offset = 2048  # 使波形居中

sine_wave = amplitude * np.sin(np.linspace(0, 2*np.pi, points, endpoint=False)) + offset
dual_channel_data = [(int(sine_wave[i]) << 16) | int(sine_wave[i]) for i in range(points)]

print("const uint32_t DualSine12bit[32] = {")
print(", ".join([f"0x{x:08X}" for x in dual_channel_data]))
print("};")

4.2 在工程中使用波形数据

将生成的数据数组添加到工程中,通常放在main.c或单独的波形数据头文件中:

/* USER CODE BEGIN PV */
const uint32_t DualSine12bit[32] = {
    0x00000800, 0x09280928, 0x11A711A7, 0x18F218F2, 0x1EAD1EAD, 
    0x229E229E, 0x24922492, 0x24722472, 0x224F224F, 0x1E4E1E4E, 
    0x18A918A9, 0x11B711B7, 0x09B909B9, 0x00F800F8, 0xF7B0F7B0, 
    0xEF0CEF0C, 0xE73AE73A, 0xE0A4E0A4, 0xDB9EDB9E, 0xD86BD86B, 
    0xD72BD72B, 0xD7E5D7E5, 0xDA7CDA7C, 0xDEB1DEB1, 0xE42AE42A, 
    0xEA7EEA7E, 0xF13DF13D, 0xF7E5F7E5, 0xFDF8FDF8, 0x030F030F, 
    0x06E006E0, 0x093F093F
};
/* USER CODE END PV */

5. 启动波形生成

在main函数中,添加以下代码启动DAC和DMA传输:

/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim6);  // 启动定时器
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t*)DualSine12bit, 32, DAC_ALIGN_WORD_B);  // 启动DAC DMA传输
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);  // 启动DAC通道1(软件触发)
/* USER CODE END 2 */

6. 调试与优化

6.1 波形验证

使用示波器观察PA4和PA5引脚输出,应能看到两个同步的正弦波信号。如果波形有失真,可以尝试:

  • 调整定时器频率,确保不超过DAC的转换速率
  • 检查DMA传输是否正常,没有溢出或错误
  • 验证正弦波数据是否正确

6.2 性能优化

  • 采样点数 :增加采样点数(如64或128)可提高波形质量,但会占用更多内存
  • 双缓冲技术 :使用DMA双缓冲模式,可在波形播放时动态更新另一半缓冲区
  • 动态频率调整 :通过修改定时器重装载值,实现输出频率的动态调整

7. 扩展应用

基于此基础框架,可以轻松实现更多高级功能:

  1. 多波形切换 :预存多种波形数据(方波、三角波等),通过按键或通信接口切换
  2. 幅度调制 :动态调整DAC输出值,实现幅度调制
  3. 频率扫描 :通过改变定时器触发频率,实现扫频功能
  4. 音频应用 :结合DAC的DMA传输,实现简单的音频播放功能

在实际项目中,这种基于CubeMX的配置方法大幅减少了底层驱动开发时间,让开发者能够专注于应用逻辑的实现。通过合理利用STM32的外设协同工作能力,仅用少量配置就能实现复杂的模拟信号生成功能。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐