STC8H开发(八): NRF24L01无线传输音频(对讲机原型)
时间:2022-08-18 10:30:02
目录
- STC8H开发(1): 在Keil5中配置和使用FwLib_STC8包装库(图文详解)
- STC8H开发(二): 在Linux VSCode配置和使用FwLib_STC8包装库(图文详解)
- STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明
- STC8H开发(4): FwLib_STC8 封装库的介绍和使用注意事项
- STC8H开发(五): SPI驱动nRF24L01无线模块
- STC8H开发(6): SPI驱动ADXL345三轴加速试验模块
- STC8H开发(7): I2C驱动MPU6050三轴加速度 三轴角速度检测模块
- STC8H开发(八): NRF24L01无线传输音频(对讲机原型)
关于PWM, DAC和音频
PWM是脉冲宽度调制的缩写, 因为介绍的文章很多, 自己做作业, 参考
- 维基百科 Pulse-width_modulation
- 百度百科 PWM技术
大部分低端MCU不带DAC转换, 但是可以用PWM模拟, 音频传输
- 500-20000人普通谈话的声波频率Hz之间, 人耳能听到的声波频率范围为20Hz至20kHz之间
- 用于通话, 8kHz带宽可以达到更好的语音传输效果
- 通过PWM模拟DAC, 因为PWM是方波, 其频率会引入底噪, 底噪的频率是PWM频率的倍数
- PWM频率在8KHz时, 底部噪音噪很大, 和传输的音频一样明显, 将PWM将频率调整到16kHz以上可有效抑制底噪
实现无线音频传输
发送部分
接收部分
以下是单声道 8kHz 8bit 采样的音频信号传输
发送部分
发送部分需要实现8kHz采样, 并通过NRF24L发送每秒8000字节数据.
语音输入
语音输入可以使用驻极体麦筒S放大输入或直接使用9013MAX9814. 建议在测试阶段使用后者, 采样输入可保证不失真, 调通后,用驻极体话筒电路代替.
ADC音频采样
因为ADC每秒8000采样需要准确, 所以不能用DMA方式, 在STC8H(包括STM32等其它MCU)下, 无法在DMA准确调整每秒采样数, 因为ADC采样频率, 采样周期和转换周期不同MCU都是固定的, 所以很难做到8kHz的采样. 实现有两种具体方式:
1.定时器驱动采集
定时器设置为8kHz, 开始中断ADC转换, 更容易实现. 此时需要将ADC也实现为中断, 因为ADC转换时间较长, 如果在定时器中断同步ADC转换, 主过程容易受到影响. 定时器需要中断和处理ADC中断处理, 定时器的中断处理仅用于启动转换, ADC读出结果的中断是用来的.
2.连续阅读连续阅读
定时器设置为8kHz, 将ADC采集设置为循环(中断采集, 但中断时再次启动), 只在定时器中断中读取采集结果. 这种方法也可以实现8kHz的采样. 因为这样实际上会消耗更多的电, 因此,在实际使用中仍采用了前一种方法.
NRF24L01发送
NRF24L01在设置为1Mbps带宽实际传输速度达到23k字节每秒, 因此对于8bit 8kHz采样的传输没有问题. 因为NRF24L响应和重发机制01传输, 当信号不好时, 容易导致发送中断, 为避免传输时间的波动, 双数组用于实现缓冲. 从采样到发送的逻辑是
- 两个256字节数组作为全局变量, 同时,定义变量指向当前写入的数组编号和写入位置
- ADC中断读取结果时, 将并移动位置写入当前编号的数组和位置, 写满一个数组时, 将此数组标记为可发送, 并切换到下一个数组继续写入
- 在主过程中, 判断目前是否有可发送的数组, 如果可发送, 循环中按32个字节发送所有数据.
由于信号强度正常收发, NRF24L01的发送速度比采样速度快, 所以基本上NRF24L01的发送是发送 -> 等待 -> 发送的状态
接收部分
接收部分应实现NRF24L存储01收到的数据, 并按照8kHz的频率, 设置每个值PWM输出占空比, 实现DAC模拟
RNF24L01接收
因为NRF24L01发送是集中发送, 而PWM恢复是匀速的, 因此,接收也需要缓冲, 接收机制与发送机制相似
- 两个256字节数组作为全局变量, 同时,定义变量指向当前写入的数组编号和写入位置
- NRF24L01通过中断接收数据, 在接收时, 将并移动位置写入当前编号的数组和位置, 写满一个数组时, 将此数组标记为可用, 并切换到下一个数组继续写入
PWM模拟DAC还原
初始化一个PWM输出, PWM周期为256对应8bit空比调节范围, 确保PWM频率不低于16kHz. 在8kHz定时器中断, 判断当前读取的数组和位置, 每次读一个值, 并将其设置为PWM占空比. 若数组不能使用, 不做任何操作, 若此时占空比为0, 会产生噪音.
音频输出
测时阶段, 可以在PWM在输出上串联2000R后电阻值连接喇叭, 输出音频可以听到. 电阻不能太小, 如果测试中的电阻小于1000R, 会导致MCU供电不足反复重启. 在确定音频输出后, 可以替换为 PAM8403 音频放大模块.
在使用 PAM8403 模块时
- 模块需要独立供电, 如果在测试中与MCU都使用USB2TTL供电, 会使MCU供电不足导致声音输出异常
- 模块与MCU输出可不共地, 即模块MCU的PWM输出和地, 可直接接入PAM8403的音频输入
- 因为是单声道信号, 所以只能用PAM8403的声道, L或者R都可以
演示代码
- GitHub FwLib_STC8/tree/master/demo/spi/nrf24l01_audio
- Gitee FwLib_STC8/tree/master/demo/spi/nrf24l01_audio
接线说明
在测试中使用发送部分 STC8H3K32S2, 接收部分使用 STC8H1K08, 你可以使用STC8H任何型号的系列
共同连接部分(NRF24L01)
8H3K32S2/8H1K08 NRF24L01 P35(SS, Ignored) => CSN 16 P34(MOSI) => MOSI 15 P33(MISO) => MISO 14 P32(SPCLK) => CLK 13 P36(INT2) => IRQ 17 P37(IO) => CE 18
发送部分
STC8H3K32S2 MAX9814 P11(ADC1) => MIC 3.3V => VDD 3.3V => GAIN GND => A/R GND => GND
ADC, 如果是STC8H3K32S2, 使用ADC采样需要将AVcc, AGnd 和 ADC_Vref 正确连线
AVcc => 3.3V AGnd => GND ADC_Vref => 3.3V P11 => Output(MAX9814) or MIC
接收部分
STC8H1K08 PAM8403 P10(PWM1P) => 200R => L or R Input GND => _|_ Input Ext 3.3V/5V => VCC Ext GND => GND
注意:
- MCU的pin脚布局不一定相同, STC8H3K32S2和STC8H1K08都是20pin的封装, 但是pin脚布局就不一样
- 烧录发送部分和接收部分时, 注意要调换 nrf24l01.c 中的 RX_ADDRESS 和 TX_ADDRESS
效果演示
B站视频 https://www.bilibili.com/video/BV1kZ4y1Z78v
调试说明
因为这个演示实际上包含了定时器, ADC采样, NRF24L01发送, 接收, PWM调制这几个环节, 任一个环节出问题, 都会导致演示失败. 在调试中, 需要遵循化整为零, 逐个确认的原则, 对每个节点是否工作正常进行确认.
定时器调试
因为8kHz的输出较难观测, 可以用一个uint16_t的全局变量自增到8000后串口输出观察时间间隔是否正确
ADC调试
- 先通过同步模式, 查看ADC采集是否正确, STC8H1K和STC8H3K的ADC接线是不一样的, 如果接线不正确, 输出的就是噪音.
- 同步采样没问题后, 再通过中断方式采集检查是否正确
- 中断没问题后, 就可以结合定时器, 通过定时器发起采样
NRF24L01 调试
可以参考前面的例子SPI驱动nRF24L01无线模块 单独运行 NRF24L01 进行收发是否功能正常
PWM 调试
有条件的可以用逻辑分析仪, 输出正常后, 用音频进行测试, 可以参考PWM输出音频这个例子, 循环播放一段8bit音频检查PWM输出是否正确, 因为音频较大, 测试这个需要使用Flash容量至少32K字节的芯片, 例如STC8H3K32S2.
最小系统联调
最小系统的发送端先不使用ADC, 使用固定的8bit音频作为输入进行发送, 接收端先不外接音频放大, 直接用200欧串联小喇叭进行检查, 工作正常的情况下, 音频播放效果应当是非常好的
在最小系统联调没问题后, 就可以开始调试ADC, 没问题后最后加入音频放大模块.