声音使用pwm 模拟 dac 输出 ,pwm的原理就是在高频率下按点空比翻转电平以达到类似线性模拟信号的目的,翻转的频率由时钟源最高频率与设置的分辨率值决定,大概是时针频率/ (2的分辨率次方) ,可能还有取模的步骤,分辨率就是一个周期内能控制的细腻程度,因为这种细粒度的控制其实现是需要时钟脉冲的,所以分辨率越高pwm的频率就只能越低,分辨率为1位时,pwm频率为最高时钟频率的一半。
使用pwm 输出音频一般是对音质没什么要求的场景,硬件资源可能也有限,可以选择 8bit 的采样深度,8khz的采样率,这样音频数据会比较小, 内容也能正常听清,pwm 的分辨率设置为8bit ,频率按时钟源来计算,循环取pcm数据设置为 每帧的占空比,每帧延时 125us,就可以正常播放音频 ,pwm 频率太低会有很大的噪音,因为pwm本质是方波,只有提高频率才能更线性。
下面是rust 实现的部分程序示例
const bytes: &'static [u8] = include_bytes!("../files/sing8bit.wav");
let wave = Wave::from_bytes(&bytes).unwrap();
match wave.data {
Samples::BitDepth8(samples) => {
loop {
println!("begin");
for sample in samples.iter() {
// 占空比的值
pwm_io.set_duty_hw(*sample as u32);
//这个延时很重要,通过音频采样率计算,
// 延时短了,就会有倍速播放的感觉,长了就慢速播放
//这里是8khz频率的延时
Delay.delay_us(125);
}
Timer::after_secs(2).await;
println!("end");
}
},
Samples::BitDepth16(samples) => println!("{:?}", samples),
Samples::BitDepth24(samples) => println!("{:?}", samples),
}