单片机使用数字模拟转换器(DAC)进行音频合成和波形生成

本文详细介绍了基于ArmCortex架构的MCU集成的数字模拟转换器(DAC)的特性,包括噪声波形生成、双通道模式、DMA、定时器触发以及在音频播放中的应用。通过实例演示了如何利用DAC生成正弦波和播放.WAV文件,突出了DAC在数字信号处理中的重要性。
摘要由CSDN通过智能技术生成

1 数字模拟转换器(DAC)的主要特点

1.1 概述

本文的MCU基于Arm®公司的Cortex®核心的MCU产品集成了具有不同配置和特点的DAC:

  • 一到三个输出通道
  • 噪声波形生成
  • 三角波形生成
  • DMA(直接内存访问)运行结束标志

专用模拟时钟 有关不同DAC配置的详细信息,请参阅对应的MCU数据手册和参考手册。

1.2 数据格式

如图1所示,DAC接受三种整数格式的数据:8位(数据保持寄存器的低8位),12位右对齐(数据保持寄存器的低12位),以及12位左对齐(数据保持寄存器的高12位)。

图1 DAC数据结构

模拟输出电压在每个DAC通道输出上由以下公式确定: 𝐷𝐴𝐶𝑂𝑢𝑡𝑝𝑢𝑡=𝑉𝑅𝐸𝐹×𝐷𝑂𝑅/4096DACOutput=VREF×DOR/4096

1.3 双通道模式

注意:此特性仅支持至少嵌入两个DAC的产品。

DAC有两个输出通道,每个通道都有自己的转换器。在双DAC通道模式下,转换可以独立或同时进行。 当DAC通道由同一触发源触发时,两个通道将被组合在一起进行同步更新操作,并且转换将同时完成。

1.4 专用定时器

除了软件和外部触发器,DAC转换还可以由不同的定时器触发。 TIM6和TIM7是基本定时器,旨在用于DAC触发。 每当DAC接口在选定的定时器触发输出(TIMx_TRGO)上检测到上升沿时,存储在DAC_DHRx寄存器中的最后数据将被传输到DAC_DORx寄存器(以MCU为示例)。 

图2. MCU DAC触发通道示例

1.5 DMA(直接内存访问)

MCU至少拥有一个具有多个通道(流)的DMA模块。每个DAC通道(流)都连接到一个独立的DMA通道。例如,微控制器中有4个DAC通道,DAC通道1连接到DMA通道3,而DAC通道2连接到DMA通道4。

当不使用DMA时,CPU被用来向DAC提供与要生成的波形相关的数字代码。这个代码存储在RAM中,或者存储在嵌入式非易失性(NV)存储器中,然后CPU将数据从存储器传输到DAC。 图3. 无DMA的DAC交互

图3 不带DMA的DAC接口示意图

当使用DMA(直接内存访问)时,系统的总体性能会通过释放CPU来提高。这是因为数据是由DMA从内存移动到DAC(数字模拟转换器),而无需CPU进行任何操作。这样,CPU资源就可以用于其他操作。 

图4 带DMA的DAC接口

 

1.6 DMA运行不足错误

当DMA被用来向DAC提供波形的数字代码时,可能会出现DMA传输速度比DAC转换速度慢的情况。在这些情况下,DAC检测到一部分波形数据尚未接收且无法转换,然后会设置“DMA运行不足错误”标志。

1.7 白噪声生成器

1.7.1 定义

MCU的DAC具有一个伪随机码生成器,如图5所示。 根据移位寄存器上使用的抽头,可以生成最多2^n-1个数字的序列,直到序列重复。

图5 DMA嵌入的伪随机码发生器

 图6说明了DAC的伪随机码生成器产生的噪声特性。白噪声是指在所有频率上具有相同功率的随机信号,其频谱是平坦的。这里提到的“平坦的频谱分布”意味着噪声在不同频率下的能量是均匀分布的,这是白噪声的一个典型特征。然而,与高斯分布(正态分布)不同,这里生成的噪声是均匀分布的,意味着在生成的数字序列中,每个数字出现的概率是相同的。图6可能是展示这种均匀分布特性的图表。

图6 噪声波形

 应用程序可以通过调整噪声波形的偏移量来生成具有特定信号模式的复合波形。在某些应用中,可能需要在噪声波形中加入一定的直流偏置(DC bias),或者根据需要调整偏移量以模拟特定的信号模式。通过编程控制偏移量,可以将预定义的信号模式与噪声波形相结合,从而生成所需的复合波形。

图7. 具有可修改偏移量的噪声波形

1.7.2 典型应用

STM32产品配备了12位增强型模数转换器(ADC),其采样率可以超过100万次/秒。在大多数应用中,这种分辨率已经足够。当需要更高准确度时,可以实施过采样和对输入信号进行抽取的方法,以节省使用外部ADC解决方案,并减少应用的功耗。这种噪声波形可以用来通过过采样方法提高ADC的精度。

有关这些方法的更多细节可以在对应的MCU规格官网找到,各MCU厂商都会详细讲解如何使用白噪声进行过采样。 白噪声生成器也可用于制作电子音乐,可以直接使用,或者作为滤波器的输入以创建其他类型的噪声信号。它在音频合成中被广泛使用,通常用于重现打击乐器(如铙钹)的声音,这些乐器在其频率域中具有高噪声含量。 白噪声生成器还可用于控制工程目的,例如对放大器和电子滤波器进行频率响应测试。

1.8 三角波生成器

1.8.1 定义

MCU嵌入的DAC模块为用户提供了一个具有可调偏移、幅度和频率的三角波形生成器。 三角波形的幅度可以通过DAC_CR寄存器中的MAMPx位来固定。

表2. 预编程的三角波形幅度值

MAMPx[3:0]位数字幅度模拟幅度 (伏特) (VREF+ = 3.3V)
010.0008
130.0024
270.0056
3150.0121
4310.0250
5630.0508
61270.1023
72550.2054
85110.4117
910230.8242
1020471.6492
≥ 1140953.2992

 如果需要更深入地了解三角波形的工作原理和特性,应该查阅应用的微控制器参考手册中专门介绍三角波形的部分。此外,它还说明三角波形的频率是如何依赖于触发信号源的频率的。在数字模拟转换器(DAC)的应用中,触发信号通常用于控制波形生成的开始和周期,因此触发源的频率直接影响了生成波形的频率特性。

 MCU的DAC中三角波形偏移量具有可编程特性。用户可以通过调整偏移量,结合预设的信号模式,生成一个信号模式和三角波形叠加的复合波形。同时,由于DAC硬件没有内置的溢出保护机制,因此在设置偏移量和幅度时需要特别注意,以确保它们的总和不会超过DAC的最大数字幅度值4095。如果超出这个值,可能会导致不正确的模拟输出或者潜在的硬件损坏。

图9. 具有可变偏移量的三角波形

 

1.8.2 典型应用

三角波生成器经常用于声音合成,因为它们的音色比方波(其上谐波的幅度下降得更快)要温和。

1.9 缓冲输出

为了在不使用外部放大器的情况下驱动外部负载,DAC通道具有嵌入式输出缓冲器,可以根据用户应用的需要启用或禁用。 当DAC输出未缓冲,并且在用户应用电路中存在负载时,由于DAC输出阻抗显著,输出电压会低于期望的电压(见图10)。请参阅相关的MCU数据手册以获取DAC输出阻抗的规格,有的MCU为了使输出电压降低不超过输出信号电压的1%,电阻性负载电阻必须高于1.5兆欧。 启用缓冲器时,输出电压和期望电压相似(见图11)。

图10. 非缓冲通道电压(带负载和不带负载)

 图10. 缓冲通道电压(带负载和不带负载)

缓冲输出允许DAC直接驱动外部负载,而不需要外部放大器,这在设计电路时可以提供更大的灵活性。同时,它也提到了在未启用缓冲器时,由于DAC的输出阻抗,可能会导致输出电压低于预期,因此需要根据DAC的输出阻抗选择合适的负载电阻。启用缓冲器后,可以显著减少电压降,使得输出电压更接近期望值。

2 应用示例

2.1 使用DAC生成正弦波形

2.1.1 描述

这个示例一步步描述了如何生成一个正弦波形。 正弦波形也称为单音信号,它是一种纯音(或正弦)音调。传统上,正弦音调被用作评估音频系统响应的刺激。

2.1.2 波形准备

为了准备波形的数字模式,我们需要进行一些数学计算。 我们的目标是获得十个正弦波形的数字模式数据(样本),该波形从0变化到2π。

图12. 正弦波模型样本

 采样步长是 2𝜋/𝑛𝑠(样本数量)。 正弦函数 sin⁡(𝑥)sin(x) 的值在 -1 和 1 之间变化,我们需要将其上移,以便得到一个正的正弦波,其样本值在 0 到 0xFFF 之间变化(对应于 0 到 3.3 V 的电压范围,其中 VREF 被设置为 3.3 V)。

数字输入通过在 0 到 VREF+ 之间的线性转换被转换为输出电压。 每个DAC通道引脚上的模拟输出电压由以下公式确定:

注:对于右对齐的12位分辨率:𝐷𝐴𝐶最大数字值=0𝑥𝐹𝐹𝐹

对于右对齐的8位分辨率:𝐷𝐴𝐶最大数字值=0𝑥𝐹𝐹

因此,模拟正弦波形 𝑦正弦模拟值 可以通过以下方程确定:

表3. 正弦波的数字和模拟样本值

样本 (x)数字样本值 𝑦正弦数字值(x)模拟样本值 (伏特) 𝑦正弦模拟值​ (x)
020481.650
132512.620
239953.219
339963.220
432532.622
520511.653
68470.682
71010.081
8980.079
98390.676

通过定时器触发输出的频率来设置DAC生成的正弦波信号的频率。定时器触发输出(𝑓TimerTRGOfTimerTRGO​)控制着DAC数据更新的速率,进而决定了生成的正弦波的频率。当定时器触发时,DMA会从内存中读取数据表中的下一个样本值,并将其传输到DAC,DAC随后将这个数字值转换为相应的模拟电压,从而产生连续的正弦波形。通过调整定时器的频率,可以改变正弦波的频率。

通过定时器的触发频率来确定DAC生成的正弦波的频率,并且指出了触发频率是DAC生成波形频率的两倍(在这个例子中是1MHz触发频率生成100kHz的正弦波)。此外,还提到为了生成更接近理论值的单音(正弦波),推荐使用尽可能多的样本点。这是因为在数字信号处理中,样本点的数量越多,生成的波形就越接近理想的连续波形,这种现象在图13和图14的比较中可以明显看出。 

图13. 使用ns=10生成的正弦波

图14. 使用ns=255生成的正弦波 

 

2.2 使用DAC实现音频播放器

2.2.1 描述

本演示的目的是提供一个基于ARM核MCU的音频播放器解决方案,用于播放.WAV文件。该方法旨在使用最少数量的外部组件,并为用户提供使用自己.WAV文件的可能性。音频文件存储在微SD记忆卡中,MCU可以通过SPI总线访问。

图15. 数据从微SD记忆卡流向外部扬声器的流程

 

2.2.2 音频波形文件规格

本应用程序假定要播放的.WAV文件具有以下格式:

  • 音频格式:PCM(一种未压缩的波形数据格式,其中每个值代表采样时信号的幅度)
  • 采样率:可能是8000、11025、22050或44100赫兹
  • 每样本的位数:8位(音频样本数据值在[0-255]范围内)
  • 通道数:1(单声道)

2.2.3 .WAV文件格式

.WAV文件格式是资源交换文件格式(RIFF)规范的一个子集,用于存储多媒体文件。RIFF文件以文件头开始,后跟一系列数据块。.WAV文件通常只是一个带有单个“WAVE”块的RIFF文件,由两个子块组成:

a)fmt块,指定数据格式

b)data块,包含实际的样本数据。

WAVE文件格式以RIFF头开始:它指示文件长度。

接下来,fmt块描述样本格式,它包含有关波形音频(PCM/...)的格式、通道数(单声道/立体声)、采样率(每秒样本数,例如22050)和样本数据大小(例如8位/16位)的信息。最后,data块包含样本数据。

2.3 音频波形播放器实现

音频波形播放器应用程序基于SPI、DMA、TIM6和DAC外设。

启动时,应用程序首先使用SPI与微SD卡接口,并使用DOSFS文件系统解析其内容,寻找USER文件夹中可用的.WAV文件。一旦找到有效的.WAV文件,它就通过SPI读回,数据使用CPU传输到位于RAM中的缓冲数组。DMA用于将数据从RAM传输到DAC外设。TIM6用于触发DAC,将音频数字数据转换为模拟波形。

在可以播放音频数据之前,需要解析.WAV文件的头部,以便确定数据的采样率及其长度。

通过使用样本数据(.WAV文件中包含的数据)更新DAC输出的值来实现音频再现任务,这些数据采用8位编码(值从0到255)。

DAC通道1由TIM6根据.WAV文件头的采样率定时触发。 .WAV文件从已经格式化为DOSFS文件系统的microSD™卡中读取。

在演示源代码项目中,音频播放器例程包含在C语言文件waveplayer.c和waveplayer.h中。 音频播放器任务通过调用图16中描述的WavePlayerMenu_Start()函数开始。

图16. 音频播放器流程图

当DMA从SRAM的一个缓冲区传输数据时,CPU将数据从microSD™ Flash存储器传输到另一个SRAM缓冲区。 

在本应用中,必须进行协同处理,以允许波形数字代码的同时读取(从外部存储器)和写入(到DAC寄存器)。

图17. 在波形播放过程中CPU和DMA的活动

 3 总结

本文展示了使用DAC音频处理和波形发生的基础知识,特别是第2节“应用示例”中给出的例子,帮助学习者熟悉了DAC的主要特点。 第一个示例(第2.1节:使用DAC生成正弦波形)展示了如何生成一个模拟波形(提供了正弦波形生成的源代码作为参考)。第二个示例(第2.2节:使用DAC实现音频播放器)提供了一个简单且灵活的解决方案,使用arm内核MCU播放存储在SPI microSD™ Flash存储器中的.WAV文件。

  • 27
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
生成锯齿波可以使用单片机的DA转换器。下面是一个基于STM32F103C8T6的示例代码,可以生成一个简单的锯齿波: ```c #include "stm32f10x.h" #define SAWTOOTH_LENGTH 1000 // 锯齿波的周期长度 #define DAC_MAX_VALUE 4095 // DAC转换器的最大值 int main(void) { // 初始化GPIO口 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // DAC输出引脚为PA4 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入模式 GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化DAC DAC_InitTypeDef DAC_InitStructure; DAC_InitStructure.DAC_Trigger = DAC_Trigger_None; // 不使用触发器 DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; // 输出缓冲器使能 DAC_Init(DAC_Channel_1, &DAC_InitStructure); // 初始化DAC通道1 // 启动DAC DAC_Cmd(DAC_Channel_1, ENABLE); // 生成锯齿波 while (1) { for (int i = 0; i < SAWTOOTH_LENGTH; i++) { DAC_SetChannel1Data(DAC_Align_12b_R, i * DAC_MAX_VALUE / SAWTOOTH_LENGTH); // 设置DAC输出值 delay(1); // 等待一段时间,控制输出频率 } } } void delay(int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < 1000; j++); } } ``` 在上述代码中,我们使用了STM32的DAC通道1,通过改变DAC输出值,可以生成不同的锯齿波形。我们使用一个for循环来控制输出的频率和周期,每次循环通过DAC_SetChannel1Data函数来设置DAC输出值。其中,i * DAC_MAX_VALUE / SAWTOOTH_LENGTH的计算结果就是当前的DAC输出值,通过改变i的值可以生成不同的锯齿波形。 需要注意的是,DAC输出值是一个0-4095的数字量,对应的是0-3.3V的模拟电压。因此,在使用锯齿波时需要注意输出电压的范围和波形的形状。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MUKAMO

你的鼓励是我们创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值