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 基础变量

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

main.c基础变量

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

2. LED随音乐跳动


//将LED设置成全灭
void LED_RESET(){HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11|GPIO_PIN_10, GPIO_PIN_RESET);
}void LED(int i){if(i >= 1)  HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_SET);if(i >= 2)  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);if(i >= 3)  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11,GPIO_PIN_SET);if(i >= 4)  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);
}
//随音节输入,改变LED状�??
void LED_BEEP(int i){LED_RESET();switch(i){case 1:{LED(1);break;}case 2:{LED(1);break;}case 3:{LED(2);break;}case 4:{LED(2);break;}case 5:{LED(3);break;}case 6:{LED(3);break;}case 7:{LED(4);break;}default:{LED_RESET();break;}}
}

3. 配置低中高音


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

4.乐谱结构体

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

5. 编写乐谱


//创建乐谱 返回有多少首音乐
int music_init(){int cnt = 0;//第一首音�?? 生日快乐strcpy(music[0].name, "生日快乐"); 				// 使用strcpy复制字符�?? 给音乐命�??int music0_unit[29] = {0,0, 5,5,6,5,1,7, 5,5,6,5,2,1,5,5,6,3,1,7, 6,4,4,3,1,2,1,0,0};		//基础乐谱int music0_time[29] = {1,1, 1,1,2,2,2,3, 1,1,2,2,2,3,2,2,2,2,2,2, 2,2,2,2,2,2,3,1,1};		//乐谱节拍music[0].num = 29;										//乐谱总数int music0_unit_HL[29] = {1,1,0,0,0,0,1,0, 0,0,0,0,1,1,0,0,1,1,1,0, 0,1,1,1,1,1,1,1,1}; 	//乐谱全为中音//第二首音�?? �??闪一闪亮晶晶cnt++;strcpy(music[1].name, "�??闪一闪亮晶晶"); 					// 使用strcpy复制字符�?? 给音乐命�??int music1_unit[44] = {0,1,1,5,5,6,6,5, 4,4,3,3,2,2,1,5,5,4,4,3,3,2, 5,5,4,4,3,3,2,1,1,5,5,6,6,5, 4,4,3,3,2,2,1,0};		//基础乐谱int music1_time[44] = {2,2,2,2,2,2,2,3, 2,2,2,2,2,2,3,2,2,2,2,2,2,3, 2,2,2,2,2,2,3,2,2,2,2,2,2,3, 2,2,2,2,2,2,3,2};		//乐谱节拍int music1_unit_HL[44] ={1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1}; 		//乐谱全为中音music[1].num = 44;											//乐谱总数//第三首音�?? 两只老虎cnt++;strcpy(music[2].name, "两只老虎"); 					// 使用strcpy复制字符�?? 给音乐命�??int music2_unit[38] = {0,1,2,3,1, 1,2,3,1, 3,4,5,5, 3,4,5,5,5,6,5,4, 3,1,5,6, 5,4,3,1, 1,5,1,1,1,5,1,1, 0};		//基础乐谱int music2_time[38] = {2,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,0,0,0,0, 1,1,0,0, 0,0,1,1, 1,1,1,2,1,1,1,2, 2};		//乐谱节拍int music2_unit_HL[38] ={1,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,0,1,1,1,0,1,1, 1}; 		//乐谱�??   中音music[2].num = 38;											//乐谱总数//第四首音�?? 青花瓷片�??cnt++;strcpy(music[3].name, "青花瓷片选"); 					// 使用strcpy复制字符�?? 给音乐命�??int music3_unit[100] = {0,0,0,0, 0,5,5,3, 2,3,6,2, 3,5,3,2, 2,5,5,3,2,3,5,2, 3,5,2,1, 1,1,2,3, 5,6,5,4, 5,3,3,2,2,2,1,2, 1,1,2,1, 2,3,5,3, 3,3,5,5, 3,2,3,6,2,3,5,3, 2,2,5,5, 3,2,3,5, 2,3,5,2, 1,1,1,2,3,5,6,5, 4,5,3,3, 2,2,5,3, 2,2,2,1, 1,0,0,0};		//基础乐谱int music3_time[100] = {0,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,2, 0,0,0,0,0,0,1,0, 0,0,0,2, 0,0,0,0, 0,0,0,0, 0,0,0,0,2,0,0,0, 0,0,0,0, 0,1,0,0, 2,0,0,0, 0,0,0,1,0,0,0,0, 2,0,0,0, 0,0,0,1, 0,0,0,0, 2,0,0,0,0,0,0,0, 0,0,0,0, 0,2,0,1, 0,0,0,1, 2,1,1,1};		//乐谱节拍for(int i =0;i<100;i++)music3_time[i] = music3_time[i]+1;int music3_unit_HL[100] ={ 1,1,1,1, 1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1,1,1,0,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,0,1,1,1,1, 1,1,1,1, 1,1,1,0, 1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1}; 		//乐谱�??   中音music[3].num = 100;											//乐谱总数for (int i = 0; i < MAX_unit_num; i++) {//将乐谱保存进结构�??if(i<music[0].num){//确保数据正确music[0].unit[i] =music0_unit[i];music[0].unit_HL[i] =music0_unit_HL[i];music[0].time[i] =music0_time[i];}//将乐谱保存进结构�??if(i<music[1].num){//确保数据正确music[1].unit[i] =music1_unit[i];music[1].unit_HL[i] =music1_unit_HL[i];music[1].time[i] =music1_time[i];}//将乐谱保存进结构�??if(i<music[2].num){//确保数据正确music[2].unit[i] =music2_unit[i];music[2].unit_HL[i] =music2_unit_HL[i];music[2].time[i] =music2_time[i];}//将乐谱保存进结构�??if(i<music[3].num){//确保数据正确music[3].unit[i] =music3_unit[i];music[3].unit_HL[i] =music3_unit_HL[i];music[3].time[i] =music3_time[i];}}return cnt;
}

6. 音乐实现函数

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

7. 全部中断


void EXTI0_IRQHandler(void)
{/* USER CODE BEGIN EXTI0_IRQn 0 */if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_0) == 0)//确保数据稳定{//每次按下解决 音量�?? Low_volume_cntLow_volume = Low_volume + Low_volume_cnt;if(Low_volume >= 10)Low_volume = 0;}/* USER CODE END EXTI0_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);/* USER CODE BEGIN EXTI0_IRQn 1 *//* USER CODE END EXTI0_IRQn 1 */
}/*** @brief This function handles EXTI line1 interrupt.*/
void EXTI1_IRQHandler(void)
{/* USER CODE BEGIN EXTI1_IRQn 0 */if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_1) == 0)//确保数据稳定{//控制音乐播放的�?�度static int i = 0;i++;//倍数计算公式 1 + (1 - (新的节拍速度 / 原来的节拍�?�度))switch(i){case 0:{Beat_speed = 5;	//0.5s半个节拍,正常+�?�度break;}case 1:{Beat_speed = 4;	//1.2倍数break;}case 2:{Beat_speed = 3;	//约等�?? 1.5倍数break;}case 3:{Beat_speed = 1;	//约等�?? 2 倍数break;}case 4:{Beat_speed = 6;	//约等�?? 0.8 倍数break;}case 5:{Beat_speed = 7;	//约等�?? 0.6 倍数break;}default:{Beat_speed = 5;	//0.5s半个节拍,正常�?�度i=0;break;}}}/* USER CODE END EXTI1_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);/* USER CODE BEGIN EXTI1_IRQn 1 *//* USER CODE END EXTI1_IRQn 1 */
}/*** @brief This function handles EXTI line2 interrupt.*/
void EXTI2_IRQHandler(void)
{/* USER CODE BEGIN EXTI2_IRQn 0 *///按下�??次音乐进入下�??�??if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_2) == 0)//确保数据稳定{list++;if(list > list_max){list = 0;}}/* USER CODE END EXTI2_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);/* USER CODE BEGIN EXTI2_IRQn 1 *//* USER CODE END EXTI2_IRQn 1 */
}/*** @brief This function handles TIM2 global interrupt.*/
void TIM2_IRQHandler(void)
{/* USER CODE BEGIN TIM2_IRQn 0 */if(EN == 1)time_100ms_cnt++;elsetime_100ms_cnt = time_100ms_cnt;	//其余状�?�不计数if(time_100ms_cnt >= Beat_speed_n * Beat_num){	//这个音节结束time_100ms_cnt = 0;flag = 1;	//发�?�音节结束信�??}/* USER CODE END TIM2_IRQn 0 */HAL_TIM_IRQHandler(&htim2);/* USER CODE BEGIN TIM2_IRQn 1 *//* USER CODE END TIM2_IRQn 1 */
}/*** @brief This function handles EXTI line9 interrupt.*/
void EXTI9_IRQHandler(void)
{/* USER CODE BEGIN EXTI9_IRQn 0 */if(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_9) == 0)//确保数据稳定EN = !EN;/* USER CODE END EXTI9_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);/* USER CODE BEGIN EXTI9_IRQn 1 *//* USER CODE END EXTI9_IRQn 1 */
}

五、总代码

main.c

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:*                        opensource.org/licenses/BSD-3-Clause********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */#include <string.h> // 引入strcpy函数�?�?的头文件
/* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim4;/* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM4_Init(void);
static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *///将LED设置成全�??
void LED_RESET(){HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11|GPIO_PIN_10, GPIO_PIN_RESET);
}void LED(int i){if(i >= 1)  HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1, GPIO_PIN_SET);if(i >= 2)  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);if(i >= 3)  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11,GPIO_PIN_SET);if(i >= 4)  HAL_GPIO_WritePin(GPIOI, GPIO_PIN_10, GPIO_PIN_SET);
}
//随音节输入,改变LED状�??
void LED_BEEP(int i){LED_RESET();switch(i){case 1:{LED(1);break;}case 2:{LED(1);break;}case 3:{LED(2);break;}case 4:{LED(2);break;}case 5:{LED(3);break;}case 6:{LED(3);break;}case 7:{LED(4);break;}default:{LED_RESET();break;}}
}extern int time_100ms_cnt; 	//0.1s计数�??
extern int Beat_speed;		//节拍速度,代表半个节拍需要多少个0.1s
extern int Beat_speed_n;	//实际执行的节�??extern int Beat_num;		//这个�?? �??要多少个 半拍
extern int flag; 			//当其等于 1 时,表示�??个音结束
extern int EN;				//使能信号,用于开启整个音�??
extern int list ;			//音乐列表
extern int list_max ;		//音乐总数
extern int Low_volume;		//音量大小int tone[3][8];
//初始化高中低�??
void tone_init(){tone[1][0] = 0;	//不执�??tone[1][1] = 191;tone[1][2] = 170;tone[1][3] = 151;tone[1][4] = 143;tone[1][5] = 127;tone[1][6] = 113;tone[1][7] = 101;// 低音 (Low)for (int i = 0; i < 8; i++) {tone[0][i] = tone[1][i] * 2; // 只是�??个近似的值,实际值可能不�??}// 高音 (High)for (int i = 0; i < 8; i++) {tone[2][i] = tone[1][i] / 2; // 只是�??个近似的值,实际值可能不�??}
}#define MAX_unit_num 200 //�??大乐谱数�??
//创建结构体保存乐�??
struct music_unit{char name[50];		//乐谱名称int unit[MAX_unit_num];		//发什么音int unit_HL[MAX_unit_num];	//发高音或者其�??int time[MAX_unit_num];		//发音时间//int time_4[MAX_unit_num];	//判断是否�??1/4�??int num;			//记录有多少个
}music[25];//创建乐谱 返回有多少首音乐
int music_init(){int cnt = 0;//第一首音�?? 生日快乐strcpy(music[0].name, "生日快乐"); 				// 使用strcpy复制字符�?? 给音乐命�??int music0_unit[29] = {0,0, 5,5,6,5,1,7, 5,5,6,5,2,1,5,5,6,3,1,7, 6,4,4,3,1,2,1,0,0};		//基础乐谱int music0_time[29] = {1,1, 1,1,2,2,2,3, 1,1,2,2,2,3,2,2,2,2,2,2, 2,2,2,2,2,2,3,1,1};		//乐谱节拍music[0].num = 29;										//乐谱总数int music0_unit_HL[29] = {1,1,0,0,0,0,1,0, 0,0,0,0,1,1,0,0,1,1,1,0, 0,1,1,1,1,1,1,1,1}; 	//乐谱全为中音//第二首音�?? �??闪一闪亮晶晶cnt++;strcpy(music[1].name, "�??闪一闪亮晶晶"); 					// 使用strcpy复制字符�?? 给音乐命�??int music1_unit[44] = {0,1,1,5,5,6,6,5, 4,4,3,3,2,2,1,5,5,4,4,3,3,2, 5,5,4,4,3,3,2,1,1,5,5,6,6,5, 4,4,3,3,2,2,1,0};		//基础乐谱int music1_time[44] = {2,2,2,2,2,2,2,3, 2,2,2,2,2,2,3,2,2,2,2,2,2,3, 2,2,2,2,2,2,3,2,2,2,2,2,2,3, 2,2,2,2,2,2,3,2};		//乐谱节拍int music1_unit_HL[44] ={1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1}; 		//乐谱全为中音music[1].num = 44;											//乐谱总数//第三首音�?? 两只老虎cnt++;strcpy(music[2].name, "两只老虎"); 					// 使用strcpy复制字符�?? 给音乐命�??int music2_unit[38] = {0,1,2,3,1, 1,2,3,1, 3,4,5,5, 3,4,5,5,5,6,5,4, 3,1,5,6, 5,4,3,1, 1,5,1,1,1,5,1,1, 0};		//基础乐谱int music2_time[38] = {2,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,0,0,0,0, 1,1,0,0, 0,0,1,1, 1,1,1,2,1,1,1,2, 2};		//乐谱节拍int music2_unit_HL[38] ={1,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,0,1,1,1,0,1,1, 1}; 		//乐谱�??   中音music[2].num = 38;											//乐谱总数//第四首音�?? 青花瓷片�??cnt++;strcpy(music[3].name, "青花瓷片选"); 					// 使用strcpy复制字符�?? 给音乐命�??int music3_unit[100] = {0,0,0,0, 0,5,5,3, 2,3,6,2, 3,5,3,2, 2,5,5,3,2,3,5,2, 3,5,2,1, 1,1,2,3, 5,6,5,4, 5,3,3,2,2,2,1,2, 1,1,2,1, 2,3,5,3, 3,3,5,5, 3,2,3,6,2,3,5,3, 2,2,5,5, 3,2,3,5, 2,3,5,2, 1,1,1,2,3,5,6,5, 4,5,3,3, 2,2,5,3, 2,2,2,1, 1,0,0,0};		//基础乐谱int music3_time[100] = {0,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,2, 0,0,0,0,0,0,1,0, 0,0,0,2, 0,0,0,0, 0,0,0,0, 0,0,0,0,2,0,0,0, 0,0,0,0, 0,1,0,0, 2,0,0,0, 0,0,0,1,0,0,0,0, 2,0,0,0, 0,0,0,1, 0,0,0,0, 2,0,0,0,0,0,0,0, 0,0,0,0, 0,2,0,1, 0,0,0,1, 2,1,1,1};		//乐谱节拍for(int i =0;i<100;i++)music3_time[i] = music3_time[i]+1;int music3_unit_HL[100] ={ 1,1,1,1, 1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1,1,1,0,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,0,1,1,1,1, 1,1,1,1, 1,1,1,0, 1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1}; 		//乐谱�??   中音music[3].num = 100;											//乐谱总数for (int i = 0; i < MAX_unit_num; i++) {//将乐谱保存进结构�??if(i<music[0].num){//确保数据正确music[0].unit[i] =music0_unit[i];music[0].unit_HL[i] =music0_unit_HL[i];music[0].time[i] =music0_time[i];}//将乐谱保存进结构�??if(i<music[1].num){//确保数据正确music[1].unit[i] =music1_unit[i];music[1].unit_HL[i] =music1_unit_HL[i];music[1].time[i] =music1_time[i];}//将乐谱保存进结构�??if(i<music[2].num){//确保数据正确music[2].unit[i] =music2_unit[i];music[2].unit_HL[i] =music2_unit_HL[i];music[2].time[i] =music2_time[i];}//将乐谱保存进结构�??if(i<music[3].num){//确保数据正确music[3].unit[i] =music3_unit[i];music[3].unit_HL[i] =music3_unit_HL[i];music[3].time[i] =music3_time[i];}}return cnt;
}//播放�?? N首音�?? 音量�?? X 0 - 100
void play_music(int n, int x){static int ni = 0; 		//用于判断 是否换了音乐static int cnt = 0;		//记录播放到哪�??�?? 音节if(ni != n ){//如果音乐换了ni = n;cnt = 0;__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,0);//设置音量HAL_Delay(1000);//}//int value = tone[music[n].unit_HL[cnt]][music[n].unit[cnt]];	//获取频率if(flag == 1){	//接受到一个音节结�??flag = 0;	//复位Beat_num = music[n].time[cnt]; 				//这个音需要多少个半拍LED_BEEP(music[n].unit[cnt]);				//LED随音节变动�?�变�??if(music[n].time[cnt] == 0){//如果�?? 1/4�??Beat_speed_n = Beat_speed /2;}else{//如果没有1/4�??Beat_speed_n = Beat_speed;}//if(value != 0)//如果有频率�?�执行,没有者只更新 时间�??__HAL_TIM_SET_AUTORELOAD(&htim4,value);		//自动加载频率�??cnt ++; 	//可进行下�??次音�??if(cnt >= music[n].num){ //如果�??个音节播放完�??cnt = 0;//重新播放//__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,0);//设置音量//HAL_Delay(500);//}}//__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,x * (value/100));//设置音量__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,(value/10)*x);//设置音量
}/* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init */if(IS_ENGINEERING_BOOT_MODE()){/* Configure the system clock */SystemClock_Config();}/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM4_Init();MX_TIM2_Init();/* USER CODE BEGIN 2 */tone_init(); //初始化音量频�??list_max = music_init();//更新乐谱HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);	//�??启PWMHAL_TIM_Base_Start_IT(&htim2);		  	//�??启定时器�??/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */if(EN == 1)//�??启音�??play_music(list,Low_volume);else__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,0);//设置音量//EN = 1;//play_music(0,5);}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.HSICalibrationValue = 16;RCC_OscInitStruct.HSIDivValue = RCC_HSI_DIV1;RCC_OscInitStruct.LSIState = RCC_LSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;RCC_OscInitStruct.PLL2.PLLState = RCC_PLL_NONE;RCC_OscInitStruct.PLL3.PLLState = RCC_PLL_NONE;RCC_OscInitStruct.PLL4.PLLState = RCC_PLL_NONE;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** RCC Clock Config*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_ACLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2|RCC_CLOCKTYPE_PCLK3|RCC_CLOCKTYPE_PCLK4|RCC_CLOCKTYPE_PCLK5;RCC_ClkInitStruct.AXISSInit.AXI_Clock = RCC_AXISSOURCE_HSI;RCC_ClkInitStruct.AXISSInit.AXI_Div = RCC_AXI_DIV1;RCC_ClkInitStruct.MCUInit.MCU_Clock = RCC_MCUSSOURCE_HSI;RCC_ClkInitStruct.MCUInit.MCU_Div = RCC_MCU_DIV1;RCC_ClkInitStruct.APB4_Div = RCC_APB4_DIV1;RCC_ClkInitStruct.APB5_Div = RCC_APB5_DIV1;RCC_ClkInitStruct.APB1_Div = RCC_APB1_DIV1;RCC_ClkInitStruct.APB2_Div = RCC_APB2_DIV1;RCC_ClkInitStruct.APB3_Div = RCC_APB3_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK){Error_Handler();}
}/*** @brief TIM2 Initialization Function* @param None* @retval None*/
static void MX_TIM2_Init(void)
{/* USER CODE BEGIN TIM2_Init 0 *//* USER CODE END TIM2_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};/* USER CODE BEGIN TIM2_Init 1 *//* USER CODE END TIM2_Init 1 */htim2.Instance = TIM2;htim2.Init.Prescaler = 6400-1;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 1000-1;htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim2) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM2_Init 2 *//* USER CODE END TIM2_Init 2 */}/*** @brief TIM4 Initialization Function* @param None* @retval None*/
static void MX_TIM4_Init(void)
{/* USER CODE BEGIN TIM4_Init 0 *//* USER CODE END TIM4_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};/* USER CODE BEGIN TIM4_Init 1 *//* USER CODE END TIM4_Init 1 */htim4.Instance = TIM4;htim4.Init.Prescaler = 640-1;htim4.Init.CounterMode = TIM_COUNTERMODE_UP;htim4.Init.Period = 100-1;htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim4) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_Init(&htim4) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 0;sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM4_Init 2 *//* USER CODE END TIM4_Init 2 */HAL_TIM_MspPostInit(&htim4);}/*** @brief GPIO Initialization Function* @param None* @retval None*/
static void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOF_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOI_CLK_ENABLE();__HAL_RCC_GPIOG_CLK_ENABLE();__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOF, GPIO_PIN_1|GPIO_PIN_6, GPIO_PIN_RESET);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOI, GPIO_PIN_11|GPIO_PIN_10, GPIO_PIN_RESET);/*Configure GPIO pins : PF1 PF6 */GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_6;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);/*Configure GPIO pin : PC7 */GPIO_InitStruct.Pin = GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/*Configure GPIO pins : PI11 PI10 */GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);/*Configure GPIO pins : PG2 PG0 PG1 */GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_0|GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);/*Configure GPIO pin : PE9 */GPIO_InitStruct.Pin = GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);HAL_NVIC_EnableIRQ(EXTI0_IRQn);HAL_NVIC_SetPriority(EXTI1_IRQn, 2, 0);HAL_NVIC_EnableIRQ(EXTI1_IRQn);HAL_NVIC_SetPriority(EXTI2_IRQn, 2, 0);HAL_NVIC_EnableIRQ(EXTI2_IRQn);HAL_NVIC_SetPriority(EXTI9_IRQn, 1, 0);HAL_NVIC_EnableIRQ(EXTI9_IRQn);}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

stm32mp1xx_it.c

/* USER CODE BEGIN Header */
/********************************************************************************* @file    stm32mp1xx_it.c* @brief   Interrupt Service Routines.******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:*                        opensource.org/licenses/BSD-3-Clause********************************************************************************/
/* USER CODE END Header *//* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32mp1xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD *//* USER CODE END TD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int time_100ms_cnt = 0; //0.1s计数�??
int Beat_speed = 5;		//节拍速度,代表半个节拍需要多少个0.1s
int Beat_speed_n = 0;	//实际执行的节�??int Beat_num = 2;		//这个�?? �??要多少就 半拍
int flag = 0; 			//当其等于 1 时,表示�??个音结束
int EN = 0;				//使能信号,用于开启整个音�??
int list = 0;			//音乐列表
int list_max = 0;		//音乐总数
int Low_volume = 5;		//音量大小
#define Low_volume_cnt  3	//音量大小�??10增加/* USER CODE END 0 *//* External variables --------------------------------------------------------*/
extern TIM_HandleTypeDef htim2;
/* USER CODE BEGIN EV *//* USER CODE END EV *//******************************************************************************/
/*           Cortex-M4 Processor Interruption and Exception Handlers          */
/******************************************************************************/
/*** @brief This function handles Non maskable interrupt.*/
void NMI_Handler(void)
{/* USER CODE BEGIN NonMaskableInt_IRQn 0 *//* USER CODE END NonMaskableInt_IRQn 0 *//* USER CODE BEGIN NonMaskableInt_IRQn 1 */while (1){}/* USER CODE END NonMaskableInt_IRQn 1 */
}/*** @brief This function handles Hard fault interrupt.*/
void HardFault_Handler(void)
{/* USER CODE BEGIN HardFault_IRQn 0 *//* USER CODE END HardFault_IRQn 0 */while (1){/* USER CODE BEGIN W1_HardFault_IRQn 0 *//* USER CODE END W1_HardFault_IRQn 0 */}
}/*** @brief This function handles Memory management fault.*/
void MemManage_Handler(void)
{/* USER CODE BEGIN MemoryManagement_IRQn 0 *//* USER CODE END MemoryManagement_IRQn 0 */while (1){/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 *//* USER CODE END W1_MemoryManagement_IRQn 0 */}
}/*** @brief This function handles Pre-fetch fault, memory access fault.*/
void BusFault_Handler(void)
{/* USER CODE BEGIN BusFault_IRQn 0 *//* USER CODE END BusFault_IRQn 0 */while (1){/* USER CODE BEGIN W1_BusFault_IRQn 0 *//* USER CODE END W1_BusFault_IRQn 0 */}
}/*** @brief This function handles Undefined instruction or illegal state.*/
void UsageFault_Handler(void)
{/* USER CODE BEGIN UsageFault_IRQn 0 *//* USER CODE END UsageFault_IRQn 0 */while (1){/* USER CODE BEGIN W1_UsageFault_IRQn 0 *//* USER CODE END W1_UsageFault_IRQn 0 */}
}/*** @brief This function handles System service call via SWI instruction.*/
void SVC_Handler(void)
{/* USER CODE BEGIN SVCall_IRQn 0 *//* USER CODE END SVCall_IRQn 0 *//* USER CODE BEGIN SVCall_IRQn 1 *//* USER CODE END SVCall_IRQn 1 */
}/*** @brief This function handles Debug monitor.*/
void DebugMon_Handler(void)
{/* USER CODE BEGIN DebugMonitor_IRQn 0 *//* USER CODE END DebugMonitor_IRQn 0 *//* USER CODE BEGIN DebugMonitor_IRQn 1 *//* USER CODE END DebugMonitor_IRQn 1 */
}/*** @brief This function handles Pendable request for system service.*/
void PendSV_Handler(void)
{/* USER CODE BEGIN PendSV_IRQn 0 *//* USER CODE END PendSV_IRQn 0 *//* USER CODE BEGIN PendSV_IRQn 1 *//* USER CODE END PendSV_IRQn 1 */
}/*** @brief This function handles System tick timer.*/
void SysTick_Handler(void)
{/* USER CODE BEGIN SysTick_IRQn 0 *//* USER CODE END SysTick_IRQn 0 */HAL_IncTick();/* USER CODE BEGIN SysTick_IRQn 1 *//* USER CODE END SysTick_IRQn 1 */
}/******************************************************************************/
/* STM32MP1xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32mp1xx.s).                    */
/******************************************************************************//*** @brief This function handles EXTI line0 interrupt.*/
void EXTI0_IRQHandler(void)
{/* USER CODE BEGIN EXTI0_IRQn 0 */if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_0) == 0)//确保数据稳定{//每次按下解决 音量�?? Low_volume_cntLow_volume = Low_volume + Low_volume_cnt;if(Low_volume >= 10)Low_volume = 0;}/* USER CODE END EXTI0_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);/* USER CODE BEGIN EXTI0_IRQn 1 *//* USER CODE END EXTI0_IRQn 1 */
}/*** @brief This function handles EXTI line1 interrupt.*/
void EXTI1_IRQHandler(void)
{/* USER CODE BEGIN EXTI1_IRQn 0 */if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_1) == 0)//确保数据稳定{//控制音乐播放的�?�度static int i = 0;i++;//倍数计算公式 1 + (1 - (新的节拍速度 / 原来的节拍�?�度))switch(i){case 0:{Beat_speed = 5;	//0.5s半个节拍,正常+�?�度break;}case 1:{Beat_speed = 4;	//1.2倍数break;}case 2:{Beat_speed = 3;	//约等�?? 1.5倍数break;}case 3:{Beat_speed = 1;	//约等�?? 2 倍数break;}case 4:{Beat_speed = 6;	//约等�?? 0.8 倍数break;}case 5:{Beat_speed = 7;	//约等�?? 0.6 倍数break;}default:{Beat_speed = 5;	//0.5s半个节拍,正常�?�度i=0;break;}}}/* USER CODE END EXTI1_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);/* USER CODE BEGIN EXTI1_IRQn 1 *//* USER CODE END EXTI1_IRQn 1 */
}/*** @brief This function handles EXTI line2 interrupt.*/
void EXTI2_IRQHandler(void)
{/* USER CODE BEGIN EXTI2_IRQn 0 *///按下�??次音乐进入下�??�??if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_2) == 0)//确保数据稳定{list++;if(list > list_max){list = 0;}}/* USER CODE END EXTI2_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);/* USER CODE BEGIN EXTI2_IRQn 1 *//* USER CODE END EXTI2_IRQn 1 */
}/*** @brief This function handles TIM2 global interrupt.*/
void TIM2_IRQHandler(void)
{/* USER CODE BEGIN TIM2_IRQn 0 */if(EN == 1)time_100ms_cnt++;elsetime_100ms_cnt = time_100ms_cnt;	//其余状�?�不计数if(time_100ms_cnt >= Beat_speed_n * Beat_num){	//这个音节结束time_100ms_cnt = 0;flag = 1;	//发�?�音节结束信�??}/* USER CODE END TIM2_IRQn 0 */HAL_TIM_IRQHandler(&htim2);/* USER CODE BEGIN TIM2_IRQn 1 *//* USER CODE END TIM2_IRQn 1 */
}/*** @brief This function handles EXTI line9 interrupt.*/
void EXTI9_IRQHandler(void)
{/* USER CODE BEGIN EXTI9_IRQn 0 */if(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_9) == 0)//确保数据稳定EN = !EN;/* USER CODE END EXTI9_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);/* USER CODE BEGIN EXTI9_IRQn 1 *//* USER CODE END EXTI9_IRQn 1 */
}/*** @brief This function handles RCC wake-up interrupt.*/
void RCC_WAKEUP_IRQHandler(void)
{/* USER CODE BEGIN RCC_WAKEUP_IRQn 0 *//* USER CODE END RCC_WAKEUP_IRQn 0 */HAL_RCC_WAKEUP_IRQHandler();/* USER CODE BEGIN RCC_WAKEUP_IRQn 1 *//* USER CODE END RCC_WAKEUP_IRQn 1 */
}/* USER CODE BEGIN 1 *//* USER CODE END 1 */
/************************ (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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/18265.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于 HTML5 和腾讯云播放 SDK 开发的 M3U8 在线播放器

在当前的网络视频领域&#xff0c;M3U8 文件格式是一种广泛应用的流媒体播放格式&#xff0c;具有广泛的兼容性和稳定性。为了在网页上实现 M3U8 格式的在线播放&#xff0c;我们可以结合 HTML5 技术和腾讯云播放 SDK&#xff0c;快速开发一个功能强大的 M3U8 在线播放器。 体验…

kafka-生产者发送消息消费者消费消息

文章目录 1、生产者发送消息&消费者消费消息1.1、获取 kafka-console-producer.sh 的帮助信息1.2、生产者发送消息到某个主题1.3、消费主题数据 1、生产者发送消息&消费者消费消息 1.1、获取 kafka-console-producer.sh 的帮助信息 [rootlocalhost ~]# kafka-console…

16-云原生监控体系-监控 RabbitMQ-rabbitmq_exporter [部署Dashborad告警规则实战]

文章目录 1. 二进制方式部署1.1. 二进制包下载1.2. 配置1.2.1. 可用的环境变量1.2.2. 使用变量2. docker-compose 方式部署3. Metrics3.1. Global3.2. Overview3.3. Queues3.3.1 Queues - Gauge3.3.2. Queues - Counter3.4. Exchanges - Counter</

Xunsearch:实现拼音搜索和中文分词功能

首先我们需要安装xunsearch扩展库&#xff0c;参考 1、设置分词器和拼音搜索功能 在创建Xunsearch对象后&#xff0c;可以设置相应的分词器和拼音搜索功能。以下代码示例演示了如何设置分词器和拼音搜索功能&#xff1a; $index $xunsearch->index; $index->setToken…

解决SSH客户端远程连接CentOS7虚拟机时加载过慢问题

1、编辑 /etc/ssh/sshd_config 文件&#xff0c;将 useDNS 中的 yes 改为 no &#xff0c;关闭UseDNS加速&#xff1a; vi /etc/ssh/sshd_config2、重启ssh服务: systemctl restart sshd

Golang 创建第一个web项目(Gin + Gorm)

1. 写这篇博客的由来&#xff1a; 当你想使用最快的框架创建项目的时候是不是有点束手无策&#xff1f; 当你想配置数据库写 SQL 甚至不知道如何写&#xff0c;文件夹都不知道建在哪里&#xff1f; &#x1f604;因为Golang 目前并没有 JAVA 那种硬性规范&#xff0c;但是…

kafka-主题创建(主题操作的命令)

文章目录 1、topic主题操作的命令1.1、创建一个3分区1副本的主题1.1.1、获取 kafka-topics.sh 的帮助信息1.1.2、副本因子设置不能超过集群中broker的数量1.1.3、创建一个3分区1副本的主题1.1.4、查看所有主题1.1.5、查看主题详细描述 1、topic主题操作的命令 kafka发送消息会存…

巨额分红与大幅下调募资金额,小方制药注册生效半年后仍无进展

《港湾商业观察》施子夫 2022年7月1日&#xff0c;上海小方制药股份有限公司&#xff08;以下简称&#xff0c;小方制药&#xff09;递表上交所板&#xff0c;2023年9月1日公司提交了注册申请&#xff0c;并于同年12月19日获得生效。 离挂牌上市仅有一步之遥的小方制药注册生…

flutter开发实战-外接纹理texture处理图片展示

flutter开发实战-外接纹理处理图片展示 在Flutter中&#xff0c;如果你想要创建一个外接纹理的widget&#xff0c;你可以使用Texture widget。Texture widget用于显示视频或者画布&#xff08;canvas&#xff09;的内容。该组件只有唯一入参textureId 通过外接纹理的方式&…

迁移基于MicroBlaze处理器的设计

迁移基于MicroBlaze处理器的设计 生成系统基础设施&#xff08;MicroBlaze、AXI_Interconnect&#xff0c; Clk_Wiz、Proc_Sys_Reset&#xff09; 生成系统基础设施&#xff08;MicroBlaze、AXI_Interconnect、Clk_Wiz和 Proc_Sys_Reset&#xff09;&#xff1a; 1.使用所需的板…

Effective C++ 不要滥用宏

1.用宏的坏处 #define PI 3.14 用宏定义PI 所有遇到PPI的都替换为3.14 若是发生错误 这就是3.14 看不到这个PPI 用const 代替 如 const double Pi 3.14; 2.const替换宏 宏是不可修改的 const char * Text "hello"; 这只代表 "hello"不可改变 可…

素数环_回溯法

课本例题&#xff1a; 素数环是一个计算机程序问题&#xff0c;指的是将从1到n这n个整数围成一个圆环&#xff0c;若其中任意2个相邻的数字相加&#xff0c;结果均为素数&#xff0c;那么这个环就成为素数环。 #include <iostream>#include <cmath>using namespa…

2024年【危险化学品经营单位安全管理人员】考试报名及危险化学品经营单位安全管理人员找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位安全管理人员考试报名考前必练&#xff01;安全生产模拟考试一点通每个月更新危险化学品经营单位安全管理人员找解析题目及答案&#xff01;多做几遍&#xff0c;其实通过危险化学品经营单位安全管…

芋道源码 / yudao-cloud:前端技术架构探索与实践

摘要&#xff1a; 随着企业信息化建设的深入&#xff0c;后台管理系统在企业运营中扮演着至关重要的角色。本文将以芋道源码的yudao-cloud项目为例&#xff0c;深入探讨其前端技术架构的设计思路、关键技术与实现细节&#xff0c;并分享在开发过程中遇到的挑战与解决方案。 一、…

TCP UDP 传输协议 Acl 访问控制列表

TCP的应用 端口 21 FTP 22 SSH 25 SMTP 53 DNS 80 HTTP 443 HTTPS UDP 的应用 端口 69 TFTP 53 DNS 123 NTP Acl 访问控制列表 路由器ACL配置&#xff1a;[Huawei]acl 2000 //创建acl 列表号是2000[Huawei-acl-basic-2000]rule deny source 192…

列表、元组、字典和集合的区别

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在前面介绍了序列中的列表、元组、字典和集合的应用&#xff0c;下面通过表2对这几个数据序列进行比较。 表2 列表、元组、字典和集合的区别 数 据…

消除控制台打印com.apple.commcenter.coretelephony.xpc

控制台输出&#xff1a; [Client] Synchronous remote object proxy returned error: Error DomainNSCocoaErrorDomain Code4099 "The connection to service named com.apple.commcenter.coretelephony.xpc was invalidated." UserInfo{NSDebugDescriptionThe conne…

MyBatis 面试题

一、什么是 Mybatis? 1、Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时 只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。程序员直接编写原生态 sql,可以严格控制 sql 执行性 能,灵活度高。 …

【设计模式】适配器

来源&#xff1a;爱编程的大丙 STL标准模板库有六大组件&#xff0c;其中之一就是适配器 六大组件分别是&#xff1a;容器、算法、迭代器、仿函数、空间适配器 适配器可以分为&#xff1a;容器适配器、函数适配器、迭代器适配器 适配器&#xff0c;相当于沟通的桥梁。将一个…

半导体测试基础 - 功能测试

功能测试(Functional Test)主要是验证逻辑功能,是运用测试矢量和测试命令来进行的一种测试,相比于纯 DC 测试而言,组合步骤相对复杂且耦合度高。 在功能测试阶段时,测试系统会以周期为单位,将测试矢量输入 DUT,提供预测的结果并与输出的数据相比较,如果实际的结果与测…