当前位置:   article > 正文

如何用STM32驱动小喇叭或者蜂鸣器来演奏菊次郎的夏天_stm32扬声器如何控制

stm32扬声器如何控制

前言

上一篇文章写到STlink的小插曲,问题已经解决,于是就继续完成了目标,就是驱动一个小喇叭工作,它的原理与蜂鸣器相同,之前提到过原本我是想整个驱动电路的,毕竟功率与声音的大小有关系,后来觉得麻烦就没做,试了一下IO可以驱动起来,就这样直接做了。

准备

首先准备一个小喇叭或者蜂鸣器,这两个都是通过PWM来驱动的,理论上来说PWM的频率决定了声调,占空比决定了振幅,我还没试过输出其他声音,理论上来说都是震动,或许PWM能力有限,只能靠震动频率分辨出音调,音色或许与波形有关,但是想输出一首钢琴曲还是足够的。

使用的板子是STM32F103C8最小板,简单好用,通过STlink烧录代码,使用定时器1来做,用C1口输出PWM,也就是PA8,用CubeMX省点力气,如下图配置很简单:

这里可能要注意一下时钟的问题,我给的定时器时钟是72MHz,可以从时钟树上读出来,72分频也就是1MHz,然后Counter的值和比较值后面会重新赋值,初始化的时候分别给1000和500就可以响了。

此时我们在主函数中加两个函数:

  1. HAL_TIM_Base_Start(&htim1);
  2. HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);

这两句就能够驱动起来定时器和PWM了,这样连接好喇叭的GND和PA8之后烧录代码运行就会响了。

但是响不是目的,我们要输出《菊次郎的夏天》

音乐数组准备

第一步我们要先弄清楚每个音调的频率,直接搜博客上已经有前辈讲过,再次不赘述,也可以直接抄我的数组:

  1. uint16_t cn_music_3[28] = {
  2. 956,851,758,715,637,568,506,
  3. 477,425,379,358,318,284,253,
  4. 239,212,189,179,159,142,126,
  5. 119,106,94,89,79,71,63};

说明一下这里一共28个值,分别是在刚才配置情况下的音调对应的频率。也就是说当我们的定时器频率是1MHz的时候,Counter的值是956时震动的音调接近do,这里并不是C调,主要是因为频率太低声音很小就没有了,所以我就往高频方向移了几个八度。向后Counter的数值越来越小,频率越来越高,我也没有写升调,好像用不到,读者拿计算器一按基本上就能发现规律。

第二步,找一个谱子,我虽然也钢琴入了门,但是太不熟练了就找了一个按数字写的,然后到网上找一个曲谱转蜂鸣器的软件(这里可以自己慢慢算,但是实在太慢,还是使用软件效率高一些,或者直接抄我的数组也可以)。

软件界面长这样:

在右边按对应的音调,然后转换就能出数组,我按照谱子转换了一部分,同时进行了一定的修正,如下:

  1. uint8_t music_3[] = {
  2. 6,3, 13,3, 16,3, 13,3, 4,3,
  3. 11,3, 14,3, 11,3, 5,3, 12,3,
  4. 15,3, 12,3, 11,3, 15,3, 21,3,
  5. 15,3, 6,3, 13,3, 16,3, 13,3,
  6. 4,3,11,3, 14,3, 11,3, 5,3,
  7. 12,3,15,3, 12,3, 11,3, 15,3,
  8. 25,4, 31,4, 32,4, 33,4,32,3,
  9. 31,4, 31,4, 16,3, 13,3,4,3,
  10. 11,3, 25,4, 31,4, 32,4,33,4,
  11. 32,3, 31,4, 32,5, 33,3,
  12. 33,2, 25,4, 31,4, 32,4, 33,4,
  13. 32,3, 31,4, 31,4, 16,3, 13,3,
  14. 4,3, 11,3, 25,4, 31,4, 32,4,
  15. 33,4, 32,3, 31,4, 32,3, 35,3,
  16. 33,2, 33,3, 34,3, 35,3, 35,4,
  17. 35,5, 35,3, 35,3, 33,4,
  18. 31,4, 14,3, 33,4, 34,4, 35,3,
  19. 35,4, 35,5, 35,3, 35,3,
  20. 33,4, 31,4,16,3, 31,4, 32,4,
  21. 33,3, 33,4,33,5, 33,3,
  22. 33,3, 36,3,33,3, 31,3, 32,2,
  23. 5,3, 12,3,25,4, 31,4, 32,4,
  24. 33,4, 32,3,31,4, 31,4, 16,3,
  25. 13,3, 4,3,11,3, 25,4, 31,4,
  26. 32,4, 33,4,32,3, 31,4, 32,5,
  27. 33,3,33,2, 25,4, 31,4,
  28. 32,4, 33,4,32,3, 31,4, 31,4,
  29. 16,3, 13,3,4,3, 11,3, 25,4,
  30. 31,4, 32,4,33,4, 32,3, 31,4,
  31. 32,5, 35,3, 33,2, 33,3,
  32. 34,3, 35,3,35,4, 35,5,
  33. 35,3, 35,3,33,4, 31,4, 14,3,
  34. 33,4, 34,4,35,3, 35,4, 35,5,
  35. 35,3, 35,3, 33,4, 31,4,
  36. 16,3, 31,4,32,4, 33,3, 33,4,
  37. 33,5, 33,3, 33,3, 11,3,
  38. 33,4, 32,4,31,4, 26,4, 31,2,
  39. 31,2, 23,3,16,3, 13,3,
  40. };

转换完成后格式基本上跟上面一样,但是我作了略微修改,第一个数是音调,相当于十位是所在的八度(没有学过乐理大家将就一下我的措辞,理解就好,这里的意思是说21比11高一个八度),个位是音调取值1-7,然后第二个数是与拍相关的,数字越大拍越短,这里不会出现5,但是限于软件做不出来连音,我就自己改了一些5出来,配合下面的数组使用:

uint16_t delay_1[4] = {420,180,60,300},delay_2[4] = {60,60,60,60};

这个数组的含义就是延时时间,也就是每个音持续的时间和它响完之后静音的时间,其实静音时间都是60ms,然后将上面数组的数字减去2对应的delay_1数组中的值就是延时时间,单位ms,比如3-2=1,那就是这个音持续180ms。

然后由于我只有一个小喇叭,就只能输出双手中的高音,将低音覆盖掉。

主函数

有了上面的数组之后,加上主函数就能跑了:

  1. int main(void)
  2. {
  3. /* USER CODE BEGIN 1 */
  4. uint16_t i = 0;
  5. uint16_t len = sizeof(music_3) / sizeof(music_3[0]); //放数组长度
  6. uint8_t x;
  7. /* USER CODE END 1 */
  8. /* MCU Configuration--------------------------------------------------------*/
  9. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  10. HAL_Init();
  11. /* USER CODE BEGIN Init */
  12. /* USER CODE END Init */
  13. /* Configure the system clock */
  14. SystemClock_Config();
  15. /* USER CODE BEGIN SysInit */
  16. /* USER CODE END SysInit */
  17. /* Initialize all configured peripherals */
  18. MX_GPIO_Init();
  19. MX_TIM1_Init();
  20. /* USER CODE BEGIN 2 */
  21. HAL_TIM_Base_Start(&htim1);
  22. HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
  23. /* USER CODE END 2 */
  24. /* Infinite loop */
  25. /* USER CODE BEGIN WHILE */
  26. while (1)
  27. {
  28. /* USER CODE END WHILE */
  29. /* USER CODE BEGIN 3 */
  30. x = (music_3[i] / 10)*7 + music_3[i] % 10 - 1;
  31. __HAL_TIM_SET_PRESCALER(&htim1,cn_music_3[x]);
  32. __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,cn_music_3[x]-1);
  33. i++;
  34. i %= len;
  35. HAL_Delay(delay_1[music_3[i]-2]);
  36. __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,0);
  37. HAL_Delay(delay_2[music_3[i]-2]);
  38. i++;
  39. i %= len;
  40. }
  41. /* USER CODE END 3 */
  42. }

这里补充一下占空比,我为了图省事直接用Counter中的数值减去1作为比较值,小喇叭是可以正常工作(而且理论上已经做到了最大的响度了,或者还可以继续调定时器高频率就能等效调高占空比,但是其他数据也要跟着改变),就是不知道蜂鸣器行不行,不行的话只需要将它除2就行,就能做出来接近50占空比的方波了。

代码为什么这样写,相信读者理解了上面的内容就懂了,然后我们跑一下代码就能听到小喇叭放出音乐啦!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/835933
推荐阅读
相关标签
  

闽ICP备14008679号