[ESP8266/ESP32]FireBeetle 直接放音(PWM篇) 精华

2214浏览
查看: 2214|回复: 1

[ESP8266/ESP32] FireBeetle 直接放音(PWM篇)

[复制链接]
本帖最后由 zoologist 于 2021-4-9 08:52 编辑

前面介绍了FireBeetle通过 DAC 来播放音频,除此之外,还可以使用 PWM 方式来播放音频。
关于 PWM动力老男孩在“Arduino系列教程之 PWM的秘密(上)”【参考1】有介绍,对于我们来说,能用到的就是下面这一段:
PWM是用占空比不同的方波,来模拟模拟输出的一种方式。靠,这个太拗口了,简而言之就是电脑只会输出01,那么想输出0.5怎么办呢?于是输出01010101.,平均之后的效果就是0.5了。早这么说就了然了嘛。
FireBeetle 直接放音(PWM篇)图1
比如,当前最高电压是5V,如果输出50%的PWM信号,可以当作 2.5V 的信号输出。
对于 ESP32来说,有对 PWM的直接支持【参考2】。

Arduino core for the ESP32 并没有一般Arduino 中用来输出 PWM analogWrite(pin, value) 方法,取而代之的 ESP32 有一个 LEDC ,设计是用来控制 LED
ESP32 LEDC 总共有16个路通道(0 ~ 15),分为高低速两组,高速通道(0 ~ 7)由80MHz时钟驱动,低速通道(8 ~ 15)由 1MHz 时钟驱动。

对于我们来说,用到的函数有下面3个:

ledcSetup(uint8_t channel, double freq, uint8_tresolution_bits)

分别设定使用的通道(Channel),PWM 的频率, PWM 的分辨率。比如,我们设定1Hz 的频率,然后分辨率为4Bit,那么就可以设置从 0 15,一共16PWM值。可以看出,分辨率越高,可以细分出更多的 PWM值。

ledcWrite(uint8_t channel, uint32_t duty)
对通道设定当前的占空比(duty

ledcAttachPin(uint8_t pin, uint8_t channel)

LEDC 通道绑定到指定IO 口上
这样,我们就得到了一个和之前 DAC 很像的代码:

  1. #include "audio\SoundData.h"
  2. int freq = 8000*256;    // 频率
  3. int channel = 0;    // 通道
  4. int resolution = 8;   // 分辨率
  5. const int led = 25;
  6. void setup() {
  7.   ledcSetup(channel, freq, resolution); // 设置通道
  8.   ledcAttachPin(led, channel);  // 将通道与对应的引脚连接‘
  9.   Serial.begin(115200);
  10. }
  11. void loop() {
  12.   for (unsigned int i=0;i<2527766;i++) {
  13.      ledcWrite(channel, WarOfWorldsWav[i]);
  14.      delayMicroseconds(120);
  15.   }
  16. }
复制代码


测试结果表示和 DAC 的音质无差别。

前面提到了,PWM支持更高的分辨率,因此,我们可以尝试播放16Bits的音频。最简单的想法,直接将频率设定为8000Hz,然后PWM信号分辨率为16位。但是实际测试下来这样无法工作,经过研究,频率和分辨率之间有一定的限制关系【参考3】。在 8000Hz 下能够达到最高分辨率是13bits。最终实验表明使用12Bits 分辨率8000Hz 可以接收,再高噪音会较大。此外,16bits WAV 8Bits 的还有一个很大的区别在于:前者是有符号数值,后者是无符号数值。比如:0x8001实际上表示的是 -1。因此代码中取出数值后需要加上 0x8000 再做处理。另外,因为 16Bits 相对于 8Bits 数据量是直接翻倍了,导致无法在 Flash 中放下全部文件,为此,16Bits音频数据只是部分歌曲。

  1. #include "audio\SoundData.h"
  2. int freq = 8000*4;    // 频率
  3. int channel = 0;    // 通道
  4. int resolution = 12;   // 分辨率
  5. const int led = 25;
  6. void setup() {
  7.   ledcSetup(channel, freq, resolution); // 设置通道
  8.   ledcAttachPin(led, channel);  // 将通道与对应的引脚连接
  9. }
  10. void loop() {
  11.    int tmp;
  12.     for (unsigned int i=0;i<2831155;i=i+2) {
  13.       tmp=(int)(WarOfWorldsWav[i]+(WarOfWorldsWav[i+1]<<8));
  14.       tmp=tmp+0x8000;
  15.    ledcWrite(channel, tmp>>4);
  16.    delayMicroseconds(120);
  17.     }
  18. }
复制代码

参考:



The maximum PWM frequency with the currently used ledc dutyresolution of 10 bits in PWM module is 78.125KHz.
The duty resolution can be lowered down to 1 bit in whichcase the maximum frequency is 40 MHz, but only the duty of 50% is available.
For duty resolution of 8 buts, the maximal frequency is312.5 kHz.
The available duty levels are (2^bit_num)-1, where bit_num canbe 1-15.
The maximal frequency is 80000000 / 2^bit_num
In my MicroPython implementation, I'm currently working onenabling user selectable and/or automatic duty resolution and higher maxumumfrequencies.

4.手册上有描述

FireBeetle 直接放音(PWM篇)图2

zoologist  高级技匠
 楼主|

发表于 2021-4-9 08:49:51

播放 8Bits 的代码和数据
下载附件8BitsWavPWM.zip

播放 16Bits 的代码和数据
下载附件16BitsWavPWM.zip

可以看到 16Bits 相对于 8Bits 数据量直接翻倍。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail