STM32F407学习笔记(一) CubeMX、CubeIDE配置按键控制PWM波使蜂鸣器播放音乐

文章框架

    • PWM生成及歌曲实现原理
    • CubeMX配置
    • CubeIDE代码
      • gpio.h代码定义
      • gpio.c编写函数代码
      • main.c调用

PWM生成及歌曲实现原理

STM32F407有两类定时器:基础定时器和通用定时器(关于定时器可以看这里)。

通用定时器具有生成PWM波的功能,因此本例中使用通用定时器中的TIM13生成PWM波。

在定时器中时基单元有三种寄存器:计数寄存器(CNT)、 预分频寄存器(PSC)、自动重载寄存器(ARR)。

PWM波生成,通过设置ARR寄存器和CCR寄存器的值,在计数器的值CNT变化过程中,输出PWM波。PWM波的频率由ARR寄存器决定,占空比由CCR寄存器决定。

单片机输出高低不同的脉冲信号来控制蜂鸣器发音,要想产生音频脉冲信号,需要算出某音频的周期(1/频率)关键是每个音阶对应频率的方波如何求.在歌曲中,音调就是PWM波的频率(ARR),音量是其占空比(CCR),节拍通过delay延时函数实现。

f P W M = f 时 钟 频 率 ( P S C + 1 ) ( A R R + 1 ) f_{PWM}=\frac{f_{时钟频率}}{(PSC+1)(ARR+1)} fPWM=(PSC+1)(ARR+1)f
所以可得 A R R = f 时 钟 频 率 ( P S C + 1 ) ∗ f P W M − 1 ARR=\frac{f_{时钟频率}}{(PSC+1)*f_{PWM}}-1 ARR=(PSC+1)fPWMf1
我们在此例程中设置时钟频率为50MHz,预分频系数PSC为49,则
A R R = 1000000 f P W M − 1 ARR=\frac{1000000}{f_{PWM}}-1 ARR=fPWM10000001

CubeMX配置

STM32F407学习笔记(一) CubeMX、CubeIDE配置按键控制PWM波使蜂鸣器播放音乐_第1张图片
选择已经设置好FSMC的.ioc文件导入.
1.设置PinoutView
引脚PE2、PE3、PE4、PA0-WAKEUP为GPIO Input,用户标签分别为Key_Right,Key_Down,Key_LeftKey_Up;
PF8设置为TIM13_CH1;
PH0和PH1设置为RCC_OSC_INRCC_OSC_OUT
2.Timers 设置
激活TIM13,进行如下设置:
STM32F407学习笔记(一) CubeMX、CubeIDE配置按键控制PWM波使蜂鸣器播放音乐_第2张图片
在这里插入图片描述
3.时钟树设置
如图
STM32F407学习笔记(一) CubeMX、CubeIDE配置按键控制PWM波使蜂鸣器播放音乐_第3张图片之后生成代码即可。

CubeIDE代码

右键单击IDE中打开的项目名称
STM32F407学习笔记(一) CubeMX、CubeIDE配置按键控制PWM波使蜂鸣器播放音乐_第4张图片
将TFT_LCD子模块添加进去(如果不需要在开发板的LCD屏幕上显示该例程相关信息则不需要此步)。完成之后是这样的
STM32F407学习笔记(一) CubeMX、CubeIDE配置按键控制PWM波使蜂鸣器播放音乐_第5张图片
接下来在gpio.h中编写代码

gpio.h代码定义

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* USER CODE BEGIN Private defines */
#define  ZERO  3000//
	#define  R  1000000 //F_CLOCK/(psc+1)=50M/(49+1)=1000000
	//set tune *****************
	#define  L1       (R/262)-1        //低音1 DO
	#define  half_L1  (R/277)-1        //#1 DO#
	#define  L2       (R/294)-1
	#define  half_L2  (R/311)-1
	#define  L3       (R/330)-1
	#define  L4       (R/349)-1
	#define  half_L4  (R/370)-1
	#define  L5       (R/392)-1
	#define  half_L5  (R/410)-1
	#define  L6       (R/440)-1
	#define  half_L6  (R/466)-1
	#define  L7       (R/494)-1

	#define  M1       (R/523)-1        //中音1 DO 
	#define  half_M1 (R/554)-1        /
	#define  M2       (R/587)-1
	#define  half_M2  (R/622)-1
	#define  M3       (R/659)-1
	#define  M4       (R/698)-1
	#define  half_M4  (R/740)-1
	#define  M5       (R/784)-1
	#define  half_M5  (R/831)-1
	#define  M6       (R/880)-1
	#define  half_M6  (R/932)-1
	#define  M7       (R/988)-1

	#define  H1       (R/1046)-1        //高音1 DO
	#define  half_H1 (R/1109)-1
	#define  H2       (R/1175)-1
	#define  half_H2  (R/1245)-1
	#define  H3       (R/1318)-1
	#define  H4       (R/1397)-1
	#define  half_H4  (R/1480)-1
	#define  H5       (R/1568)-1
	#define  half_H5  (R/1661)-1
	#define  H6       (R/1760)-1
	#define  half_H6  (R/1865)-1
	#define  H7       (R/1967)-1
	/* USER CODE END Private defines */

gpio.c编写函数代码

/* USER CODE BEGIN 2 */
const uint32_t btnDelay2=1.5*300;//0.5
const uint32_t btnDelay3=600;//1
const uint32_t btnDelay4=2*150;//0.25
const uint32_t btnDelay5=700;//1+0.5
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//实现 EXTI 的回调函数 
{
	if (GPIO_Pin == GPIO_PIN_0) //如果KeyPA0=KEYUP,启动音乐
		{
		    HAL_TIM_Base_Start_IT(&htim13); 	//以中断方式启动TIM13
		    HAL_TIM_PWM_Start_IT(&htim13,TIM_CHANNEL_1);	//TIM13通道1, 启动生成PWM
			HAL_Delay(50);//消除按键抖动影响
		}
		else if(GPIO_Pin == GPIO_PIN_2)//PE2=KeyRight,关闭PWM生成
		{
		    HAL_TIM_Base_Stop_IT(&htim13);
		    HAL_TIM_PWM_Stop_IT(&htim13,TIM_CHANNEL_1);
			HAL_Delay(50);//消除按键抖动影响
		}
		else if(GPIO_Pin == GPIO_PIN_3)//PE3=KeyDown,关闭
		{
		    HAL_TIM_Base_Stop_IT(&htim13);
		    HAL_TIM_PWM_Stop_IT(&htim13,TIM_CHANNEL_1);
			HAL_Delay(50);//消除按键抖动影响
		}
		else if(GPIO_Pin == GPIO_PIN_4)//PE4=KeyLeft,启动音乐
		{
		    HAL_TIM_Base_Start_IT(&htim13); 	//以中断方式启动TIM13
		    HAL_TIM_PWM_Start_IT(&htim13,TIM_CHANNEL_1);	//TIM13通道1, 启动生成PWM
			HAL_Delay(50);//消除按键抖动影响
		}
}

void tim1(uint16_t tune)//短节拍
{
	 __HAL_TIM_SET_AUTORELOAD(&htim13,tune);//设置ARR的值
	 __HAL_TIM_SET_COMPARE(&htim13,TIM_CHANNEL_1,0.5*tune);//设置CCR的值,令CCR为ARR的一般,即占空比50%
	 HAL_Delay(btnDelay2);
}

void tim2(uint16_t tune)
{
	 __HAL_TIM_SET_AUTORELOAD(&htim13,tune);
	 __HAL_TIM_SET_COMPARE(&htim13,TIM_CHANNEL_1,0.5*tune);
	 HAL_Delay(btnDelay3);
}

void tim3(uint16_t tune)
{
	 __HAL_TIM_SET_AUTORELOAD(&htim13,tune);
	 __HAL_TIM_SET_COMPARE(&htim13,TIM_CHANNEL_1,0.5*tune);
	 HAL_Delay(btnDelay4);
}

void tim4(uint16_t tune)
{
	 __HAL_TIM_SET_AUTORELOAD(&htim13,tune);
	 __HAL_TIM_SET_COMPARE(&htim13,TIM_CHANNEL_1,0.5*tune);
	 HAL_Delay(btnDelay5);
}

	void play_music()//播放音乐
{

		    tim2(0);
			tim2(0);
			tim2(0);
	    	tim1(M6);
			tim1(M7);

			tim3(H1);
			tim1(M7);
			tim2(H1);
			tim2(H3);

			tim4(M7);
//			tim2(0,duration3);
			tim2(M7);
			tim1(M7);
			tim1(M3);
			tim1(M3);

			tim3(M6);
			tim1(M5);
			tim2(M6);
			tim2(H1);

			tim4(M5);
			tim4(M5);
			tim4(M5);
			tim2(0);
			tim2(M3);

//			tim3(M5,duration3);
//			tim1(M3,duration3);
			tim3(M4);
			tim1(M3);
			tim2(M4);
			tim2(H1);
////////////////////////////
			tim3(M3);
			tim1(M3);
			tim1(ZERO);
			tim1(H1);
			tim1(H1);
			tim1(H1);
			////////////////////59.
			tim3(M7);
			tim1(half_M4);
			tim2(M4);
			tim2(M7);

			tim4(M7);
			tim2(M7);
			tim2(ZERO);
			tim1(M6);
			tim1(M7);
			////////////////69

			tim3(H1);
			tim1(M7);
			tim2(H1);
			tim2(H3);

			tim4(M7);
			tim1(M7);
			tim1(M7);
			tim2(ZERO);
			tim1(M3);
			tim1(M3);

			tim3(M6);
			tim1(M5);
			tim2(M6);
			tim2(H1);
			//////////////////84
			tim4(M5);
			tim2(M5);
			tim1(M5);
			tim2(ZERO);
			tim1(M2);
			tim1(M3);

			tim2(M4);
			tim1(H1);
			tim2(M7);
			tim2(M7);
			tim3(H1);
			tim3(H1);

			tim1(H2);
			tim1(H2);
			tim1(H3);
			tim3(H1);
			tim2(ZERO);
			////////////////////100
			tim1(H1);
			tim1(H1);
			tim1(H1);
			tim1(M7);
			tim1(M6);
			tim1(M6);
			tim2(M7);
			tim2(half_M5);
			tim4(M6);
			tim4(M6);
			tim4(M6);
			tim1(H1);
			tim1(H2);

			tim3(H3);
			tim1(H2);
			tim2(H3);
			tim2(H5);

			tim4(H2);
			tim4(H2);
			tim4(H2);
			tim1(M5);
			tim1(M5);

			tim3(H1);
			tim1(M7);
			tim2(H1);
			tim2(H3);

			tim1(H3);
			tim1(H3);
			tim1(H3);
			tim1(H3);

			tim1(M6);/////////
			tim1(M7);
			tim2(H1);
			tim2(M7);
			tim1(H2);
			tim1(H2);

			tim3(H1);
			tim1(M5);
			tim3(M5);
			tim1(M5);

			tim2(H4);
			tim2(H3);
			tim2(H2);
			tim2(H1);

			tim4(H3);
			tim2(H3);
			tim2(H3);
			tim2(H3);

			tim4(H6);
			tim4(H6);
			tim2(H5);
			tim2(H5);
			tim1(H3);/////////
			tim1(H2);
			tim4(H1);
			tim4(H1);
			tim1(ZERO);
			tim1(H1);

			tim2(H2);
			tim1(H1);
			tim1(H2);
			tim2(H2);
			tim2(H5);

			tim1(H3);
			tim1(H3);
			tim1(H3);
			tim2(ZERO);
			tim1(H3);

			tim4(H6);
			tim4(H6);
			tim4(H5);
			tim4(H5);

			tim1(H3);
			tim1(H2);
			tim4(H1);
			tim4(H1);
			tim1(ZERO);
			tim1(H1);/////////

			tim2(H2);
			tim1(H1);
			tim2(H2);
			tim2(H2);

			tim2(M7);
			tim2(M6);
//			tim1(M6,duration2);
//			tim1(M6,duration2);
//			tim1(M6,duration2);
//			tim1(M7,duration2);
//			tim1(H2,0);
}
/* USER CODE END 2 */

main.c调用

/* USER CODE BEGIN Includes */
#include	"tftlcd.h"
#include "stm32f4xx_hal_tim.h"
/* USER CODE END Includes */
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_FSMC_Init();
  MX_TIM13_Init();
  /* USER CODE BEGIN 2 */
	TFTLCD_Init();		//TFT LCD软件初初始化
	LCD_ShowStr(10,10,(uint8_t *)"Demo10_5:PWM sky");
	LCD_ShowStr(10,LCD_CurY+LCD_SP20,(uint8_t *)"TIM13 generate PWM on PF8(BEEP)");
	LCD_ShowStr(10,LCD_CurY+LCD_SP20,(uint8_t *)"PWM interval= 200ms");
	LCD_ShowStr(10,LCD_CurY+LCD_SP20,(uint8_t *)"High pulse width= 50ms");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  play_music();
  }
  /* USER CODE END 3 */

上述代码实现的是《天空之城》,如果不需要按键控制播放和暂停,可以直接在主函数中设置相应的函数.

你可能感兴趣的:(学习笔记,【日进日新】,STM32学习)