当前位置:   article > 正文

STM32简易音乐播放器(HAL库)_stm32播放音乐

stm32播放音乐

一、设计描述

        本设计以STM32MP157A单片机为核心控制器,加上其他的模块一起组成基于单片机的音乐盒的整个系统,通过不同频率的PWM使蜂鸣器播放音乐,通过按键中断实现歌曲切换,音量调节,定时器中断实现播放速度调节,LED灯也会随着音乐而闪烁。

        硬件:STM32MP157A

        软件:STM32CUBEIDE

音乐盒的功能:

1、能稳定的播放出音乐,满足使用者对音乐盒的需求。

2、具有开始和暂停的功能,按下暂停键音乐会停止播放,再按下开始,音乐会接着播放。

3、可以通过按下切换键播放下一首歌曲。

4、可以通过按下变速键,实现歌曲由1倍数-1.2倍数-1.5倍数-2倍数-0.8倍数-0.6倍数-1倍数的切换。

5、可以通过按下音量键使音量逐渐变大,到达阈值之后音量变为0实现静音,再按又会逐渐增大。

6、led会随着歌曲的音调而变化。

二、基本配置信息

        通常情况可以采用HAL_Delay()来实现一个音的持续时间,我们将其换成定时器,便于控制。再就是PWM控制蜂鸣器,我们需要设置对应的高中低音。

        定时器:使用TIM2配置出一个0.1s的中断,我们将一个半拍按0.5秒算,这样我们只需要改变   对tim2中断的计数来改变播放速度。

        PWM蜂鸣器:我们先了解一个公式 || (  (PSC+1)/CLK ) * ( ARR+1 ) = 1 / f   ||  f(频率)

        clk:系统时钟(64MHZ)(STM32MP157A)我们在程序中会更改ARR来改变频率,所以我们需要事先确定一个合适的PSC。 频率:一秒执行多少次。

我们取 1/f 中 取中音1频率  1/523.3 = 0.00191094974202178482705904834703

很长一串小数,可能还没算完,那我们可以取小数点后五位数据。我们以 0.00001为基础也就是让

(PSC+1)/CLK )  = 0.00001  已知clk = 64*10^6   得出PSC + 1 = 640

那么ARR是用于干什么的呢。1/523.3 就约等于 0.00001 *( ARR+1 ) 那么 ARR+1就等于191。

总结一下:我们通过计算得出一个基数,PSC配置为 640 - 1 ,明显ARR在最初时没有实际效果,因为音频不同相应的ARR也不同(这里简易 ARR = 999,不建议设置太大)

                                                        音乐盒 架构图

三、STM32CUBEIDE配置

1、定时器--100ms

2、PWM配置(蜂鸣器 -- PB6)

3、按键极LED

4、NVIC

四、程序编写

1. 基础变量

        因为有许多中断,所以将在stm32mp1xx_it.c  和 main.c 之间交换信息。

stm32mp1xx_it.c 基础变量

  1. int time_100ms_cnt = 0; //0.1s计数器
  2. int Beat_speed = 5; //节拍速度,代表半个节拍需要多少个0.1s
  3. int Beat_speed_n = 0; //实际执行的节拍数
  4. int Beat_num = 2; //这个一个音需要多少个 半拍
  5. int flag = 0; //当其等于 1 时,表示一个音结束
  6. int EN = 0; //使能信号,用于开启整个音乐盒
  7. int list = 0; //音乐列表
  8. int list_max = 0; //音乐总数
  9. int Low_volume = 5; //音量大小
  10. #define Low_volume_cnt 3 //音量大小增加数

main.c基础变量

  1. extern int time_100ms_cnt ; //0.1s计数器
  2. extern int Beat_speed ; //节拍速度,代表半个节拍需要多少个0.1s
  3. extern int Beat_speed_n ; //实际执行的节拍数
  4. extern int Beat_num ; //这个一个音需要多少个 半拍
  5. extern int flag ; //当其等于 1 时,表示一个音结束
  6. extern int EN ; //使能信号,用于开启整个音乐盒
  7. extern int list ; //音乐列表
  8. extern int list_max ; //音乐总数
  9. extern int Low_volume ; //音量大小

2. LED随音乐跳动

  1. //将LED设置成全灭
  2. void LED_RESET(){
  3. HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_RESET);
  4. HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
  5. HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11|GPIO_PIN_10, GPIO_PIN_RESET);
  6. }
  7. void LED(int i){
  8. if(i >= 1) HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_SET);
  9. if(i >= 2) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);
  10. if(i >= 3) HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11,GPIO_PIN_SET);
  11. if(i >= 4) HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);
  12. }
  13. //随音节输入,改变LED状�??
  14. void LED_BEEP(int i){
  15. LED_RESET();
  16. switch(i){
  17. case 1:{
  18. LED(1);
  19. break;
  20. }
  21. case 2:{
  22. LED(1);
  23. break;
  24. }
  25. case 3:{
  26. LED(2);
  27. break;
  28. }
  29. case 4:{
  30. LED(2);
  31. break;
  32. }
  33. case 5:{
  34. LED(3);
  35. break;
  36. }
  37. case 6:{
  38. LED(3);
  39. break;
  40. }
  41. case 7:{
  42. LED(4);
  43. break;
  44. }
  45. default:{
  46. LED_RESET();
  47. break;
  48. }
  49. }
  50. }

3. 配置低中高音

  1. int tone[3][8];
  2. //初始化高中低音频率
  3. void tone_init(){
  4. tone[1][0] = 0; //不执行音乐
  5. tone[1][1] = 191;
  6. tone[1][2] = 170;
  7. tone[1][3] = 151;
  8. tone[1][4] = 143;
  9. tone[1][5] = 127;
  10. tone[1][6] = 113;
  11. tone[1][7] = 101;
  12. // 低音 (Low)
  13. for (int i = 0; i < 8; i++) {
  14. tone[0][i] = tone[1][i] * 2; // 只是低音 近似的值
  15. }
  16. // 高音 (High)
  17. for (int i = 0; i < 8; i++) {
  18. tone[2][i] = tone[1][i] / 2; // 只是高音 近似的值
  19. }
  20. }

4.乐谱结构体

  1. #define MAX_unit_num 200 //�??大乐谱数�??
  2. //创建结构体保存乐�??
  3. struct music_unit{
  4. char name[50]; //乐谱名称
  5. int unit[MAX_unit_num]; //发什么音
  6. int unit_HL[MAX_unit_num]; //发高音或者其�??
  7. int time[MAX_unit_num]; //发音时间
  8. //int time_4[MAX_unit_num]; //判断是否�??1/4�??
  9. int num; //记录有多少个
  10. }music[25];

5. 编写乐谱

  1. //创建乐谱 返回有多少首音乐
  2. int music_init(){
  3. int cnt = 0;
  4. //第一首音�?? 生日快乐
  5. strcpy(music[0].name, "生日快乐"); // 使用strcpy复制字符�?? 给音乐命�??
  6. int music0_unit[29] = {0,0, 5,5,6,5,1,7, 5,5,6,5,2,1,
  7. 5,5,6,3,1,7, 6,4,4,3,1,2,1,
  8. 0,0}; //基础乐谱
  9. int music0_time[29] = {1,1, 1,1,2,2,2,3, 1,1,2,2,2,3,
  10. 2,2,2,2,2,2, 2,2,2,2,2,2,3,
  11. 1,1}; //乐谱节拍
  12. music[0].num = 29; //乐谱总数
  13. int music0_unit_HL[29] = {1,1,
  14. 0,0,0,0,1,0, 0,0,0,0,1,1,
  15. 0,0,1,1,1,0, 0,1,1,1,1,1,1,
  16. 1,1}; //乐谱全为中音
  17. //第二首音�?? �??闪一闪亮晶晶
  18. cnt++;
  19. strcpy(music[1].name, "�??闪一闪亮晶晶"); // 使用strcpy复制字符�?? 给音乐命�??
  20. int music1_unit[44] = {0,
  21. 1,1,5,5,6,6,5, 4,4,3,3,2,2,1,
  22. 5,5,4,4,3,3,2, 5,5,4,4,3,3,2,
  23. 1,1,5,5,6,6,5, 4,4,3,3,2,2,1,
  24. 0}; //基础乐谱
  25. int music1_time[44] = {2,
  26. 2,2,2,2,2,2,3, 2,2,2,2,2,2,3,
  27. 2,2,2,2,2,2,3, 2,2,2,2,2,2,3,
  28. 2,2,2,2,2,2,3, 2,2,2,2,2,2,3,
  29. 2}; //乐谱节拍
  30. int music1_unit_HL[44] =
  31. {1,
  32. 1,1,1,1,1,1,1, 1,1,1,1,1,1,1,
  33. 1,1,1,1,1,1,1, 1,1,1,1,1,1,1,
  34. 1,1,1,1,1,1,1, 1,1,1,1,1,1,1,
  35. 1}; //乐谱全为中音
  36. music[1].num = 44; //乐谱总数
  37. //第三首音�?? 两只老虎
  38. cnt++;
  39. strcpy(music[2].name, "两只老虎"); // 使用strcpy复制字符�?? 给音乐命�??
  40. int music2_unit[38] = {0,
  41. 1,2,3,1, 1,2,3,1, 3,4,5,5, 3,4,5,5,
  42. 5,6,5,4, 3,1,5,6, 5,4,3,1, 1,5,1,1,
  43. 1,5,1,1, 0}; //基础乐谱
  44. int music2_time[38] = {2,
  45. 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
  46. 0,0,0,0, 1,1,0,0, 0,0,1,1, 1,1,1,2,
  47. 1,1,1,2, 2}; //乐谱节拍
  48. int music2_unit_HL[38] =
  49. {1,
  50. 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
  51. 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,0,1,1,
  52. 1,0,1,1, 1}; //乐谱�?? 中音
  53. music[2].num = 38; //乐谱总数
  54. //第四首音�?? 青花瓷片�??
  55. cnt++;
  56. strcpy(music[3].name, "青花瓷片选"); // 使用strcpy复制字符�?? 给音乐命�??
  57. int music3_unit[100] = {0,0,0,0, 0,5,5,3, 2,3,6,2, 3,5,3,2, 2,5,5,3,
  58. 2,3,5,2, 3,5,2,1, 1,1,2,3, 5,6,5,4, 5,3,3,2,
  59. 2,2,1,2, 1,1,2,1, 2,3,5,3, 3,3,5,5, 3,2,3,6,
  60. 2,3,5,3, 2,2,5,5, 3,2,3,5, 2,3,5,2, 1,1,1,2,
  61. 3,5,6,5, 4,5,3,3, 2,2,5,3, 2,2,2,1, 1,0,0,0}; //基础乐谱
  62. int music3_time[100] = {0,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,2, 0,0,0,0,
  63. 0,0,1,0, 0,0,0,2, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  64. 2,0,0,0, 0,0,0,0, 0,1,0,0, 2,0,0,0, 0,0,0,1,
  65. 0,0,0,0, 2,0,0,0, 0,0,0,1, 0,0,0,0, 2,0,0,0,
  66. 0,0,0,0, 0,0,0,0, 0,2,0,1, 0,0,0,1, 2,1,1,1}; //乐谱节拍
  67. for(int i =0;i<100;i++)
  68. music3_time[i] = music3_time[i]+1;
  69. int music3_unit_HL[100] =
  70. { 1,1,1,1, 1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1,
  71. 1,1,0,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
  72. 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,0,
  73. 1,1,1,1, 1,1,1,1, 1,1,1,0, 1,1,1,1, 1,1,1,1,
  74. 1,1,1,1, 1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1}; //乐谱�?? 中音
  75. music[3].num = 100; //乐谱总数
  76. for (int i = 0; i < MAX_unit_num; i++) {
  77. //将乐谱保存进结构�??
  78. if(i<music[0].num){//确保数据正确
  79. music[0].unit[i] =music0_unit[i];
  80. music[0].unit_HL[i] =music0_unit_HL[i];
  81. music[0].time[i] =music0_time[i];
  82. }
  83. //将乐谱保存进结构�??
  84. if(i<music[1].num){//确保数据正确
  85. music[1].unit[i] =music1_unit[i];
  86. music[1].unit_HL[i] =music1_unit_HL[i];
  87. music[1].time[i] =music1_time[i];
  88. }
  89. //将乐谱保存进结构�??
  90. if(i<music[2].num){//确保数据正确
  91. music[2].unit[i] =music2_unit[i];
  92. music[2].unit_HL[i] =music2_unit_HL[i];
  93. music[2].time[i] =music2_time[i];
  94. }
  95. //将乐谱保存进结构�??
  96. if(i<music[3].num){//确保数据正确
  97. music[3].unit[i] =music3_unit[i];
  98. music[3].unit_HL[i] =music3_unit_HL[i];
  99. music[3].time[i] =music3_time[i];
  100. }
  101. }
  102. return cnt;
  103. }

6. 音乐实现函数

  1. //播放音乐 N首音乐 音量 X 0 - 10
  2. void play_music(int n, int x){
  3. static int ni = 0; //用于判断 是否换了音乐
  4. static int cnt = 0; //记录播放到哪一个 音节
  5. if(ni != n ){//如果音乐换了
  6. ni = n;
  7. cnt = 0;
  8. __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,0);//设置音量
  9. HAL_Delay(1000);//
  10. }
  11. //
  12. int value = tone[music[n].unit_HL[cnt]][music[n].unit[cnt]]; //获取频率
  13. if(flag == 1){ //接受到一个音节结束
  14. flag = 0; //复位
  15. Beat_num = music[n].time[cnt]; //这个音需要多少个半拍
  16. LED_BEEP(music[n].unit[cnt]); //LED随音节变动
  17. if(music[n].time[cnt] == 0){// 后面添加的 1/4
  18. Beat_speed_n = Beat_speed /2;
  19. }
  20. else{//如果没有1/4
  21. Beat_speed_n = Beat_speed;
  22. }
  23. __HAL_TIM_SET_AUTORELOAD(&htim4,value); //自动加载频率
  24. cnt ++; //可进行下一次音节
  25. if(cnt >= music[n].num){ //如果一首音乐播放完毕
  26. cnt = 0;//重新播放
  27. //__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,0);//设置音量
  28. //HAL_Delay(500);//
  29. }
  30. }
  31. //__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,x * (value/100));//设置音量
  32. __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,(value/10)*x);//设置音量
  33. }

7. 全部中断

  1. void EXTI0_IRQHandler(void)
  2. {
  3. /* USER CODE BEGIN EXTI0_IRQn 0 */
  4. if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_0) == 0)//确保数据稳定
  5. {
  6. //每次按下解决 音量�?? Low_volume_cnt
  7. Low_volume = Low_volume + Low_volume_cnt;
  8. if(Low_volume >= 10)
  9. Low_volume = 0;
  10. }
  11. /* USER CODE END EXTI0_IRQn 0 */
  12. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  13. /* USER CODE BEGIN EXTI0_IRQn 1 */
  14. /* USER CODE END EXTI0_IRQn 1 */
  15. }
  16. /**
  17. * @brief This function handles EXTI line1 interrupt.
  18. */
  19. void EXTI1_IRQHandler(void)
  20. {
  21. /* USER CODE BEGIN EXTI1_IRQn 0 */
  22. if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_1) == 0)//确保数据稳定
  23. {
  24. //控制音乐播放的�?�度
  25. static int i = 0;
  26. i++;
  27. //倍数计算公式 1 + (1 - (新的节拍速度 / 原来的节拍�?�度))
  28. switch(i){
  29. case 0:{
  30. Beat_speed = 5; //0.5s半个节拍,正常+�?�度
  31. break;
  32. }
  33. case 1:{
  34. Beat_speed = 4; //1.2倍数
  35. break;
  36. }
  37. case 2:{
  38. Beat_speed = 3; //约等�?? 1.5倍数
  39. break;
  40. }
  41. case 3:{
  42. Beat_speed = 1; //约等�?? 2 倍数
  43. break;
  44. }
  45. case 4:{
  46. Beat_speed = 6; //约等�?? 0.8 倍数
  47. break;
  48. }
  49. case 5:{
  50. Beat_speed = 7; //约等�?? 0.6 倍数
  51. break;
  52. }
  53. default:{
  54. Beat_speed = 5; //0.5s半个节拍,正常�?�度
  55. i=0;
  56. break;
  57. }
  58. }
  59. }
  60. /* USER CODE END EXTI1_IRQn 0 */
  61. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
  62. /* USER CODE BEGIN EXTI1_IRQn 1 */
  63. /* USER CODE END EXTI1_IRQn 1 */
  64. }
  65. /**
  66. * @brief This function handles EXTI line2 interrupt.
  67. */
  68. void EXTI2_IRQHandler(void)
  69. {
  70. /* USER CODE BEGIN EXTI2_IRQn 0 */
  71. //按下�??次音乐进入下�??�??
  72. if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_2) == 0)//确保数据稳定
  73. {
  74. list++;
  75. if(list > list_max){
  76. list = 0;
  77. }
  78. }
  79. /* USER CODE END EXTI2_IRQn 0 */
  80. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
  81. /* USER CODE BEGIN EXTI2_IRQn 1 */
  82. /* USER CODE END EXTI2_IRQn 1 */
  83. }
  84. /**
  85. * @brief This function handles TIM2 global interrupt.
  86. */
  87. void TIM2_IRQHandler(void)
  88. {
  89. /* USER CODE BEGIN TIM2_IRQn 0 */
  90. if(EN == 1)
  91. time_100ms_cnt++;
  92. else
  93. time_100ms_cnt = time_100ms_cnt; //其余状�?�不计数
  94. if(time_100ms_cnt >= Beat_speed_n * Beat_num){ //这个音节结束
  95. time_100ms_cnt = 0;
  96. flag = 1; //发�?�音节结束信�??
  97. }
  98. /* USER CODE END TIM2_IRQn 0 */
  99. HAL_TIM_IRQHandler(&htim2);
  100. /* USER CODE BEGIN TIM2_IRQn 1 */
  101. /* USER CODE END TIM2_IRQn 1 */
  102. }
  103. /**
  104. * @brief This function handles EXTI line9 interrupt.
  105. */
  106. void EXTI9_IRQHandler(void)
  107. {
  108. /* USER CODE BEGIN EXTI9_IRQn 0 */
  109. if(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_9) == 0)//确保数据稳定
  110. EN = !EN;
  111. /* USER CODE END EXTI9_IRQn 0 */
  112. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
  113. /* USER CODE BEGIN EXTI9_IRQn 1 */
  114. /* USER CODE END EXTI9_IRQn 1 */
  115. }

五、总代码

main.c

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under BSD 3-Clause license,
  13. * the "License"; You may not use this file except in compliance with the
  14. * License. You may obtain a copy of the License at:
  15. * opensource.org/licenses/BSD-3-Clause
  16. *
  17. ******************************************************************************
  18. */
  19. /* USER CODE END Header */
  20. /* Includes ------------------------------------------------------------------*/
  21. #include "main.h"
  22. /* Private includes ----------------------------------------------------------*/
  23. /* USER CODE BEGIN Includes */
  24. /* USER CODE END Includes */
  25. /* Private typedef -----------------------------------------------------------*/
  26. /* USER CODE BEGIN PTD */
  27. #include <string.h> // 引入strcpy函数�?�?的头文件
  28. /* USER CODE END PTD */
  29. /* Private define ------------------------------------------------------------*/
  30. /* USER CODE BEGIN PD */
  31. /* USER CODE END PD */
  32. /* Private macro -------------------------------------------------------------*/
  33. /* USER CODE BEGIN PM */
  34. /* USER CODE END PM */
  35. /* Private variables ---------------------------------------------------------*/
  36. TIM_HandleTypeDef htim2;
  37. TIM_HandleTypeDef htim4;
  38. /* USER CODE BEGIN PV */
  39. /* USER CODE END PV */
  40. /* Private function prototypes -----------------------------------------------*/
  41. void SystemClock_Config(void);
  42. static void MX_GPIO_Init(void);
  43. static void MX_TIM4_Init(void);
  44. static void MX_TIM2_Init(void);
  45. /* USER CODE BEGIN PFP */
  46. /* USER CODE END PFP */
  47. /* Private user code ---------------------------------------------------------*/
  48. /* USER CODE BEGIN 0 */
  49. //将LED设置成全�??
  50. void LED_RESET(){
  51. HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_RESET);
  52. HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
  53. HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11|GPIO_PIN_10, GPIO_PIN_RESET);
  54. }
  55. void LED(int i){
  56. if(i >= 1) HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_SET);
  57. if(i >= 2) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);
  58. if(i >= 3) HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11,GPIO_PIN_SET);
  59. if(i >= 4) HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);
  60. }
  61. //随音节输入,改变LED状�??
  62. void LED_BEEP(int i){
  63. LED_RESET();
  64. switch(i){
  65. case 1:{
  66. LED(1);
  67. break;
  68. }
  69. case 2:{
  70. LED(1);
  71. break;
  72. }
  73. case 3:{
  74. LED(2);
  75. break;
  76. }
  77. case 4:{
  78. LED(2);
  79. break;
  80. }
  81. case 5:{
  82. LED(3);
  83. break;
  84. }
  85. case 6:{
  86. LED(3);
  87. break;
  88. }
  89. case 7:{
  90. LED(4);
  91. break;
  92. }
  93. default:{
  94. LED_RESET();
  95. break;
  96. }
  97. }
  98. }
  99. extern int time_100ms_cnt; //0.1s计数�??
  100. extern int Beat_speed; //节拍速度,代表半个节拍需要多少个0.1s
  101. extern int Beat_speed_n; //实际执行的节�??
  102. extern int Beat_num; //这个�?? �??要多少个 半拍
  103. extern int flag; //当其等于 1 时,表示�??个音结束
  104. extern int EN; //使能信号,用于开启整个音�??
  105. extern int list ; //音乐列表
  106. extern int list_max ; //音乐总数
  107. extern int Low_volume; //音量大小
  108. int tone[3][8];
  109. //初始化高中低�??
  110. void tone_init(){
  111. tone[1][0] = 0; //不执�??
  112. tone[1][1] = 191;
  113. tone[1][2] = 170;
  114. tone[1][3] = 151;
  115. tone[1][4] = 143;
  116. tone[1][5] = 127;
  117. tone[1][6] = 113;
  118. tone[1][7] = 101;
  119. // 低音 (Low)
  120. for (int i = 0; i < 8; i++) {
  121. tone[0][i] = tone[1][i] * 2; // 只是�??个近似的值,实际值可能不�??
  122. }
  123. // 高音 (High)
  124. for (int i = 0; i < 8; i++) {
  125. tone[2][i] = tone[1][i] / 2; // 只是�??个近似的值,实际值可能不�??
  126. }
  127. }
  128. #define MAX_unit_num 200 //�??大乐谱数�??
  129. //创建结构体保存乐�??
  130. struct music_unit{
  131. char name[50]; //乐谱名称
  132. int unit[MAX_unit_num]; //发什么音
  133. int unit_HL[MAX_unit_num]; //发高音或者其�??
  134. int time[MAX_unit_num]; //发音时间
  135. //int time_4[MAX_unit_num]; //判断是否�??1/4�??
  136. int num; //记录有多少个
  137. }music[25];
  138. //创建乐谱 返回有多少首音乐
  139. int music_init(){
  140. int cnt = 0;
  141. //第一首音�?? 生日快乐
  142. strcpy(music[0].name, "生日快乐"); // 使用strcpy复制字符�?? 给音乐命�??
  143. int music0_unit[29] = {0,0, 5,5,6,5,1,7, 5,5,6,5,2,1,
  144. 5,5,6,3,1,7, 6,4,4,3,1,2,1,
  145. 0,0}; //基础乐谱
  146. int music0_time[29] = {1,1, 1,1,2,2,2,3, 1,1,2,2,2,3,
  147. 2,2,2,2,2,2, 2,2,2,2,2,2,3,
  148. 1,1}; //乐谱节拍
  149. music[0].num = 29; //乐谱总数
  150. int music0_unit_HL[29] = {1,1,
  151. 0,0,0,0,1,0, 0,0,0,0,1,1,
  152. 0,0,1,1,1,0, 0,1,1,1,1,1,1,
  153. 1,1}; //乐谱全为中音
  154. //第二首音�?? �??闪一闪亮晶晶
  155. cnt++;
  156. strcpy(music[1].name, "�??闪一闪亮晶晶"); // 使用strcpy复制字符�?? 给音乐命�??
  157. int music1_unit[44] = {0,
  158. 1,1,5,5,6,6,5, 4,4,3,3,2,2,1,
  159. 5,5,4,4,3,3,2, 5,5,4,4,3,3,2,
  160. 1,1,5,5,6,6,5, 4,4,3,3,2,2,1,
  161. 0}; //基础乐谱
  162. int music1_time[44] = {2,
  163. 2,2,2,2,2,2,3, 2,2,2,2,2,2,3,
  164. 2,2,2,2,2,2,3, 2,2,2,2,2,2,3,
  165. 2,2,2,2,2,2,3, 2,2,2,2,2,2,3,
  166. 2}; //乐谱节拍
  167. int music1_unit_HL[44] =
  168. {1,
  169. 1,1,1,1,1,1,1, 1,1,1,1,1,1,1,
  170. 1,1,1,1,1,1,1, 1,1,1,1,1,1,1,
  171. 1,1,1,1,1,1,1, 1,1,1,1,1,1,1,
  172. 1}; //乐谱全为中音
  173. music[1].num = 44; //乐谱总数
  174. //第三首音�?? 两只老虎
  175. cnt++;
  176. strcpy(music[2].name, "两只老虎"); // 使用strcpy复制字符�?? 给音乐命�??
  177. int music2_unit[38] = {0,
  178. 1,2,3,1, 1,2,3,1, 3,4,5,5, 3,4,5,5,
  179. 5,6,5,4, 3,1,5,6, 5,4,3,1, 1,5,1,1,
  180. 1,5,1,1, 0}; //基础乐谱
  181. int music2_time[38] = {2,
  182. 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
  183. 0,0,0,0, 1,1,0,0, 0,0,1,1, 1,1,1,2,
  184. 1,1,1,2, 2}; //乐谱节拍
  185. int music2_unit_HL[38] =
  186. {1,
  187. 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
  188. 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,0,1,1,
  189. 1,0,1,1, 1}; //乐谱�?? 中音
  190. music[2].num = 38; //乐谱总数
  191. //第四首音�?? 青花瓷片�??
  192. cnt++;
  193. strcpy(music[3].name, "青花瓷片选"); // 使用strcpy复制字符�?? 给音乐命�??
  194. int music3_unit[100] = {0,0,0,0, 0,5,5,3, 2,3,6,2, 3,5,3,2, 2,5,5,3,
  195. 2,3,5,2, 3,5,2,1, 1,1,2,3, 5,6,5,4, 5,3,3,2,
  196. 2,2,1,2, 1,1,2,1, 2,3,5,3, 3,3,5,5, 3,2,3,6,
  197. 2,3,5,3, 2,2,5,5, 3,2,3,5, 2,3,5,2, 1,1,1,2,
  198. 3,5,6,5, 4,5,3,3, 2,2,5,3, 2,2,2,1, 1,0,0,0}; //基础乐谱
  199. int music3_time[100] = {0,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,2, 0,0,0,0,
  200. 0,0,1,0, 0,0,0,2, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  201. 2,0,0,0, 0,0,0,0, 0,1,0,0, 2,0,0,0, 0,0,0,1,
  202. 0,0,0,0, 2,0,0,0, 0,0,0,1, 0,0,0,0, 2,0,0,0,
  203. 0,0,0,0, 0,0,0,0, 0,2,0,1, 0,0,0,1, 2,1,1,1}; //乐谱节拍
  204. for(int i =0;i<100;i++)
  205. music3_time[i] = music3_time[i]+1;
  206. int music3_unit_HL[100] =
  207. { 1,1,1,1, 1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1,
  208. 1,1,0,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
  209. 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,0,
  210. 1,1,1,1, 1,1,1,1, 1,1,1,0, 1,1,1,1, 1,1,1,1,
  211. 1,1,1,1, 1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1}; //乐谱�?? 中音
  212. music[3].num = 100; //乐谱总数
  213. for (int i = 0; i < MAX_unit_num; i++) {
  214. //将乐谱保存进结构�??
  215. if(i<music[0].num){//确保数据正确
  216. music[0].unit[i] =music0_unit[i];
  217. music[0].unit_HL[i] =music0_unit_HL[i];
  218. music[0].time[i] =music0_time[i];
  219. }
  220. //将乐谱保存进结构�??
  221. if(i<music[1].num){//确保数据正确
  222. music[1].unit[i] =music1_unit[i];
  223. music[1].unit_HL[i] =music1_unit_HL[i];
  224. music[1].time[i] =music1_time[i];
  225. }
  226. //将乐谱保存进结构�??
  227. if(i<music[2].num){//确保数据正确
  228. music[2].unit[i] =music2_unit[i];
  229. music[2].unit_HL[i] =music2_unit_HL[i];
  230. music[2].time[i] =music2_time[i];
  231. }
  232. //将乐谱保存进结构�??
  233. if(i<music[3].num){//确保数据正确
  234. music[3].unit[i] =music3_unit[i];
  235. music[3].unit_HL[i] =music3_unit_HL[i];
  236. music[3].time[i] =music3_time[i];
  237. }
  238. }
  239. return cnt;
  240. }
  241. //播放�?? N首音�?? 音量�?? X 0 - 100
  242. void play_music(int n, int x){
  243. static int ni = 0; //用于判断 是否换了音乐
  244. static int cnt = 0; //记录播放到哪�??�?? 音节
  245. if(ni != n ){//如果音乐换了
  246. ni = n;
  247. cnt = 0;
  248. __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,0);//设置音量
  249. HAL_Delay(1000);//
  250. }
  251. //
  252. int value = tone[music[n].unit_HL[cnt]][music[n].unit[cnt]]; //获取频率
  253. if(flag == 1){ //接受到一个音节结�??
  254. flag = 0; //复位
  255. Beat_num = music[n].time[cnt]; //这个音需要多少个半拍
  256. LED_BEEP(music[n].unit[cnt]); //LED随音节变动�?�变�??
  257. if(music[n].time[cnt] == 0){//如果�?? 1/4�??
  258. Beat_speed_n = Beat_speed /2;
  259. }
  260. else{//如果没有1/4�??
  261. Beat_speed_n = Beat_speed;
  262. }
  263. //if(value != 0)//如果有频率�?�执行,没有者只更新 时间�??
  264. __HAL_TIM_SET_AUTORELOAD(&htim4,value); //自动加载频率�??
  265. cnt ++; //可进行下�??次音�??
  266. if(cnt >= music[n].num){ //如果�??个音节播放完�??
  267. cnt = 0;//重新播放
  268. //__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,0);//设置音量
  269. //HAL_Delay(500);//
  270. }
  271. }
  272. //__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,x * (value/100));//设置音量
  273. __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,(value/10)*x);//设置音量
  274. }
  275. /* USER CODE END 0 */
  276. /**
  277. * @brief The application entry point.
  278. * @retval int
  279. */
  280. int main(void)
  281. {
  282. /* USER CODE BEGIN 1 */
  283. /* USER CODE END 1 */
  284. /* MCU Configuration--------------------------------------------------------*/
  285. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  286. HAL_Init();
  287. /* USER CODE BEGIN Init */
  288. /* USER CODE END Init */
  289. if(IS_ENGINEERING_BOOT_MODE())
  290. {
  291. /* Configure the system clock */
  292. SystemClock_Config();
  293. }
  294. /* USER CODE BEGIN SysInit */
  295. /* USER CODE END SysInit */
  296. /* Initialize all configured peripherals */
  297. MX_GPIO_Init();
  298. MX_TIM4_Init();
  299. MX_TIM2_Init();
  300. /* USER CODE BEGIN 2 */
  301. tone_init(); //初始化音量频�??
  302. list_max = music_init();//更新乐谱
  303. HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); //�??启PWM
  304. HAL_TIM_Base_Start_IT(&htim2); //�??启定时器�??
  305. /* USER CODE END 2 */
  306. /* Infinite loop */
  307. /* USER CODE BEGIN WHILE */
  308. while (1)
  309. {
  310. /* USER CODE END WHILE */
  311. /* USER CODE BEGIN 3 */
  312. if(EN == 1)//�??启音�??
  313. play_music(list,Low_volume);
  314. else
  315. __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,0);//设置音量
  316. //EN = 1;
  317. //play_music(0,5);
  318. }
  319. /* USER CODE END 3 */
  320. }
  321. /**
  322. * @brief System Clock Configuration
  323. * @retval None
  324. */
  325. void SystemClock_Config(void)
  326. {
  327. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  328. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  329. /** Initializes the RCC Oscillators according to the specified parameters
  330. * in the RCC_OscInitTypeDef structure.
  331. */
  332. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;
  333. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  334. RCC_OscInitStruct.HSICalibrationValue = 16;
  335. RCC_OscInitStruct.HSIDivValue = RCC_HSI_DIV1;
  336. RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  337. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  338. RCC_OscInitStruct.PLL2.PLLState = RCC_PLL_NONE;
  339. RCC_OscInitStruct.PLL3.PLLState = RCC_PLL_NONE;
  340. RCC_OscInitStruct.PLL4.PLLState = RCC_PLL_NONE;
  341. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  342. {
  343. Error_Handler();
  344. }
  345. /** RCC Clock Config
  346. */
  347. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_ACLK
  348. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
  349. |RCC_CLOCKTYPE_PCLK3|RCC_CLOCKTYPE_PCLK4
  350. |RCC_CLOCKTYPE_PCLK5;
  351. RCC_ClkInitStruct.AXISSInit.AXI_Clock = RCC_AXISSOURCE_HSI;
  352. RCC_ClkInitStruct.AXISSInit.AXI_Div = RCC_AXI_DIV1;
  353. RCC_ClkInitStruct.MCUInit.MCU_Clock = RCC_MCUSSOURCE_HSI;
  354. RCC_ClkInitStruct.MCUInit.MCU_Div = RCC_MCU_DIV1;
  355. RCC_ClkInitStruct.APB4_Div = RCC_APB4_DIV1;
  356. RCC_ClkInitStruct.APB5_Div = RCC_APB5_DIV1;
  357. RCC_ClkInitStruct.APB1_Div = RCC_APB1_DIV1;
  358. RCC_ClkInitStruct.APB2_Div = RCC_APB2_DIV1;
  359. RCC_ClkInitStruct.APB3_Div = RCC_APB3_DIV1;
  360. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK)
  361. {
  362. Error_Handler();
  363. }
  364. }
  365. /**
  366. * @brief TIM2 Initialization Function
  367. * @param None
  368. * @retval None
  369. */
  370. static void MX_TIM2_Init(void)
  371. {
  372. /* USER CODE BEGIN TIM2_Init 0 */
  373. /* USER CODE END TIM2_Init 0 */
  374. TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  375. TIM_MasterConfigTypeDef sMasterConfig = {0};
  376. /* USER CODE BEGIN TIM2_Init 1 */
  377. /* USER CODE END TIM2_Init 1 */
  378. htim2.Instance = TIM2;
  379. htim2.Init.Prescaler = 6400-1;
  380. htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  381. htim2.Init.Period = 1000-1;
  382. htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  383. htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  384. if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  385. {
  386. Error_Handler();
  387. }
  388. sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  389. if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  390. {
  391. Error_Handler();
  392. }
  393. sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  394. sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  395. if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  396. {
  397. Error_Handler();
  398. }
  399. /* USER CODE BEGIN TIM2_Init 2 */
  400. /* USER CODE END TIM2_Init 2 */
  401. }
  402. /**
  403. * @brief TIM4 Initialization Function
  404. * @param None
  405. * @retval None
  406. */
  407. static void MX_TIM4_Init(void)
  408. {
  409. /* USER CODE BEGIN TIM4_Init 0 */
  410. /* USER CODE END TIM4_Init 0 */
  411. TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  412. TIM_MasterConfigTypeDef sMasterConfig = {0};
  413. TIM_OC_InitTypeDef sConfigOC = {0};
  414. /* USER CODE BEGIN TIM4_Init 1 */
  415. /* USER CODE END TIM4_Init 1 */
  416. htim4.Instance = TIM4;
  417. htim4.Init.Prescaler = 640-1;
  418. htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  419. htim4.Init.Period = 100-1;
  420. htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  421. htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  422. if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  423. {
  424. Error_Handler();
  425. }
  426. sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  427. if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  428. {
  429. Error_Handler();
  430. }
  431. if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
  432. {
  433. Error_Handler();
  434. }
  435. sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  436. sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  437. if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  438. {
  439. Error_Handler();
  440. }
  441. sConfigOC.OCMode = TIM_OCMODE_PWM1;
  442. sConfigOC.Pulse = 0;
  443. sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  444. sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  445. if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  446. {
  447. Error_Handler();
  448. }
  449. /* USER CODE BEGIN TIM4_Init 2 */
  450. /* USER CODE END TIM4_Init 2 */
  451. HAL_TIM_MspPostInit(&htim4);
  452. }
  453. /**
  454. * @brief GPIO Initialization Function
  455. * @param None
  456. * @retval None
  457. */
  458. static void MX_GPIO_Init(void)
  459. {
  460. GPIO_InitTypeDef GPIO_InitStruct = {0};
  461. /* GPIO Ports Clock Enable */
  462. __HAL_RCC_GPIOF_CLK_ENABLE();
  463. __HAL_RCC_GPIOC_CLK_ENABLE();
  464. __HAL_RCC_GPIOI_CLK_ENABLE();
  465. __HAL_RCC_GPIOG_CLK_ENABLE();
  466. __HAL_RCC_GPIOE_CLK_ENABLE();
  467. __HAL_RCC_GPIOB_CLK_ENABLE();
  468. /*Configure GPIO pin Output Level */
  469. HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1|GPIO_PIN_6, GPIO_PIN_RESET);
  470. /*Configure GPIO pin Output Level */
  471. HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
  472. /*Configure GPIO pin Output Level */
  473. HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11|GPIO_PIN_10, GPIO_PIN_RESET);
  474. /*Configure GPIO pins : PF1 PF6 */
  475. GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_6;
  476. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  477. GPIO_InitStruct.Pull = GPIO_NOPULL;
  478. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  479. HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
  480. /*Configure GPIO pin : PC7 */
  481. GPIO_InitStruct.Pin = GPIO_PIN_7;
  482. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  483. GPIO_InitStruct.Pull = GPIO_NOPULL;
  484. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  485. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  486. /*Configure GPIO pins : PI11 PI10 */
  487. GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_10;
  488. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  489. GPIO_InitStruct.Pull = GPIO_NOPULL;
  490. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  491. HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
  492. /*Configure GPIO pins : PG2 PG0 PG1 */
  493. GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_0|GPIO_PIN_1;
  494. GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  495. GPIO_InitStruct.Pull = GPIO_PULLUP;
  496. HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
  497. /*Configure GPIO pin : PE9 */
  498. GPIO_InitStruct.Pin = GPIO_PIN_9;
  499. GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  500. GPIO_InitStruct.Pull = GPIO_PULLUP;
  501. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
  502. /* EXTI interrupt init*/
  503. HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
  504. HAL_NVIC_EnableIRQ(EXTI0_IRQn);
  505. HAL_NVIC_SetPriority(EXTI1_IRQn, 2, 0);
  506. HAL_NVIC_EnableIRQ(EXTI1_IRQn);
  507. HAL_NVIC_SetPriority(EXTI2_IRQn, 2, 0);
  508. HAL_NVIC_EnableIRQ(EXTI2_IRQn);
  509. HAL_NVIC_SetPriority(EXTI9_IRQn, 1, 0);
  510. HAL_NVIC_EnableIRQ(EXTI9_IRQn);
  511. }
  512. /* USER CODE BEGIN 4 */
  513. /* USER CODE END 4 */
  514. /**
  515. * @brief This function is executed in case of error occurrence.
  516. * @retval None
  517. */
  518. void Error_Handler(void)
  519. {
  520. /* USER CODE BEGIN Error_Handler_Debug */
  521. /* User can add his own implementation to report the HAL error return state */
  522. __disable_irq();
  523. while (1)
  524. {
  525. }
  526. /* USER CODE END Error_Handler_Debug */
  527. }
  528. #ifdef USE_FULL_ASSERT
  529. /**
  530. * @brief Reports the name of the source file and the source line number
  531. * where the assert_param error has occurred.
  532. * @param file: pointer to the source file name
  533. * @param line: assert_param error line source number
  534. * @retval None
  535. */
  536. void assert_failed(uint8_t *file, uint32_t line)
  537. {
  538. /* USER CODE BEGIN 6 */
  539. /* User can add his own implementation to report the file name and line number,
  540. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  541. /* USER CODE END 6 */
  542. }
  543. #endif /* USE_FULL_ASSERT */
  544. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

stm32mp1xx_it.c

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file stm32mp1xx_it.c
  5. * @brief Interrupt Service Routines.
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under BSD 3-Clause license,
  13. * the "License"; You may not use this file except in compliance with the
  14. * License. You may obtain a copy of the License at:
  15. * opensource.org/licenses/BSD-3-Clause
  16. *
  17. ******************************************************************************
  18. */
  19. /* USER CODE END Header */
  20. /* Includes ------------------------------------------------------------------*/
  21. #include "main.h"
  22. #include "stm32mp1xx_it.h"
  23. /* Private includes ----------------------------------------------------------*/
  24. /* USER CODE BEGIN Includes */
  25. /* USER CODE END Includes */
  26. /* Private typedef -----------------------------------------------------------*/
  27. /* USER CODE BEGIN TD */
  28. /* USER CODE END TD */
  29. /* Private define ------------------------------------------------------------*/
  30. /* USER CODE BEGIN PD */
  31. /* USER CODE END PD */
  32. /* Private macro -------------------------------------------------------------*/
  33. /* USER CODE BEGIN PM */
  34. /* USER CODE END PM */
  35. /* Private variables ---------------------------------------------------------*/
  36. /* USER CODE BEGIN PV */
  37. /* USER CODE END PV */
  38. /* Private function prototypes -----------------------------------------------*/
  39. /* USER CODE BEGIN PFP */
  40. /* USER CODE END PFP */
  41. /* Private user code ---------------------------------------------------------*/
  42. /* USER CODE BEGIN 0 */
  43. int time_100ms_cnt = 0; //0.1s计数�??
  44. int Beat_speed = 5; //节拍速度,代表半个节拍需要多少个0.1s
  45. int Beat_speed_n = 0; //实际执行的节�??
  46. int Beat_num = 2; //这个�?? �??要多少就 半拍
  47. int flag = 0; //当其等于 1 时,表示�??个音结束
  48. int EN = 0; //使能信号,用于开启整个音�??
  49. int list = 0; //音乐列表
  50. int list_max = 0; //音乐总数
  51. int Low_volume = 5; //音量大小
  52. #define Low_volume_cnt 3 //音量大小�??10增加
  53. /* USER CODE END 0 */
  54. /* External variables --------------------------------------------------------*/
  55. extern TIM_HandleTypeDef htim2;
  56. /* USER CODE BEGIN EV */
  57. /* USER CODE END EV */
  58. /******************************************************************************/
  59. /* Cortex-M4 Processor Interruption and Exception Handlers */
  60. /******************************************************************************/
  61. /**
  62. * @brief This function handles Non maskable interrupt.
  63. */
  64. void NMI_Handler(void)
  65. {
  66. /* USER CODE BEGIN NonMaskableInt_IRQn 0 */
  67. /* USER CODE END NonMaskableInt_IRQn 0 */
  68. /* USER CODE BEGIN NonMaskableInt_IRQn 1 */
  69. while (1)
  70. {
  71. }
  72. /* USER CODE END NonMaskableInt_IRQn 1 */
  73. }
  74. /**
  75. * @brief This function handles Hard fault interrupt.
  76. */
  77. void HardFault_Handler(void)
  78. {
  79. /* USER CODE BEGIN HardFault_IRQn 0 */
  80. /* USER CODE END HardFault_IRQn 0 */
  81. while (1)
  82. {
  83. /* USER CODE BEGIN W1_HardFault_IRQn 0 */
  84. /* USER CODE END W1_HardFault_IRQn 0 */
  85. }
  86. }
  87. /**
  88. * @brief This function handles Memory management fault.
  89. */
  90. void MemManage_Handler(void)
  91. {
  92. /* USER CODE BEGIN MemoryManagement_IRQn 0 */
  93. /* USER CODE END MemoryManagement_IRQn 0 */
  94. while (1)
  95. {
  96. /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
  97. /* USER CODE END W1_MemoryManagement_IRQn 0 */
  98. }
  99. }
  100. /**
  101. * @brief This function handles Pre-fetch fault, memory access fault.
  102. */
  103. void BusFault_Handler(void)
  104. {
  105. /* USER CODE BEGIN BusFault_IRQn 0 */
  106. /* USER CODE END BusFault_IRQn 0 */
  107. while (1)
  108. {
  109. /* USER CODE BEGIN W1_BusFault_IRQn 0 */
  110. /* USER CODE END W1_BusFault_IRQn 0 */
  111. }
  112. }
  113. /**
  114. * @brief This function handles Undefined instruction or illegal state.
  115. */
  116. void UsageFault_Handler(void)
  117. {
  118. /* USER CODE BEGIN UsageFault_IRQn 0 */
  119. /* USER CODE END UsageFault_IRQn 0 */
  120. while (1)
  121. {
  122. /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
  123. /* USER CODE END W1_UsageFault_IRQn 0 */
  124. }
  125. }
  126. /**
  127. * @brief This function handles System service call via SWI instruction.
  128. */
  129. void SVC_Handler(void)
  130. {
  131. /* USER CODE BEGIN SVCall_IRQn 0 */
  132. /* USER CODE END SVCall_IRQn 0 */
  133. /* USER CODE BEGIN SVCall_IRQn 1 */
  134. /* USER CODE END SVCall_IRQn 1 */
  135. }
  136. /**
  137. * @brief This function handles Debug monitor.
  138. */
  139. void DebugMon_Handler(void)
  140. {
  141. /* USER CODE BEGIN DebugMonitor_IRQn 0 */
  142. /* USER CODE END DebugMonitor_IRQn 0 */
  143. /* USER CODE BEGIN DebugMonitor_IRQn 1 */
  144. /* USER CODE END DebugMonitor_IRQn 1 */
  145. }
  146. /**
  147. * @brief This function handles Pendable request for system service.
  148. */
  149. void PendSV_Handler(void)
  150. {
  151. /* USER CODE BEGIN PendSV_IRQn 0 */
  152. /* USER CODE END PendSV_IRQn 0 */
  153. /* USER CODE BEGIN PendSV_IRQn 1 */
  154. /* USER CODE END PendSV_IRQn 1 */
  155. }
  156. /**
  157. * @brief This function handles System tick timer.
  158. */
  159. void SysTick_Handler(void)
  160. {
  161. /* USER CODE BEGIN SysTick_IRQn 0 */
  162. /* USER CODE END SysTick_IRQn 0 */
  163. HAL_IncTick();
  164. /* USER CODE BEGIN SysTick_IRQn 1 */
  165. /* USER CODE END SysTick_IRQn 1 */
  166. }
  167. /******************************************************************************/
  168. /* STM32MP1xx Peripheral Interrupt Handlers */
  169. /* Add here the Interrupt Handlers for the used peripherals. */
  170. /* For the available peripheral interrupt handler names, */
  171. /* please refer to the startup file (startup_stm32mp1xx.s). */
  172. /******************************************************************************/
  173. /**
  174. * @brief This function handles EXTI line0 interrupt.
  175. */
  176. void EXTI0_IRQHandler(void)
  177. {
  178. /* USER CODE BEGIN EXTI0_IRQn 0 */
  179. if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_0) == 0)//确保数据稳定
  180. {
  181. //每次按下解决 音量�?? Low_volume_cnt
  182. Low_volume = Low_volume + Low_volume_cnt;
  183. if(Low_volume >= 10)
  184. Low_volume = 0;
  185. }
  186. /* USER CODE END EXTI0_IRQn 0 */
  187. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  188. /* USER CODE BEGIN EXTI0_IRQn 1 */
  189. /* USER CODE END EXTI0_IRQn 1 */
  190. }
  191. /**
  192. * @brief This function handles EXTI line1 interrupt.
  193. */
  194. void EXTI1_IRQHandler(void)
  195. {
  196. /* USER CODE BEGIN EXTI1_IRQn 0 */
  197. if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_1) == 0)//确保数据稳定
  198. {
  199. //控制音乐播放的�?�度
  200. static int i = 0;
  201. i++;
  202. //倍数计算公式 1 + (1 - (新的节拍速度 / 原来的节拍�?�度))
  203. switch(i){
  204. case 0:{
  205. Beat_speed = 5; //0.5s半个节拍,正常+�?�度
  206. break;
  207. }
  208. case 1:{
  209. Beat_speed = 4; //1.2倍数
  210. break;
  211. }
  212. case 2:{
  213. Beat_speed = 3; //约等�?? 1.5倍数
  214. break;
  215. }
  216. case 3:{
  217. Beat_speed = 1; //约等�?? 2 倍数
  218. break;
  219. }
  220. case 4:{
  221. Beat_speed = 6; //约等�?? 0.8 倍数
  222. break;
  223. }
  224. case 5:{
  225. Beat_speed = 7; //约等�?? 0.6 倍数
  226. break;
  227. }
  228. default:{
  229. Beat_speed = 5; //0.5s半个节拍,正常�?�度
  230. i=0;
  231. break;
  232. }
  233. }
  234. }
  235. /* USER CODE END EXTI1_IRQn 0 */
  236. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
  237. /* USER CODE BEGIN EXTI1_IRQn 1 */
  238. /* USER CODE END EXTI1_IRQn 1 */
  239. }
  240. /**
  241. * @brief This function handles EXTI line2 interrupt.
  242. */
  243. void EXTI2_IRQHandler(void)
  244. {
  245. /* USER CODE BEGIN EXTI2_IRQn 0 */
  246. //按下�??次音乐进入下�??�??
  247. if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_2) == 0)//确保数据稳定
  248. {
  249. list++;
  250. if(list > list_max){
  251. list = 0;
  252. }
  253. }
  254. /* USER CODE END EXTI2_IRQn 0 */
  255. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
  256. /* USER CODE BEGIN EXTI2_IRQn 1 */
  257. /* USER CODE END EXTI2_IRQn 1 */
  258. }
  259. /**
  260. * @brief This function handles TIM2 global interrupt.
  261. */
  262. void TIM2_IRQHandler(void)
  263. {
  264. /* USER CODE BEGIN TIM2_IRQn 0 */
  265. if(EN == 1)
  266. time_100ms_cnt++;
  267. else
  268. time_100ms_cnt = time_100ms_cnt; //其余状�?�不计数
  269. if(time_100ms_cnt >= Beat_speed_n * Beat_num){ //这个音节结束
  270. time_100ms_cnt = 0;
  271. flag = 1; //发�?�音节结束信�??
  272. }
  273. /* USER CODE END TIM2_IRQn 0 */
  274. HAL_TIM_IRQHandler(&htim2);
  275. /* USER CODE BEGIN TIM2_IRQn 1 */
  276. /* USER CODE END TIM2_IRQn 1 */
  277. }
  278. /**
  279. * @brief This function handles EXTI line9 interrupt.
  280. */
  281. void EXTI9_IRQHandler(void)
  282. {
  283. /* USER CODE BEGIN EXTI9_IRQn 0 */
  284. if(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_9) == 0)//确保数据稳定
  285. EN = !EN;
  286. /* USER CODE END EXTI9_IRQn 0 */
  287. HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
  288. /* USER CODE BEGIN EXTI9_IRQn 1 */
  289. /* USER CODE END EXTI9_IRQn 1 */
  290. }
  291. /**
  292. * @brief This function handles RCC wake-up interrupt.
  293. */
  294. void RCC_WAKEUP_IRQHandler(void)
  295. {
  296. /* USER CODE BEGIN RCC_WAKEUP_IRQn 0 */
  297. /* USER CODE END RCC_WAKEUP_IRQn 0 */
  298. HAL_RCC_WAKEUP_IRQHandler();
  299. /* USER CODE BEGIN RCC_WAKEUP_IRQn 1 */
  300. /* USER CODE END RCC_WAKEUP_IRQn 1 */
  301. }
  302. /* USER CODE BEGIN 1 */
  303. /* USER CODE END 1 */
  304. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

六、总结

这是一个基于STM32MP157A单片机的音乐盒设计较为全面和详细。主要包括以下几个方面:

  1. 硬件设计:

    • 使用STM32MP157A单片机作为核心控制器
    • 采用TIM2定时器产生0.1s中断控制节拍
    • 使用TIM4输出PWM信号驱动蜂鸣器播放音乐
    • 使用GPIO输入检测按键操作
  2. 软件设计:

    • 初始化音乐频率数据表,包括低音、中音和高音
    • 定义乐谱结构体,保存不同音乐的音符和节拍信息
    • 编写播放音乐的函数,根据乐谱信息控制蜂鸣器输出
    • 编写LED灯随音乐闪烁的函数
    • 实现通过按键控制音乐播放、速度、音量的功能
  3. 中断处理:

    • 使用外部中断处理按键输入,切换音乐、调节速度和音量
    • 使用定时器中断处理节拍控制,根据乐谱信息播放音乐
  4. 整体架构:

    • 将变量和函数划分到main.c和stm32mp1xx_it.c两个文件中,方便管理
    • 通过外部变量在两个文件中交换信息
    • 整体设计思路清晰,功能模块化,可扩展性强

总的来说,这个音乐盒的设计充分==利用了STM32MP157A单片机的各种外设资源,实现了一个功能丰富的音乐播放器。对于初学者来说,这个对于了解定时器和PWM有一定帮助。

帮助:关于电脑蓝屏解决方法(ST-LINK/ J-Link)

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

闽ICP备14008679号