FireBeetle 直接放音(PWM篇)
本帖最后由 zoologist 于 2021-4-9 08:52 编辑前面介绍了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_tresolution_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);
delayMicroseconds(120);
}
}
测试结果表示和 DAC 的音质无差别。
前面提到了,PWM支持更高的分辨率,因此,我们可以尝试播放16Bits的音频。最简单的想法,直接将频率设定为8000Hz,然后PWM信号分辨率为16位。但是实际测试下来这样无法工作,经过研究,频率和分辨率之间有一定的限制关系【参考3】。在 8000Hz 下能够达到最高分辨率是13bits。最终实验表明使用12Bits 分辨率8000Hz 可以接收,再高噪音会较大。此外,16bits的 WAV 和 8Bits 的还有一个很大的区别在于:前者是有符号数值,后者是无符号数值。比如:0x8001实际上表示的是 -1。因此代码中取出数值后需要加上 0x8000 再做处理。另外,因为 16Bits 相对于 8Bits 数据量是直接翻倍了,导致无法在 Flash 中放下全部文件,为此,16Bits音频数据只是部分歌曲。
#include "audio\SoundData.h"
int freq = 8000*4; // 频率
int channel = 0; // 通道
int resolution = 12; // 分辨率
const int led = 25;
void setup() {
ledcSetup(channel, freq, resolution); // 设置通道
ledcAttachPin(led, channel);// 将通道与对应的引脚连接
}
void loop() {
int tmp;
for (unsigned int i=0;i<2831155;i=i+2) {
tmp=(int)(WarOfWorldsWav+(WarOfWorldsWav<<8));
tmp=tmp+0x8000;
ledcWrite(channel, tmp>>4);
delayMicroseconds(120);
}
}
参考:1.http://www.diy-robots.com/?p=814
2.https://blog.csdn.net/weixin_434 ... &utm_term=ledcWrite
3.https://forum.micropython.org/viewtopic.php?t=3717
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_numIn my MicroPython implementation, I'm currently working onenabling user selectable and/or automatic duty resolution and higher maxumumfrequencies.
4.手册上有描述
播放 8Bits 的代码和数据
播放 16Bits 的代码和数据
可以看到 16Bits 相对于 8Bits 数据量直接翻倍。
页:
[1]