sipower 发表于 2022-4-17 16:34

【平头哥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>&ldquo;我爱下载</span></span><span style="font-size:14.0000pt"><span style="font-family:黑体"><font face="黑体">&rdquo;同学的《麦克风录音测试》文章,整明白声音采集原理后开始动手的,原贴链接如下。</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&amp;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&amp;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 &lt;stdlib.h&gt;
#include &lt;aos/aos.h&gt;

#include "board_config.h"
#include "drv/codec.h"
#include "drv/dma.h"
#include &lt;drv/ringbuffer.h&gt;
#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(&amp;codec, 0);

    if (ret != CSI_OK) {
      printf("csi_codec_init error\n");
      return ;
    }

    codec_input_ch.ring_buf = &amp;input_ring_buffer;
    csi_codec_input_open(&amp;codec, &amp;codec_input_ch, 0);
    /* input ch config */
    csi_codec_input_attach_callback(&amp;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(&amp;codec_input_ch, &amp;input_config);
    csi_codec_input_analog_gain(&amp;codec_input_ch, 0xbf);
    csi_codec_input_link_dma(&amp;codec_input_ch, &amp;dma_ch_input_handle);

    printf("start sound get\n");
    csi_codec_input_start(&amp;codec_input_ch);

    while (1)
        {
                if (cb_input_transfer_flag)
                {
                        csi_codec_input_read_async(&amp;codec_input_ch, sound_buff, 1024);
                        cb_input_transfer_flag = 0U;
                       
                        sound_max=0;
                        int ii=0;
                        while(ii &lt; 512)
                        {
                                if(sound_max &lt; 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 &lt; 64; i++) {
      for (j = 0; j &lt; 128; j++) {
            oled_draw_point(i, j, 0);
      }
    }
        for (i = 55; i &lt; 63; i++) {
      for (j = 1; j &lt; 127; j++) {
            oled_draw_point(i, j, 1);
      }
    }
        k = num_p * 124 / 100;
        for (i = 56; i &lt; 62; i++) {
      for (j = 2; j &lt; 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 &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;aos/aos.h&gt;
#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&gt;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&amp;page=1" style="background:#eee;margin-bottom:10px;" width="700"></iframe><br />
&nbsp;</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&amp;page=1" style="background:#eee;margin-bottom:10px;" width="700"></iframe><br />
&nbsp;</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

你离项目实现越来越近了。我碰到的,就一步一坚难,是不是上帝给我磨难吧

soso 发表于 2022-4-18 10:11

lugl4313820 发表于 2022-4-17 19:41
你离项目实现越来越近了。我碰到的,就一步一坚难,是不是上帝给我磨难吧

<p>期待后面越来越顺。</p>

soso 发表于 2022-4-18 10:11

<p>加油加油</p>

lugl4313820 发表于 2022-4-18 10:34

soso 发表于 2022-4-18 10:11
加油加油

<p>我昨天更新了使用固件,现在下载不了程序了,可能要翻车了。</p>

soso 发表于 2022-4-18 10:58

lugl4313820 发表于 2022-4-18 10:34
我昨天更新了使用固件,现在下载不了程序了,可能要翻车了。

<p>找平头哥支持下:)</p>

<p>&nbsp;</p>

sipower 发表于 2022-4-18 12:08

lugl4313820 发表于 2022-4-17 19:41
你离项目实现越来越近了。我碰到的,就一步一坚难,是不是上帝给我磨难吧

<p>好事多磨,多研究肯定能成功。而且你的文章含金量挺高的,给大家帮助也很多。</p>

sipower 发表于 2022-4-18 12:10

lugl4313820 发表于 2022-4-18 10:34
我昨天更新了使用固件,现在下载不了程序了,可能要翻车了。

<p>提交工单吧,他们服务还是很到位的</p>

yaoquan5201314 发表于 2022-4-18 22:44

大佬好厉害啊,干活满满的,有很多地方值得学习,我做的产品也是环境监测的,可以多参考大佬的思路了。
页: [1]
查看完整版本: 【平头哥RVB2601创意应用开发】环境监测终端04-声音采集和动感光条显示