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


    一、设计描述

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

    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. *

      © Copyright (c) 2024 STMicroelectronics.

    10. * All rights reserved.
    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. *

      © Copyright (c) 2024 STMicroelectronics.

    10. * All rights reserved.
    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)

  • 相关阅读:
    阿里巴巴内部纯享的这份SpringBoot+VUE全栈开发实战手册,绝了
    刷题DAY22 | LeetCode 235-二叉搜索树的最近公共祖先 701-二叉搜索树中的插入操作 450-删除二叉搜索树中的节点
    【VMware vSphere】搭建属于自己的 vSphere 实验环境(3)——Windows 系统安装与服务部署
    各类语言真实性能比较列表
    debian中vim的使用
    Mysql类的封装
    unix环境高级编程 第一章 UNIX基础知识 Go实现代码
    x86_64 ubuntu22.04 源码编译WebKit-7615.3.12.11.3
    Zeek学习(四) —— IP协议解析
    基础复习(IDA调试器)
  • 原文地址:https://blog.csdn.net/yandadzf/article/details/139279402