使用ESP32做一个实时语音对讲机
最近突发奇想,制作一个数字式的音频通信系统,顺便学习一下I2S与ESP-NOW协议
刚开始查阅资料,发现油管上的已经有人做过了,但是使用的C++,并用了数据流的处理流程,比较晦涩难懂,代码量也很大,属于是炫技的作品,我这篇文章使用C重新写一遍,并且代码量大大降低,也很容易理解,let's get started!
上一篇博客中已经详细讲解了I2S通信协议,在ESP32中有两个硬件I2S,我们可以通过简单的配置使用它
ESP-NOW是乐鑫的私有协议,相比于传统的七层协议,ESP-NOW只保留了物理层与数据连接层,在其之上封装了ESP-NOW协议,但是这个协议是不开源的,意味着我们看不到这个协议的源码,只能使用封装出来的接口。
使用的硬件:
麦克风:INMP441
功放:MAX98357
主控:ESP32*2
按键与指示灯:板载
使用的软件:
Arduino IDE
ESP32扩展包 2.0.4(最新)
编程思路:
发送:初始化I2S采集后,数据会源源不断的存放在DMAbuf中,按下按键,将数据取出,转换成需要的格式,最终转换成8bit数据发送出去。
接受:在ESP-NOW接受回调函数中,将接收到的数据重新转换为16位, 发送到I2S中的DMA去。注意,在没有接收到消息的是否,需清空dambuf,要不然会重复播放上一帧的音频,发出很大的噪音。
数据流向:I2S采集->原始32bit->16bit->8bit->esp-now发送->接收到数据8bit->转换为16bit->I2S播放
具体配置:
麦克风采集配置
const i2s_config_t rec_i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S| I2S_COMM_FORMAT_I2S_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 2,
.dma_buf_len = 256,
}
扬声器采集配置:
const i2s_config_t spk_i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format =(i2s_comm_format_t)(I2S_COMM_FORMAT_I2S),
.intr_alloc_flags = 0,
.dma_buf_count = 2,
.dma_buf_len = 256,
};
其中,dambuf的两个参数的设定比较有讲究,可以点击这里学习。
硬件连接:
INMP441:
BCK --->>>IO4
WS --->>>IO15
data--->>>IO13
MAX98357:
BCK --->>>IO26
WS --->>>IO22
data--->>>IO25
开源github链接,点击我
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
功放的SD与GAIN可以不连接
支持支持,一键三连,
希望能出一些关于语音压缩的教程
最近工作也在搞音频压缩,可以考虑出一期
你好,可不可以用INMP441+esp32+百度AI做一个语音识别控制的分享,自己参考了网上的很多代码,都不成功。 万分感谢
UP主,两块板子可以正常通信了,但接收器一接喇叭后按灯就不能显示了,是不是电压不稳?功放是用外置电源么
.bck_io_num = 4, // BCKL
.ws_io_num = 15, // LRCL
.data_out_num = -1, // not used (only for speakers)
.data_in_num = 13 // DOUT
这几个引脚跟实际的标识不符呀
同问,这个怎么接啊
对i2s感兴趣,请问大佬i2s协议如何在linux系统中实现,目前使用的是rv1126核心板
i2s协议在linux系统中应该是作为一个外设使用,或许应该查看对应的芯片手册并建立驱动模型
请问一下大佬这个能用ESP32C3做出来吗
我记得我查过ESP32C3的资料,它只有一个硬件IIS,如果你想使用这个芯片,你可能需要一个支持播音与收音的codec,建议你再确认一下
能给个联系方式或者b站回复一下吗,在做这个的设计,想请教一下
录音的功能可以和通话功能并存吗?
你指的是收音放音共存是吗?你可能需要修改录音播音逻辑,我完成的只是一个demo,希望可你给你带来思路
@树莓 我用你的参考程序,编译时出现这个问题:Compilation error: invalid conversion from 'void ()(const uint8_t, const uint8_t*, int)' {aka 'void ()(const unsigned char, const unsigned char*, int)'} to 'esp_now_recv_cb_t' {aka 'void ()(const esp_now_recv_info, const unsigned char*, int)'} [-fpermissive]。是什么原因?
用AI处理好了.
看起来 `esp_now_register_recv_cb` 期望的回调函数签名是 `void (*)(const esp_now_recv_info*, const uint8_t*, int)`,而不是 `void (*)(const esp_now_recv_info*, const uint8_t*, const uint8_t*, int)`。
我们需要确保 `OnDataRecv` 的签名与此匹配:
```cpp
void OnDataRecv(const esp_now_recv_info* info, const uint8_t* data, int data_len)
```
以下是更新后的代码,包括所有的修正:
### `transport.cpp`
```cpp
#include
#include "Audioi2s.h"
#include "transport.h"
extern bool speakOut; // 确保在适当的位置声明了这个外部变量
extern bool recOver; // 确保在适当的位置声明了这个外部变量
void OnDataRecv(const esp_now_recv_info* info, const uint8_t* data, int data_len) {
if (0 == speakOut) {
return;
}
recOver = 1;
for (int i = 0; i < data_len; i++) { // 接收到信息后转换为16bit,补充左右声道,写入到I2S
recive_16bit[i] = (data[i] - 128)
大佬,为啥我使用这个代码做出来的录音正常电脑服务端可以收到,但是两台esp32之间发送时播放音频莎莎莎响,像是慢放一样