目录

关于PWM, DAC和音频

PWM是脉冲宽度调制的缩写, 因为介绍的文章很多, 自己做功课即可, 参考

大部分低端MCU不带DAC转换, 但是可以使用PWM模拟, 对于音频传输

  1. 人普通谈话的声波频率在500-2000Hz之间, 人耳可以听到的声波的频率范围在20Hz至20kHz之间
  2. 用于通话, 8kHz的带宽就能达到较好的语音传输效果
  3. 通过PWM模拟DAC, 因为PWM是方波, 其频率会引入底噪, 底噪的频率是PWM频率的倍数
  4. PWM频率在8KHz时, 在听感上底噪很大, 与传输的音频一样明显, 将PWM的频率调节到16kHz以上才能有效抑制底噪

通过MCU实现无线音频传输的实现

发送部分

接收部分

以下实现的是单声道 8kHz 8bit 采样的音频信号传输

发送部分

发送部分需要实现的是8kHz采样, 并通过NRF24L01将每秒的8000字节数据发送出去.

语音输入

语音输入可以使用驻极体话筒加S9013放大输入或者直接使用MAX9814. 在测试阶段建议使用后者, 可以保证采样输入不失真, 在调通后再用驻极体话筒电路替换.

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采样的传输是没问题的. 因为NRF24L01传输时的响应和重发机制, 在信号不好时, 容易卡顿, 为了避免中间传输时间的波动影响, 在实际实现中使用了双数组做缓冲. 采样到发送之间的逻辑为

  1. 两个256字节数组作为全局变量, 同时定义变量指向当前写入的数组编号和写入位置
  2. ADC中断读取结果时, 往当前编号的数组和位置中写入并移动位置, 当写满一个数组时, 将此数组标记为可发送, 并切换到下一个数组继续写入
  3. 在主进程中, 判断当前是否有可发送的数组, 如果可发送, 则在循环中按32个字节一组将数据全部发送.

因为在正常收发的信号强度下, NRF24L01的发送速度是比采样速度快的, 所以基本上NRF24L01的发送是发送 -> 等待 -> 发送的状态

接收部分

接收部分要实现的是将NRF24L01接收到的数据进行存储, 并按照8kHz的频率, 将每个值设为PWM输出的占空比, 实现DAC模拟

RNF24L01接收

因为NRF24L01发送是集中发送, 所以在接收时也需要有缓冲, 接收的机制和发送相似

  1. 两个256字节数组作为全局变量, 同时定义变量指向当前写入的数组编号和写入位置
  2. NRF24L01通过中断接收数据, 在接收时, 往当前编号的数组和位置中写入并移动位置, 当写满一个数组时, 将此数组标记为可用, 并切换到下一个数组继续写入

PWM模拟DAC还原

初始化一个PWM输出, PWM周期为256对应8bit的占空比调节范围, 确保PWM频率不低于16kHz. 在8kHz定时器的中断中, 判断当前读取的数组和位置, 每次读取一个值, 并将其设置为PWM占空比. 如果数组不可用, 就不做任何操作, 如果此时将占空比设为0, 会产生噪音.

音频输出

测时阶段, 可以在PWM输出上串联一个200R的电阻后值连喇叭, 可以听到输出的音频. 这个电阻不能太小, 测试中如果阻值小于100R, 会导致MCU供电不足反复重启. 在确定音频输出没问题后, 可以替换为 PAM8403 音频放大模块.

在使用 PAM8403 模块时

  1. 模块需要独立供电, 测试中如果与MCU都使用USB2TTL供电, 会使MCU供电不足而导致声音输出异常
  2. 模块与MCU的输出可以不共地, 即模块MCU的PWM输出和地, 可以直接接入PAM8403的音频输入
  3. 因为是单声道信号, 所以只能用PAM8403的一个声道, L或者R都可以

演示代码

接线说明

在测试中发送部分使用的是 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

注意:

  1. MCU的pin脚布局不一定相同, STC8H3K32S2和STC8H1K08都是20pin的封装, 但是pin脚布局就不一样
  2. 烧录发送部分和接收部分时, 注意要调换 nrf24l01.c 中的 RX_ADDRESS 和 TX_ADDRESS

效果演示

B站视频 https://www.bilibili.com/video/BV1kZ4y1Z78v

STC8H开发(八): NRF24L01无线传输音频(对讲机原型)的更多相关文章

  1. STC8H开发(九): STC8H8K64U模拟USB HID外设

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  2. STC8H开发(十): SPI驱动Nokia5110 LCD(PCD8544)

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  3. STC8H开发(十一): GPIO单线驱动多个DS18B20数字温度计

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  4. STC8H开发(十二): I2C驱动AT24C08,AT24C32系列EEPROM存储

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  5. STC8H开发(十三): I2C驱动DS3231高精度实时时钟芯片

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  6. STC8H开发(十四): I2C驱动RX8025T高精度实时时钟芯片

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  7. STC8H开发(十五): GPIO驱动Ci24R1无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  8. STC8H开发(十六): GPIO驱动XL2400无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  9. STC8H开发(五): SPI驱动nRF24L01无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

随机推荐

  1. 【LeetCode】590. N-ary Tree Postorder Traversal 解题报告 (C++&Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 迭代 相似题目 参考资料 日期 题目地址:htt ...

  2. Problem 2221 RunningMan(fuzoj)

     Problem 2221 RunningMan Accept: 130    Submit: 404Time Limit: 1000 mSec    Memory Limit : 32768 KB ...

  3. 51Nod 1264:线段相交(计算几何)

    51Nod 1264:线段相交 Decision 给出平面上两条线段的两个端点,判断这两条线段是否相交(有一个公共点或有部分重合认为相交). 如果相交,输出"Yes",否则输出&q ...

  4. Jenkins+Sonar质量门禁【实践篇-maven版】

    Jenkins+Sonar质量门禁[实践篇-maven版] 配置文档百度挺多的,就不展开来了 首先很遗憾的告诉大家,maven版做不了质量门禁!只能扫描!!!     就我们公司项目里,jenkins ...

  5. MySQL 的性能

    影响数据库性能的因素: SQL 脚本 数据库服务器配置 网卡流量 磁盘 IO 大表操作 大事务操作 存储引擎 数据库参数配置 1. SQL 脚本 超高的 QPS 和 TPS TPS:英文全称是 Tra ...

  6. uniapp与webview之间的相互传值

    1.uni-app 如何发送数据到 H5? 其实很接单.在 web-view 中只需要通过 URL 就可以向 H5 进行传参 例如在 uni-app 中: <template> <v ...

  7. 基于Spring MVC + Spring + MyBatis的【图书信息管理系统(一)】

    资源下载:https://download.csdn.net/download/weixin_44893902/34867237 练习点设计:模糊查询.删除.新增 一.语言和环境 1.实现语言:JAV ...

  8. JavaScript交互式网页设计 • 【第4章 JavaScript文档对象模型】

    全部章节   >>>> 本章目录 4.1 文档对象模型简介及属性 4.1.1 文档对象模型概述 4.1.3 实践练习 4.2 document 对象查找 HTML 元素 4.2 ...

  9. python 脚本或者flask 注册成为windows服务

    分享下脚本注册成为win服务 这个借鉴了其他大佬得 具体是谁忘记了有机会推荐 今天也是找了之前得改出来得 首先安装三个模块 最后一个是定时任务如果不需要可以不装 pip install psutil ...

  10. 使用docker快速部署一个consul集群

    作为一个开发者,有时候需要一个集群环境,之前的做法要么就是使用多个虚拟机,要么就是采用不同的端口来模拟,但是虚拟机比较占内存,而且启动慢,采用不同的端口来模拟,管理起来比较麻烦一些,程序隔离性差一些. ...