使用STM32的DAC + DMA + TIM实现音乐播放(HAL库)

在嵌入式系统中,利用STM32系列微控制器实现音频播放是一个常见而又具有挑战性的任务。常见的播放音频的方式包括:

  • TIM+PWM方式: 使用定时器(TIM)和脉冲宽度调制(PWM)技术来实现音频输出。通过定时器生成一定频率的PWM信号,控制扬声器或驱动电路的工作,从而产生模拟音频输出。这种方法简单高效,适用于低功耗应用和简单音频需求。
  • DAC+运放放大器到喇叭: 使用数字模拟转换器(DAC)将数字音频信号转换为模拟信号,然后通过运放(放大器)放大至喇叭驱动的电平。这种方法提供高保真度的音频输出,适用于需要良好音质和音量的应用,如音乐播放和语音提示。
  • IIS+语音解码芯片: 使用IIS(Inter-IC Sound)接口连接专用的语音解码芯片(如VS1053),通过解码器处理和解压音频数据,然后将模拟音频信号输出到喇叭或耳机。这种方式适用于需要播放多种音频格式(如MP3、WAV等)和复杂音频处理的应用场景。

本文主要介绍如何利用DAC+运算放大器到喇叭的方式,用到的有STM32F103RCT6的DAC(数字模拟转换器)、DMA(直接存储器访问)和TIM(定时器)模块,结合HAL库(Hardware Abstraction Layer),来实现音乐的数字转模拟输出,从而实现音频播放功能。

前期准备

在开始之前,需要进行一些准备工作:

硬件准备

  • STM32F103RCT6最小开发板:某宝买的
    image-20240702112919352image-20240702113014663

  • 功放模块:某宝买的
    image-20240702113251191

  • 4Ω3W喇叭:某宝买的
    image-20240702113522879

开发工具的下载与安装

  • STM32CubeMX的下载和安装

    STM32CubeMX是STMicroelectronics提供的用于STM32微控制器系列的图形化配置工具,可以帮助快速生成初始化代码和配置文件。

  • Adobe Audition的下载和安装

    Adobe Audition是一款音频编辑软件,用于编辑、处理和转换音频文件格式(可将MP3文件进行编辑并保存为WAVE文件)。

  • WinHex的下载和安装

    WinHex是一款十六进制编辑器,用于查看和编辑二进制文件(可将GoldWave保存的.WAV文件导出为C语言的数组)。
    注:该压缩包的后缀为.exe,这不是应用程序,是一个压缩格式,正常解压即可使用

WAVE(.wav)文件格式的介绍

Wave文件格式主要是用来存储音频PCM数据的。PCM数据是脉冲编码调制(Pulse Code Modulation)的音频数据,它是一种将模拟信号转换为数字信号的编码方式,PCM中的声音数据没有被压缩,。PCM数据的主要过程包括采样、量化和编码,其中采样是将模拟信号在时间上离散化,量化是将采样值按分层单位四舍五入取整量化,而编码则是将量化后的样值转换成对应的二进制码。

详细介绍可看这篇文章:WAVE(.wav)文件格式

使用STM32CubeMX生成DAC + DMA + TIM程序

一、DAC简介

DAC(Digital-to-Analog Converter),即数字/模拟转换模块,故名思议,它的作用就是把输入的数字编码,转换成对应的模拟电压输出,它的功能与 ADC 相反。在常见的数字信号系统中,大部分传感器信号被化成电压信号,而 ADC 把电压模拟信号转换成易于计算机存储、处理的数字编码,由计算机处理完成后,再由 DAC 输出电压模拟信号,该电压模拟信号常用来驱动某些执行器件,使人类易于感知。如音频信号的采集及还原就是这样一个过程。

STM32 具有片上 DAC 外设,它的分辨率可配置为 8 位或 12 位的数字输入信号,具有两个 DAC 输出通道,这两个通道互不影响,每个通道都可以使用 DMA 功能,都具有出错检测能力,可外部触发。

二、DAC通道选择

在 STM32 中具有 2 个这样的 DAC 部件,每个 DAC 有 1 个对应的输出通道连接到特定的引脚,即:PA4-通道 1PA5-通道 2,为避免干扰,使用 DAC 功能时,DAC 通道引脚需要被配置成模拟输入功能(AIN)

image-20240624140251867

三、新建工程

1、打开STM32CubeMX软件,点击”新建工程“
image-20240625102330536
2、选择MCU和封装
image-20240625102758814
3、配置时钟

RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)

image-20240625103847423

选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz,修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置

image-20240625104350242
4. 配置调试模式

非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器,SYS 设置,选择 Debug 为 Serial Wire

image-20240625104946096

四、DAC1配置

1、配置DAC1

Analog 中选择 DAC 设置,并选择 OUT1 Configuration 通道1

image-20240625105428685

或者在右边图找到 PA4 引脚,选择 DAC_OUT1

image-20240625105651872

具体配置参数如下

image-20240625111414878
  • OUT1/2 Configuration

    对应两个输出通道。

  • External Trigger

    外部中断EXTI9 触发 就是使用外部中断来触发DAC。

  • Output Buffer

    DAC输出缓存。

    DAC 集成了 2 个输出缓存,DAC输出缓存是一个内置于DAC模块中的运算放大器,用于缓冲DAC的输出信号。启用输出缓存可以改善信号驱动能力,降低输出阻抗,并提高转换速度和稳定性,无需外部运放即可直接驱动外部负载。每个 DAC 通道输出缓存可以通过设置 DAC_CR 寄存器的 BOFFx 位来使能或者关闭。如果带载能力还不行,后面就接一个电压跟随器,选择运放一定要选择电流大的型号。
    使能输出缓冲后,DAC 输出的最小电压为 0.2V,最大电压为 VREF±0.2,而未使能输出缓冲则输出可达到0V。

    image-20240625114010514
  • Trigger

    选择DAC的触发方式

    Timer 2/4/5/6/7/8 Trigger Out event 定时器触发,利用这种方式可以输出特定的波形。在这里我们选择定时器2。

    Software trigger 软件触发,在本模式下,向 DAC_SWTRIGR 寄存器写入配置即可触发信号进行转换。

  • Wave generation mode:Disable(不使用波形发生器)。

2、配置DMA
image-20240625114850860

点击 DMA Settings 添加 DAC_CH1 对应 DMA2 的通道3。DMA模式选择循环模式,方向选为内存到外设。

  • Priority
    当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在 DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通 道编号,编号越低优先权越高,比如通道 0 高于通道 1。在大容量产品和互联型产品中,DMA1 控制器拥有高于 DMA2 控制器的优先级。
  • Mode
    Normal 表示单次传输,传输一次后终止传输。
    Circular 表示循环传输,传输完成后又重新开始继续传输,不断循环永不停止。
  • Increment Address
    Peripheral 表示外设地址自增。
    Memory 表示内存地址自增。
  • Data Width
    Byte 一个字节。
    Half Word 半个字,等于两字节。
    Word 一个字,等于四字节。

五、TIM2配置

1、配置TIM2

Timers 中选择 TIM2 设置,时钟源 Clock Source 选择内部时钟 Internal Clock

image-20240627155641529

Parameter Settings 进行具体参数配置。

image-20240627160135940
  • Prescaler(时钟预分频数):0 驱动计数器的时钟 CK_CNT = CK_INT(即72MHz)/(0+1) = 72MHz 即不分频

  • Counter Mode(计数模式):Up(向上计数模式)

  • Counter Period(自动重装载值):9000-1

  • auto-reload-preload(自动重装载):Disable(不使能)

  • TRGO Parameters(触发输出):Update Event(更新事件) 在定时器的定时时间到达的时候输出一个信号(如:定时器更新产生TRGO信号来触发DAC的同步转换)

2、代码生成

输入项目名和项目路径(项目名称和路径不要包含中文),选择应用的 IDE 开发环境 MDK-ARM V5。

image-20240627181145313

每个外设生成独立的 ’.c/.h’ 文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。

image-20240627181311151

点击 GENERATE CODE 生成代码。

image-20240627181335093

使用Adobe Audition和WinHex生成音频波形数据表

一、将MP3文件转换成Wav文件

Adobe Audition 打开一个MP3音频文件,选择一段区域。右键,存储选区为。

image-20240628162024380

设置参数,然后导出

  • 格式:Wave PCM
  • 采样类型:8000 Hz,单声道,8位
  • 去除包含标记和其他元数据,这样生成的文件更小

image-20240628162213117

采样频率越高,文件越大,后面生成的波形数据表会更大,根据上面TIM2的参数配置

TIM2的定时器频率:f = Tclk/[(psc+1) * (cnt+1)] = 72MHz/9000 = 8KHz。

  • 定时器时钟Tclk:72MHz
  • 预分频器psc:0
  • 自动重装载值cnt:8999

所以我们采样频率选择 8000 Hz,位深选择 8位。

二、将生成的Wav文件生成音频波形数据表

用WinHex打开刚保存的Wav文件,并将其生成16进制数组并复制

image-20240628165656310

生成后的16进制数组如下:

unsigned AnsiChar data[46606] = {
	0x52, 0x49, 0x46, 0x46, 0x06, 0xB6, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, 
	0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x40, 0x1F, 0x00, 0x00, 0x40, 0x1F, 0x00, 0x00, 
	0x01, 0x00, 0x08, 0x00, 0x64, 0x61, 0x74, 0x61, 0xE2, 0xB5, 0x00, 0x00, 0x81, 0x80, 0x82, 0x81, 
	0x7E, 0x81, 0x81, 0x80, 0x7E, 0x81, 0x82, 0x81, 0x80, 0x82, 0x7F, 0x81, 0x7F, 0x80, 0x82, 0x7D, 
	0x7E, 0x82, 0x7F, 0x81, 0x80, 0x83, 0x7D, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x81, 
	0x81, 0x7E, 0x80, 0x80, 0x7E, 0x80, 0x80, 0x82, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7E, 0x82, 
	0x7F, 0x7E, 0x82, 0x81, 0x82, 0x7E, 0x81, 0x82, 0x7D, 0x7E, 0x83, 0x82, 0x7F, 0x7E, 0x82, 0x81, 
	0x7F, 0x7C, 0x80, 0x82, 0x80, 0x81, 0x82, 0x81, 0x80, 0x7F, 0x81, 0x80, 0x7F, 0x7F, 0x82, 0x7F, 
	0x80, 0x7F, 0x7E, 0x80, 0x81, 0x81, 0x7F, 0x81, 0x82, 0x7F, 0x80, 0x80, 0x82, 0x80, 0x7F, 0x7F, 
	0x82, 0x7E, 0x7E, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7E, 0x80, 0x82, 0x81, 0x80, 0x81, 
	......(数组太大不贴上来了)
};

注意注意,特别重要,DMA计数寄存器通常是16位的,因此DMA的最大计数值为65535。DMA的计数值指的是在一次DMA传输操作中需要传输的数据单元数,这些数据单元的大小取决于数据对齐方式,可以是字节(byte)、半字(halfword)或字(word)。每传输一个数据单元,DMA控制器会将计数值减1,直到达到0时传输完成。因此,数组大小不要超过65535个数据单元,否则DMA无法一次性传输全部数据,可能导致音乐播放中断或数据传输不完整的问题。

我理解的DAC+DMA+TIM的工作流程:DAC的触发源为TIM中断,因此每次TIM触发中断时,会触发DAC模块。DAC在接收到TIM中断后,会根据DMA传输的新数据生成相应的模拟电压输出。DMA自动从内存中获取下一个数据并将其传输到DAC,以实现连续更新模拟输出的功能。

将音频数据移植到STM32程序中并通过DAC输出音频信号

打开上面使用STM32CubeMX生成的STM32程序,将生成的16进制数组复制到main.c如下位置,同时修改unsigned AnsiCharconst uint8_t

image-20240628171245623

修改音频数据,将Wav文件协议头删除掉,留下音频数据,Wav协议具体看上面WAVE(.wav)文件格式的介绍,如下图,将红框中的协议头删除

image-20240628171814498

同时,数组大小也需要改变,协议头的大小为44个字节,所以数组大小也需要更改大小,如下

image-20240628172108155

在main函数中

添加 HAL_TIM_Base_Start() 函数,启动定时器。
添加 HAL_DAC_Start_DMA()函数,启动 DAC 的 DMA 输出。

int main(void)
{

    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_DAC_Init();
    MX_TIM2_Init();
    /* USER CODE BEGIN 2 */
    HAL_TIM_Base_Start(&htim2);
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)data, sizeof(data), DAC_ALIGN_8B_R);
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}

观察波形数据

将程序烧录到STM32F103RCT6开发板中,用示波器测量PA4引脚,波形如下

image-20240702114406568

观察波形和上面截取的MP3文件,可以看到两个波形是一样的,至此我们的DAC已正确输出音频信号,接下来只需将功放模块和喇叭正确连接上即可播放音乐。

播放音乐

将STM32F103RCT6开发板和功放模块和喇叭按下图进行连接,连接完成之后对STM32F103RCT6开发板进行上电,就可以听到喇叭播放音乐。

image-20240702115744714

STM32+功放+喇叭播放音乐

注意事项

用户代码要加在 USER CODE BEGIN NUSER CODE END N 之间,否则下次使用 STM32CubeMX 重新生成代码后,会被删除。
image-20240703090850117

总结

本文详细介绍了如何在STM32系列微控制器上实现音频播放,涵盖了从硬件准备、工具安装、音频文件处理到代码实现的全过程。以上内容仅作为个人开发时的学习总结,欢迎各位大佬对本文提供的代码和方法提出改进意见和建议,共同进步。

参考

STM32CubeMX学习笔记(21)——DAC接口使用(输出模拟音频波形)

STM32F103使用TIM DMA DAC实现播放WAV音乐

c 读取音频协议WAV文件头(再生成wav文件)

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
ADC和DACSTM32微控制器中常用的外设模块,用于模拟信号的采集和输出。ADC(Analog-to-Digital Converter)用于将模拟信号转换为数字信号,而DAC(Digital-to-Analog Converter)则用于将数字信号转换为模拟信号。 在给出的引用中,引用\[1\]是关于DAC的配置和初始化的代码。其中,通过配置DAC的通道和触发方式,以及启动DAC通道,实现DAC的初始化。 引用\[2\]是一个示例程序,展示了如何使用DMA功能完成ADC和DAC的数据传输。在该程序中,首先启动了ADC的DMA模式,用于将模拟信号转换为数字信号。然后启动了DACDMA模式,输出正弦波信号。 引用\[3\]是关于输出正弦波的代码。其中,定义了一个包含32个数值的数组,用于存储正弦波的采样值。通过启动定时器和DACDMA模式,将数组中的数值输出为模拟信号。 综上所述,通过配置和初始化DAC,并结合DMA功能,可以实现ADC和DAC的数据传输,从而实现模拟信号的采集和输出。 #### 引用[.reference_title] - *1* [STM32F4 (hal库)ADC+TIM1+DAC的配置](https://blog.csdn.net/qq_45305276/article/details/115221150)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [STM32物联网项目-DMA使用介绍(ADC+DAC)](https://blog.csdn.net/weixin_46251230/article/details/126721597)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值