FireBeetle 直接放音(PWM篇)

前面介绍了FireBeetle 通过 DAC 来播放音频,除此之外,还可以使用 PWM 方式来播放音频。

关于 PWM动力老男孩在“Arduino系列教程之 – PWM的秘密(上)”【参考1】有介绍,对于我们来说,能用到的就是下面这一段:

PWM是用占空比不同的方波,来模拟“模拟输出”的一种方式。靠,这个太拗口了,简而言之就是电脑只会输出0和1,那么想输出0.5怎么办呢?于是输出01010101….,平均之后的效果就是0.5了。早这么说就了然了嘛。

比如,当前最高电压是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_t resolution_bits)

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

ledcWrite(uint8_t channel, uint32_t duty)

对通道设定当前的占空比(duty)

ledcAttachPin(uint8_t pin, uint8_t channel)

将 LEDC 通道绑定到指定 IO 口上

这样,我们就得到了一个和之前 DAC 很像的代码:

#include "audio\SoundData.h"

int freq = 8000*256;    // 频率
int channel = 0;    // 通道
int resolution = 8;   // 分辨率

const int led = 25;
void setup() {
  ledcSetup(channel, freq, resolution); // 设置通道
  ledcAttachPin(led, channel);  // 将通道与对应的引脚连接‘
  Serial.begin(115200);
}

void loop() {
  for (unsigned int i=0;i<2527766;i++) {
     ledcWrite(channel, WarOfWorldsWav[i]);
     delayMicroseconds(120);
  }
}

完整的代码和数据下载:

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

参考:

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

4.手册上有描述

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注