欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

STM32 f103搭配LM386声音传感器实现简单音乐识别

程序员文章站 2022-09-04 22:23:18
STM32 f103搭配LM386声音传感器实现简单音乐识别 1.前言 2019年12月初,有一个中国机器人技能大赛中的双足机器人比赛项目,意思是机器人识别音乐跳对应节奏的舞蹈,五首音乐随机抽三首歌曲,音乐停,机器人停。 新比赛,新项目,难度自然有,坑也不少。希望这篇文章能给大家带来一点帮助。废话不 ......

 

stm32 f103搭配lm386声音传感器实现简单音乐识别

1.前言

     2019年12月初,有一个中国机器人技能大赛中的双足机器人比赛项目,意思是机器人识别音乐跳对应节奏的舞蹈,五首音乐随机抽三首歌曲,音乐停,机器人停。

     新比赛,新项目,难度自然有,坑也不少。希望这篇文章能给大家带来一点帮助。废话不多说,进入正题。

2.效果

(健康歌)每100ms采样一次,歌曲前5秒内共测50次数据,重复12组STM32 f103搭配LM386声音传感器实现简单音乐识别

(卡路里) 重复7组STM32 f103搭配LM386声音传感器实现简单音乐识别

       可以看出一首歌经过多次测值,其采样值数组呈现出有规律的特征;不同的歌曲的特征也有较好的区分度。达到了区分歌曲的效果。下面讲讲具体实现步骤。

3.思路

  1. 做什么:识别不同音乐,识别声音有无。
  2. 怎么做:a.利用传感器判断出音乐或声音(网上资料极少);   b.利用手机app听歌识曲,返回对应值(app感觉太难) ;    c.检测到声音就随机跳(下策,保命方案);    d.遥控(作弊);   e.人在旁边说出歌曲有关的词语,语音模块识别(干扰大)
  3. 我的选择:a+c
  4. 技术路线STM32 f103搭配LM386声音传感器实现简单音乐识别

4.硬件

      找到一块具有模拟量输出功能的声音传感器模块,我用的是下面这块,感觉不错,其他的没尝试过。将f103芯片的a1脚与模块的aout引脚相连(奇怪的是我与dout相连也会得到和aout差不多的模拟量值,很迷,有大佬懂的话麻烦指出一下问题所在)。

STM32 f103搭配LM386声音传感器实现简单音乐识别

 

5.软件

利用正点原子的adc.c文件来处理模拟量值,并最终返回给get_adc_average()函数

 
 
 
x
 
 
 
 
1
//初始化adc
2
//这里我们仅以规则通道为例
3
//我们默认将开启通道0~3
4
void  adc_init(void)
5
{ 
6
    adc_inittypedef adc_initstructure; 
7
gpio_inittypedef gpio_initstructure;
8
    //使能adc1通道时钟
9
rcc_apb2periphclockcmd(rcc_apb2periph_gpioa |rcc_apb2periph_adc1, enable ); 
10
rcc_adcclkconfig(rcc_pclk2_div6);//设置adc分频因子6 72m/6=12,adc最大时间不能超过14m
11
    //pa1 作为模拟通道输入引脚                         
12
gpio_initstructure.gpio_pin = gpio_pin_1;
13
gpio_initstructure.gpio_mode = gpio_mode_ain;//模拟输入引脚
14
gpio_init(gpioa, &gpio_initstructure);
15
16
adc_deinit(adc1);  //复位adc1 
17
18
adc_initstructure.adc_mode = adc_mode_independent;
19
    //adc工作模式:adc1和adc2工作在独立模式
20
adc_initstructure.adc_scanconvmode = disable;//模数转换工作在单通道模式
21
adc_initstructure.adc_continuousconvmode = disable;//模数转换工作在单次转换模式
22
adc_initstructure.adc_externaltrigconv = adc_externaltrigconv_none;
23
    //转换由软件而不是外部触发启动
24
adc_initstructure.adc_dataalign = adc_dataalign_right;//adc数据右对齐
25
adc_initstructure.adc_nbrofchannel = 1;//顺序进行规则转换的adc通道的数目
26
adc_init(adc1, &adc_initstructure);
27
    //根据adc_initstruct中指定的参数初始化外设adcx的寄存器   
28
29
  
30
adc_cmd(adc1, enable);//使能指定的adc1
31

32
adc_resetcalibration(adc1);//使能复位校准  
33

34
while(adc_getresetcalibrationstatus(adc1));//等待复位校准结束
35

36
adc_startcalibration(adc1); //开启ad校准
37

38
while(adc_getcalibrationstatus(adc1)); //等待校准结束
39

40
    //adc_softwarestartconvcmd(adc1, enable);//使能指定的adc1的软件转换启动功能
41
}
42
43
//获得adc值
44
//ch:通道值 0~3
45
u16 get_adc(u8 ch)   
46
{
47
  //设置指定adc的规则组通道,一个序列,采样时间
48
adc_regularchannelconfig(adc1, ch, 1, adc_sampletime_239cycles5 );
49
    //adc1,adc通道,采样时间为239.5周期      
50
  
51
adc_softwarestartconvcmd(adc1, enable);//使能指定的adc1的软件转换启动功能
52

53
while(!adc_getflagstatus(adc1, adc_flag_eoc ));//等待转换结束
54
55
return adc_getconversionvalue(adc1);//返回最近一次adc1规则组的转换结果
56
}
57
58
u16 get_adc_average(u8 ch,u8 times)
59
{
60
u32 temp_val=0;
61
u8 t;
62
for(t=0;t<times;t++)
63
{
64
temp_val+=get_adc(ch);
65
delay_ms(5);
66
}
67
return temp_val/times;
68
}  
 
 

      将get_adc_average()拿到的值通过串口输出在电脑屏幕上,适当调整其数值范围,刷新时间间隔。我在代码中就进行了(4093-adcx),(delay_ms(100))相关处理。

 
 
 
xxxxxxxxxx
18
 
 
 
 
1
while(1)
2
{
3
 printf("\r\n");
4
 for(i=0;;i++) 
5
        {
6
  for(j=0;j<50;j++)
7
     {
8
                  adcx=get_adc_average(adc_channel_1,10);
9
                  printf("%-4d \r",4093-adcx);                
10
                  delay_ms(100);
11
      }
12
             printf("\r\n");
13
             delay_ms(1500);
14
             delay_ms(1500);
15
     }
16
}
17
18
 
 

判断歌曲就更简单了,把采样值存入数组,写一个条件语句判断数组的特征就好了,如下:

 
 
 
xxxxxxxxxx
35
 
 
 
 
1
u8 check_song(void)
2
{
3
u16 adcx,adc[35]={0};
4
u8 i,flag=0;
5
printf("\r\n");
6
for(i=0;i<35;i++)//存储数据
7
   {
8
adcx=currentadc();
9
adc[i]=adcx;
10
if (adc[i]>300)
11
   flag++;
12
printf("%-4d \r", adc[i]);
13
delay_ms(100);
14
15
   }
16

17
18
 if(flag>32) 
19
           {
20
        printf("flag%d\r",flag);
21
        return 0;//太极拳
22
   }
23
 else
24
   {
25
        printf("flag%d\r",flag);
26
        
27
if((adc[23]<5&&adc[24]<5)
28
 ||(adc[24]<5&&adc[25]<5)
29
 ||(adc[25]<5&&adc[26]<5)
30
 ||(adc[26]<5&&adc[27]<5)
31
 ||(adc[27]<5&&adc[28]<5))
32
   return 1;//健康歌
33
   else return 2;//翻跟头
34
   }
35
}
 
 

6.总结

a.未知是最大的恐惧,行动是最好的解药

      一看到比赛项目的时候,卧槽,感觉很难,果然网上一查,什么资料也没有。。绝望,想放弃。。比赛前半个月,老师开始问进度了,很慌,啥也没有。但不好意思空手去,于是和队友总结出上面几套方案,发现有个保命方案,心里稍微有点底,开始去探索更好的方法。最后搞出来声音的adc采集,其实现在看看代码,实在是简单,惭愧惭愧。其实比赛现场能真正识别出音乐的不超过10个(共30个队伍),我难人亦难,但我只要去做,山重水复疑无路,柳暗花明又一村。这已超过了不少的人,最重要的是战胜了自己。一定要去做,用心做!

b.做项目就跟取西经样,人生何尝不是

      准备过程中是不可能一帆风顺的,一天一个小自闭,三天一个大自闭,烧板子查不出问题,断结构重新打印,破代码运行不出效果,软件崩溃文件没保存......简直怀疑人生。。一般遇到这时候,放下手中的工作,跑个步,洗个澡,吃个饭,归来还是少年。做人嘛,最重要的就是心态好啦。

c.持续学习,模仿优秀的人

      现阶段自身的能力还不足以输出很多很好的内容。模仿大佬,总结经验是比较好的成长路线。慢慢地就会有自己的风格了。加油!