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,一经查实,立即删除!

相关文章

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

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

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.使用所需的板…

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 列表、元组、字典和集合的区别 数 据…

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

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

凤香的“蜜”密

执笔 | 文 清 编辑 | 古利特 “遇水则漏&#xff0c;遇酒生香”。酒海&#xff0c;一种大型盛酒容器&#xff0c;因盛酒量以“吨”计算&#xff0c;故称“海”&#xff0c;传于唐宋&#xff0c;兴盛于明清&#xff0c;距今有1400多年的历史。文人墨客笔下&#xff0c;也多有…

C++重点基础知识汇总大全

文章目录 一些基础知识点指针和引用 一些基础知识点 1、十进制的数字比较长的时候&#xff0c;可以加方便阅读到底是几位&#xff0c;输出的时候跟不加是一样的效果 // 十进制可以加 cout << 13890324 << endl; // 13890324 // 二进制前加0b cout << 0b111…

LeetCode/NowCoder-链表经典算法OJ练习4

人的才华就如海绵的水&#xff0c;没有外力的挤压&#xff0c;它是绝对流不出来的。流出来后&#xff0c;海绵才能吸收新的源泉。&#x1f493;&#x1f493;&#x1f493; 目录 说在前面 题目一&#xff1a;环形链表 题目二&#xff1a;环形链表 II 题目三&#xff1a;随机…

《Python编程从入门到实践》day34

# 昨日知识点回顾 json文件提取数据、绘制图表渐变色显示 # 今日知识点学习 第17章 17.1 使用Web API Web API作为网站的一部分&#xff0c;用于与使用具体URL请求特定信息的程序交互&#xff0c;这种请求称为API调用。 17.1.1 Git 和 GitHub Git&#xff1a;分布式版本控制系…

Media Encoder 2024 for Mac媒体编码器安装教程ME2024安装包下载

安装 步骤 1&#xff0c;双击打开下载好的安装包。 2&#xff0c;选择install ame_24...双击打开启动安装程序。 3&#xff0c;点击install。 4&#xff0c;输入电脑密码。 5&#xff0c;软件安装中... 6&#xff0c;安装结束点击好。 7&#xff0c;返回打开的镜像 选择激活补…

零基础,想做一名网络安全工程师,该怎么学习?

​ 相比IT类的其它岗位&#xff0c;网络工程师的学习方向是比较明亮的。想要成为网络工程师&#xff0c;华为认证就是最好的学习方法。而网络工程师的从零开始学习就是从华为认证的初级开始学起&#xff0c;也就是HCIA&#xff0c;也就是从最基本的什么是IP地址、什么是交换机这…

响应式流和reactor框架进阶

响应式流和reactor框架进阶 响应式流创建、转换、处理 本文档主要介绍在响应式编程中如何从流中获取数据并处理。 前提条件 假设您已经能掌握Java基础、Maven使用、Lamda表达式、响应式编程等基础。 如何获取流中数据 &#x1f30f; 说明 1、不要试图从流中获取数据出来&a…