使用PWM实现语音播放

本文转自ARM中文社区,作者:Xiaoya

链接:https://community.arm.com/cn/b/blog/posts/nucleof429-2-pwm

事实上大部分MCU都可以实现语音播放

下面是一段音频数据的波形

局部放大图:

以一定的速度采样(ADC)这些波形进行存储,就是音频数据了,所以播放就是按原来采样的速率再用DAC输出对应的数据即可。

这里的音频有两个主要的参数,采样速率采样位数

采样速率:指1s中采样多少个数据点,比如1s种采集16000个点,那么采样率就是16KHz。采样速率越高,越能抓到频率较高的声音,比如CD的采样率就是44.1KHz,确保人耳能听到的声音都会被抓到。

采样位数:指音频幅度最大值与最小值分为了多少阶,比如满幅度是3.3V,如果是8Bit位数,那么每一阶就是3.3V/256 = 12.89mv,采样位数越高,声音细节越好。所以采样速率和位数越高,声音还原越逼真,但存储的数据量也越大,一首三四分钟的歌曲,如果不采用编码按原始波形数据存储,数据量有好几十兆大小,这涉及到音频编码的问题,这里不展开讲了,有兴趣的同学可以找相关资料。

接下来看怎么播放,最简单的当然是把采样(ADC)的数据按原样输出(DAC)了。但我们有些芯片本身不带有DAC,所以只能用PWM代替DAC,PWM即脉冲宽度调制。这里只需要把DAC的幅度值转换成PWM的占空比即可,例如16KHz 8Bit的声音转换成16Khz 256阶占空比的PWM。但有一个问题,如果用16KHz的PWM播放语音,声音是可以播放,但有一个16Khz的谐波存在,这个声音会被人耳听到,所以需要更高频率的PWM,数据还是按照16Khz更新。

我这里使用32KHz的PWM,用16KHz 8Bit PCM格式的音频数据,8Bit的数据对应一个Byte,16KHz采样,1秒种占用存储空间就是16K Byte,F429有2M Byte的Flash存储空间,理论上可以存储2048K/16K = 128秒的音频。

下面是用NucleoF429实现音频播放的具体过程:

一、配置PWM

1、用STM32CubeMx建立工程,配置两个定时器TIM1和TIM2,TIM用于PWM产生,TIM2用于16KHz数据更新。

TIM1选择PWM互补输出(单通道也可以),将PE8和PE9复用为PWMN和PWMP。

TIM1在APB2总线上,TIM2在APB1总线上

所以TIM1和TIM2的时钟频率分别为180M和90M,系统时钟用HSE输入的8MHz。

将TIM1设置为32KHz,即31.25us。8Bit占空比,一个LSB为31.25us / 256 = 0.1220703125us = 8.192MHz,TIM1 180M / 8.192M = 21.97265625,这里取整数22。所以实际的PWM频率为1/(180 / 22) *256 =  31.289us = 31.96KHz

TIM2 为90MHz,45分频后为2MHz即0.5us,周期125即62.5us = 16KHz。

NVIC开启TIM2中断。生成工程名和目录后生成Keil工程。

二、播放语音

1、先编译后,编写TIM中断服务程序。

完成后,开启TIM2中断和PWM,(PWM是互补输出,需要单独开启各个通道)

用逻辑分析仪测量输出波形。

如图所示,TIM1 PWM为31.96KHz,TIM2为62.5us即16KHz,结果正确。

接下来处理音频:

这里使用的音频是PCM格式,是未进行压缩编码的原始数据,可以直接给PWM输出。

音频处理的软件有许多,只要能把格式转为PCM即可,下面是我用Cool Edit这款软件做的音频格式转换。

选择菜单 文件-->批量转换

选择新的采样率和采样位数。

选择PCM格式。设置输出目录后运行批处理完成转换。

完成后的音频文件用WinHeX这个软件打开。

图中红框中的44个Byte为PCM格式的文件头信息,后面的的数据为音频数据,数据全选后利用WinHex的可选格式复制

将数据以C数组的形式导出,在工程目录下新建.h文件,将复制的文件粘帖到.H文件并在工程中Include进来,定义起始和结束地址,数组的大小即为文件结束地址,数组用const修饰,可以将数据存储到Flash中。

在TIM2中,以16KHz的速度更新PWM数据即可实现音频播放。

编译工程,下载到NucleoF429板子上,在PE8或PE9上接一个喇叭即可听到声音。

以上用的音频采样是16K 8Bit,要想提高音质,提高采样和Bit数即可,音量可以用外接三极管或功放放大,音频数据也可以用ADC采集后存储到SPI Flash后播放,实现录音回放。

为了方便阅读,附件中包含了此文的PDF文档,Source Code也在附件中,可以直接下载到Nucleo运行。

公众号后台回复关键词:PWM语音,即可获取源码下载链接。


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/466086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C小项目 —— 学生选课系统

C小项目 —— 学生选课系统#include<stdio.h> #include<windows.h> #include<stdlib.h> #include<conio.h>typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t;#define CLASS_CLS system("cl…

为了杀蚊子,他用树莓派DIY了一把激光枪!

本文经AI新媒体量子位&#xff08;公众号ID&#xff1a;QbitAI&#xff09;授权转载&#xff0c;转载请联系出处。世人苦蚊子久矣。尤其在夏夜&#xff0c;耳边嗡嗡作响&#xff0c;甚至还得与其“挑灯夜战”个三百回合。为此&#xff0c;一个国外博士便DIY了一种高端的杀蚊方式…

java获取操作系统信息

Java代码 import java.util.Properties; Properties propsSystem.getProperties(); //获得系统属性集 String osName props.getProperty("os.name"); //操作系统名称 String osArch props.getProperty("os.arch"); //操作系统构架 String osVe…

scp和sftp常用操作

文件异地直接复制&#xff1a; scp SCP的全称是secure copy (remote file copy program)&#xff0c;此命令是openssh-clients附带的,它的作用就是在机器之间实现拷贝&#xff0c;且机器之间的传输完全是加密的。 最简单的 scp 用法如下&#xff1a; [rootwww ~]# scp [-pr] [-…

SM7250(高通5G)平台LCD bringup

写在前面的话高通平台显示这一块&#xff0c;自从去年开始&#xff0c;高通全面使用SMxxxx命名的芯片比如高端系列&#xff1a;SM8350(骁龙888)&#xff0c;SM8250(骁龙865)&#xff0c;SM8150(骁龙855)中端系列&#xff1a;SM7250&#xff08;骁龙765g&#xff09;&#xff0c…

网络管理人员的未来?

这是流传已久的一张带讽刺性的照片。一名网络专业的学生的未来难道真会如此&#xff1f;或者&#xff0c;是某些人理解错了这个专业的诸多特性&#xff1f;转载于:https://blog.51cto.com/zhangbikai/166694

python笔记-1(import导入、time/datetime/random/os/sys模块)

python笔记-6&#xff08;import导入、time/datetime/random/os/sys模块&#xff09; 一、了解模块导入的基本知识 此部分此处不展开细说import导入&#xff0c;仅写几个点目前的认知即可。其它内容待日后有深入理解了再来细说 1、import可以导入的两种不同的内容 1.1 *.py文件…

嵌入式里如何给内存做压力测试?不妨试试memtester

大家好&#xff0c;我是痞子衡&#xff0c;是正经搞技术的痞子。今天痞子衡给大家介绍的是内存读写正确性压力测试程序memtester。在嵌入式系统中&#xff0c;内存(RAM)的重要性不言而喻&#xff0c;系统性能及稳定性都与内存息息相关。关于内存性能有很多个不同指标&#xff0…

一位嵌入式工程师的成长之路

有些事并不是因为有希望才去坚持&#xff0c;而是因为坚持了才有希望。分享一位嵌入式工程师的成长之路&#xff0c;希望能给朋友一点勉励。刚毕业找不着工作2008年大专毕业后&#xff0c;意气风发南下深圳找工作&#xff0c;想找一份电子技术员的工作&#xff0c;白天上班&…

分享GitHub上一些嵌入式相关的高星开源项目

关于GitHub&#xff0c;可能很多人误以为这是互联网人的专属&#xff0c;其实并不是&#xff0c;那上面嵌入式相关的开源项目是有很多的。现分享一些高星开源项目&#xff08;像RT-Thread、AWTK等大家都熟知的就不介绍了&#xff09;&#xff1a;Avem项目链接&#xff1a;https…

安全四部曲之一---***工具简单使用

所需工具&#xff1a;ASP小旋风5.asp(黑防)鸽子2006ie_xpsp2网马生成器##############Michael分割线################先给大家几个外网路由的地址你们进去捣乱捣乱,没事的,因为没有日志记录用户名密码 全都是admin,别搞太破坏哦如果改动里面的设置,记得把登录密码改了,否则他们…

第 8 章 配置listener监听器

第 8 章 配置listener监听器注意 还记得我们之前讲过的在线列表吗&#xff1f;第 4.2 节 “例子&#xff1a;在线列表”。我们曾经说过那个在线列表无法判断用户非法退出&#xff0c;很可能造成在线列表无限增大&#xff0c;现在我们可以用listener来弥补这一问题了。如果你不满…

集合(collection)

使用数组存放数据的弊端&#xff1a;长度不可变&#xff0c;而集合可以动态的添加值 java集合类不仅可以存储数量不等的多个对象&#xff0c;还可以保存具有映射关系的关联数组 /* * 1.存储对象可以考虑&#xff1a;①数组 ②集合 * 2.数组存储对象的特点&#xff1a;Student[]…

聊培训跳槽的事

■原来跟我沟通有压力这是我最近跟一个微信好友聊天才知道的事情&#xff0c;说跟我沟通还挺有压力的。实话说&#xff0c;我多少对这样的感觉感同身受&#xff0c;记得刚毕业那会&#xff0c;跟我师傅聊天说事情&#xff0c;总担心自己会说错了什么&#xff0c;有问题的时候也…

iOS开发针对对Masonry下的FPS优化讨论

今天博客的内容就系统的讨论一下Masonry对FSP的影响&#xff0c;以及如何更好的使用Masonry。如果你对iOS开发足够熟悉的话&#xff0c;那么对Masonry框架应该不陌生。简单的说&#xff0c;Masonry的诞生让AutoLayout的使用更为优雅&#xff0c;让控件的布局更为方便。使用辩证…

导师带学生卡Bug,这波操作~

本文来自知乎https://www.zhihu.com/question/455891395/answer/1847953969事情的起因是明尼苏达大学计算机科学&工程系的助理教授 Kangjie Lu 和他的 Ph. D. 学生 Qiushi Wu 的论文《通过伪君子提交在开源软件中隐蔽地引入漏洞的可行性》&#xff0c;据称将在 2021 年五月…

我想做个MP3,要怎么入手?

从我更新的频率&#xff0c;大家应该猜出来了&#xff0c;最近有点忙。忙完了设备调试的工作&#xff0c;又来了个画图的活。本来改动不大&#xff0c;但怎料...哎&#xff0c;一言难尽。今天回答一个粉丝的提问&#xff1a;看完这个回复&#xff0c;我依然没明白他到底想做哪部…

[内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析

关于进程上下文&#xff0c;中断上下文&#xff0c;请看这篇文章Linux进程上下文和中断上下文内核空间和用户空间自旋锁的初衷&#xff1a;在短期间内进行轻量级的锁定。一个被争用的自旋锁使得请求它的线程在等待锁重新可用的期间进行自旋(特别浪费处理器时间)&#xff0c;所以…

网络流24题 洛谷 3355 骑士共存

转换成最小割&#xff1b; #include <bits/stdc.h>using namespace std ;const int mx [ 9 ] { 2 , 2 , -2 , -2 , -1 , 1 , -1 , 1 } ; const int my [ 9 ] { -1 , 1 , -1 , 1 , 2 , 2 , -2 , -2 } ; const int N 100000 10 , inf 1e8 7 ;queue < int …

从零开始设计CPU

CPU&#xff0c;中文全称为中央处理单元&#xff0c;简称处理器&#xff0c;是现代电子计算机的核心器件。如果你想了解一台计算机是如何构建并工作的&#xff0c;那么深入了解CPU的设计非常有用。不过&#xff0c;这个美好的愿望是否会遭遇“骨感”的现实呢&#xff1f;毕竟一…