【平头哥RVB2601创意应用开发】环境监测终端04-声音采集和动感光条显示
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">本篇文章介绍</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">使用</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体">RVB2601</span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">开发板自带的</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">麦克风采集周围的声音,记录单位时间内的最大值,用以表示环境噪声水平。为了更直观显示,在</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">OLED显示屏上设计</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">了一个动感光条,能够随着声音节奏跳动</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">。</font></span></span></span></span></p><p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">1、准备工作</font></span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">开始动工之前首先是查阅资料,做准备工作。作为推出有一段时间的单片机系统,网上早有大神做过声音方面的试验。我的本次试验就是先学习了</font>“我爱下载</span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">”同学的《麦克风录音测试》文章,整明白声音采集原理后开始动手的,原贴链接如下。</font></span></span></span></span></p>
<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><a href="https://occ.t-head.cn/community/post/detail?spm=a2cl5.26076654.0.0.56981f9cfBQl94&id=3945884479054815232"><u><span class="15" style="font-size:14.0000pt"><span style="font-family:黑体"><span style="color:#0000ff"><span style="text-decoration:underline"><span style="text-underline:single">https://occ.t-head.cn/community/post/detail?spm=a2cl5.26076654.0.0.56981f9cfBQl94&id=3945884479054815232</span></span></span></span></span></u></a></span></span></p>
<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">2、硬件原理</font></span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">首先介绍一下硬件原理。</font>RVB2601 通过 I2S 和 I2C 总线连接 ES7210 ADC 芯片,实现硅麦的音频信号采样。原理图如下。</span></span></span></span></p>
<p class="imagemiddle" style="text-align: center;"></p>
<p align="center" style="text-align:center"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">图</font>1、音频采样原理</span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体">CH2601采用I2C接口完成ES7210的配置,采用I2S接口读取ES7210的转换数据,其接口如图所示。</span></span></span></span></p>
<p class="imagemiddle" style="text-align: center;"></p>
<p align="center" style="text-align:center"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">图</font>2、硬件接口</span></span></span></span></p>
<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">3、软件设计</font></span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">软件驱动设计</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">使用了</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体">CODEC</span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">编解码库。</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体">CODEC在这里指的是同时具有D/A(数字讯号转换成模拟讯号)和A/D(模拟讯号转换成数字讯号)转换功能的编解码器,播放音乐的时候用到的是D/A转换功能。在录音的时候用到的是A/D转换功能。</span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">具体的详细介绍和使用方法见如下官方链接。</font></span></span></span></span></p>
<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><a href="https://yoc.docs.t-head.cn/yocbook/Chapter3-AliOS/CSI%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%8E%A5%E5%8F%A3/CSI2/CODEC.html"><u><span class="15" style="font-size:14.0000pt"><span style="font-family:黑体"><span style="color:#0000ff"><span style="text-decoration:underline"><span style="text-underline:single">https://yoc.docs.t-head.cn/yocbook/Chapter3-AliOS/CSI%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%8E%A5%E5%8F%A3/CSI2/CODEC.html</span></span></span></span></span></u></a></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">在接口中,</font>D/A指的是输出通道,A/D指的是输入通道。</span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">本次实验</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">主要使用</font>AD的输入通道</span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">。用到的</font></span></span><span style="font-size:14.0000pt"><span style="font-family:黑体">CODEC的CSI接口如下所示:</span></span></span></span></p>
<p class="imagemiddle" style="text-align: center;"></p>
<p align="center" style="text-align:center"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">图</font>3、软件接口</span></span></span></span></p>
<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">4、代码编写</font></span></span></span></span></p>
<p align="justify" style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="text-justify:inter-ideograph"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">下载官方例程</font>ch2601_ft_demo,截取其中录音部分代码。因为本次应用只需要声音幅值,对其代码大幅删减改造,将缓存缩小,只保留一个采样周期就行,每次采样完成,计算这个周期内的音频数据最大值,这个结果就作为要输出的实时音量数据。可以通过串口打印输出,也可以传递给其他任务用于显示。音频采样代码如下。</span></span></span></span></span></p>
<pre>
<code class="language-cpp">#include <stdlib.h>
#include <aos/aos.h>
#include "board_config.h"
#include "drv/codec.h"
#include "drv/dma.h"
#include <drv/ringbuffer.h>
#include "snd_get.h"
csi_codec_t codec;
csi_codec_input_tcodec_input_ch;
csi_dma_ch_t dma_ch_input_handle;
#define INPUT_BUF_SIZE2048
uint8_t input_buf;
ringbuffer_t input_ring_buffer;
volatile uint32_t cb_input_transfer_flag = 0;
int16_t sound_buff;
volatile int16_t sound_max=0;
static void codec_input_event_cb_fun(csi_codec_input_t *i2s, csi_codec_event_t event, void *arg)
{
if (event == CODEC_EVENT_PERIOD_READ_COMPLETE) {
cb_input_transfer_flag += 1;
}
}
void cmd_ft_mic_handler(uint32_t channel_status)
{
csi_error_t ret;
csi_codec_input_config_t input_config;
ret = csi_codec_init(&codec, 0);
if (ret != CSI_OK) {
printf("csi_codec_init error\n");
return ;
}
codec_input_ch.ring_buf = &input_ring_buffer;
csi_codec_input_open(&codec, &codec_input_ch, 0);
/* input ch config */
csi_codec_input_attach_callback(&codec_input_ch, codec_input_event_cb_fun, NULL);
input_config.bit_width = 16;
input_config.sample_rate = 8000;
input_config.buffer = input_buf;
input_config.buffer_size = INPUT_BUF_SIZE;
input_config.period = 1024;
input_config.mode = CODEC_INPUT_DIFFERENCE;
csi_codec_input_config(&codec_input_ch, &input_config);
csi_codec_input_analog_gain(&codec_input_ch, 0xbf);
csi_codec_input_link_dma(&codec_input_ch, &dma_ch_input_handle);
printf("start sound get\n");
csi_codec_input_start(&codec_input_ch);
while (1)
{
if (cb_input_transfer_flag)
{
csi_codec_input_read_async(&codec_input_ch, sound_buff, 1024);
cb_input_transfer_flag = 0U;
sound_max=0;
int ii=0;
while(ii < 512)
{
if(sound_max < sound_buff)
{
sound_max = sound_buff;
}
ii++;
}
// printf("max sound:%d\n",sound_max);
}
aos_msleep(10);
}
return;
}</code></pre>
<p align="justify" style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="text-justify:inter-ideograph"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">下图是用串口打印输出的实时音量数据,我对着麦克风用不同音量说话,可以看到,实际数据最小在</font>30左右,最大为32767,平均底噪在50左右。</span></span></span></span></span></p>
<p class="imagemiddle" style="text-align: center;"></p>
<p align="center" style="text-align:center"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">图</font>4、串口输出音量</span></span></span></span></p>
<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">5、动感光条实现</font></span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">从串口数据看还不是很直观,我改造了一下显示程序,将音量变化情况实时显示到</font>OLED屏上。</span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">由于大部分时间都是晚上测试这个板子,看着这个</font>OLED屏幕全亮时还是比较刺眼的,为了能看起来更舒服一点,也增加屏幕寿命,减少功耗,我对显示底层程序做了一点改动,将颜色取反了一下,就看起来舒服多了。具体是修改oled.c这个文件里面的画点函数。代码如下。</span></span></span></span></p>
<pre>
<code class="language-cpp">void oled_draw_point(uint8_t r, uint8_t c, uint8_t t)
{
if (t) {
CLR_BIT(g_oled_ram, ((r % 8)));
} else {
SET_BIT(g_oled_ram, (r % 8));
}
// if (t) {
// SET_BIT(g_oled_ram, ((r % 8)));
// } else {
// CLR_BIT(g_oled_ram, (r % 8));
// }
}</code></pre>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">然后设计动感光条代码,思路就是按照套娃方法,先画一个大一点的正色矩形,用于显示边框;然后画一个小一圈的反色矩形做衬底;最后将量化后的音量值作为参数,传入后作为长度,用于画第三层正色矩形,就实现了光条设计。连续调用的时候,随着传入的数值变化,光条长短在变化,就实现了动态光条设计,具体代码如下。</font></span></span></span></span></p>
<pre>
<code class="language-cpp">//num_p = 1...100
void oled_draw_bar(uint8_t num_p)
{
unsigned char i, j, k;
for (i = 54; i < 64; i++) {
for (j = 0; j < 128; j++) {
oled_draw_point(i, j, 0);
}
}
for (i = 55; i < 63; i++) {
for (j = 1; j < 127; j++) {
oled_draw_point(i, j, 1);
}
}
k = num_p * 124 / 100;
for (i = 56; i < 62; i++) {
for (j = 2; j < k; j++) {
oled_draw_point(i, j, 0);
}
}
oled_reflesh();
}</code></pre>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">传入不同数值时,光条动态效果如下。</font></span></span></span></span></p>
<p class="imagemiddle" style="text-align: center;"></p>
<p align="center" style="text-align:center"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">图</font>5、动态光条效果</span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">然后在主函数里面创建一个任务,将动态光条和声音采样关联起来,就可实现随音乐跳动的炫动光条效果了。代码如下。</font></span></span></span></span></p>
<pre>
<code class="language-cpp">/*
* Copyright (C) 2019-2020 Alibaba Group Holding Limited
*/
#include <stdlib.h>
#include <string.h>
#include <aos/aos.h>
#include "aos/cli.h"
#include "main.h"
#include "app_init.h"
#include "oled.h"
#include "snd_get.h"
#define TAG "app"
static void snd_get_task(void *arg);
extern int16_t sound_max;
int main(void)
{
int i=0;
board_yoc_init();
aos_task_new("snd", snd_get_task, NULL, 10 * 1024);
LOGD(TAG, "%s\n", aos_get_app_version());
oled_init();
while (1)
{
aos_msleep(100);
i = sound_max /20;
i++;
if(i>100)i=100;
printf("%d\n",i);
oled_draw_bar( i);
}
return 0;
}
static void snd_get_task(void *arg)
{
cmd_ft_mic_handler(0);
}</code></pre>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">最终的音乐光条效果如下视频。音频采集到的数值比较大,为了在普通音量下效果比较明显。我做了一点简单处理,但是声音很大时光柱会显示饱和。要想更好的效果,可以对原始数据进行一阶高通数字滤波,只截取高频波动部分显示,就能够适应更宽的音量范围。</font></span></span></span></span></p>
<p align="center" style="text-align:center"><iframe allowfullscreen="true" frameborder="0" height="450" src="//player.bilibili.com/player.html?bvid=143411T7eu&page=1" style="background:#eee;margin-bottom:10px;" width="700"></iframe><br />
</p>
<p align="center" style="text-align:center"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">图</font>6、音乐光条</span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">最后,我将声音采集代码移植到我上一篇文章介绍的显示界面中,从下面视频可以看出实时响应效果有些滞后,这个是</font>LVGL的刷新不够造成的。但是在我预期的应用中,影响不大,因为我预计一秒钟以上才上传一次平均值,对实时性要求不高。</span></span></span></span></p>
<p align="center" style="text-align:center"><iframe allowfullscreen="true" frameborder="0" height="450" src="//player.bilibili.com/player.html?bvid=1zR4y1N7ue&page=1" style="background:#eee;margin-bottom:10px;" width="700"></iframe><br />
</p>
<p align="center" style="text-align:center"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">图</font>7、在LVGL中显示音量</span></span></span></span></p>
<p style="text-indent:28.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">本次试验主要是从定性的角度进行声音采集和显示,没有定量校准,如果后面能搞到分贝仪,可以尝试对声音采集部分进行校准,就能比较准确显示音量分贝值了。</font></span></span></span></span></p>
你离项目实现越来越近了。我碰到的,就一步一坚难,是不是上帝给我磨难吧 lugl4313820 发表于 2022-4-17 19:41
你离项目实现越来越近了。我碰到的,就一步一坚难,是不是上帝给我磨难吧
<p>期待后面越来越顺。</p>
<p>加油加油</p>
soso 发表于 2022-4-18 10:11
加油加油
<p>我昨天更新了使用固件,现在下载不了程序了,可能要翻车了。</p>
lugl4313820 发表于 2022-4-18 10:34
我昨天更新了使用固件,现在下载不了程序了,可能要翻车了。
<p>找平头哥支持下:)</p>
<p> </p>
lugl4313820 发表于 2022-4-17 19:41
你离项目实现越来越近了。我碰到的,就一步一坚难,是不是上帝给我磨难吧
<p>好事多磨,多研究肯定能成功。而且你的文章含金量挺高的,给大家帮助也很多。</p>
lugl4313820 发表于 2022-4-18 10:34
我昨天更新了使用固件,现在下载不了程序了,可能要翻车了。
<p>提交工单吧,他们服务还是很到位的</p>
大佬好厉害啊,干活满满的,有很多地方值得学习,我做的产品也是环境监测的,可以多参考大佬的思路了。
页:
[1]