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)∗fPWMf时钟频率−1
我们在此例程中设置时钟频率为50MHz,预分频系数PSC为49,则
A R R = 1000000 f P W M − 1 ARR=\frac{1000000}{f_{PWM}}-1 ARR=fPWM1000000−1
选择已经设置好FSMC的.ioc文件导入.
1.设置PinoutView
引脚PE2、PE3、PE4、PA0-WAKEUP为GPIO Input
,用户标签分别为Key_Right
,Key_Down
,Key_Left
和Key_Up
;
PF8设置为TIM13_CH1
;
PH0和PH1设置为RCC_OSC_IN
和RCC_OSC_OUT
2.Timers 设置
激活TIM13,进行如下设置:
3.时钟树设置
如图
之后生成代码即可。
右键单击IDE中打开的项目名称
将TFT_LCD子模块添加进去(如果不需要在开发板的LCD屏幕上显示该例程相关信息则不需要此步)。完成之后是这样的
接下来在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 */
/* 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 */
/* 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 */
上述代码实现的是《天空之城》,如果不需要按键控制播放和暂停,可以直接在主函数中设置相应的函数.