STM32-PWM驱动无源蜂鸣器播放周杰伦的《发如雪》

C调音符与频率对照表:

STM32-PWM驱动无源蜂鸣器播放周杰伦的《发如雪》_第1张图片

// 音符频率对照表(单位:Hz)
#define L1     262    // 低音1
#define L1_    277
#define L2     294
#define L2_    311
#define L3     300
#define L4     349
#define L4_    370
#define L5     392
#define L5_    415
#define L6     440
#define L6_    466
#define L7     494
#define N1     523    // 中音1
#define N1_    554
#define N2     587
#define N2_    622
#define N3     659
#define N4     698
#define N4_    740
#define N5     784
#define N5_    831
#define N6     880
#define N6_    932
#define N7     988
#define H1     1046    // 高音1
#define H1_    1109
#define H2     1175
#define H2_    1245
#define H3     1318
#define H4     1397
#define H4_    1480
#define H5     1568
#define H5_    1661
#define H6     1760
#define H6_    1865
#define H7     1976
#define END    0      // 结束标志

周杰伦《发如雪》简谱

STM32-PWM驱动无源蜂鸣器播放周杰伦的《发如雪》_第2张图片

GPIO和TIM初始化

#include "stm32f10x.h"                  // Device header

void RCC_Configuration(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}

void GPIO_Configuration(void)
{
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin= GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void TIM_Configuration(uint16_t freq)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	uint16_t prescaler = 72;  // 72MHz/72 = 1MHz	
	uint16_t period = (freq == 0) ? 0 : (1000000 / freq);
	
	TIM_InternalClockConfig(TIM2);
	
	//初始化时基单元	
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = period - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = prescaler -1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;	
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	//初始化PWM
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = period / 2;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;	
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

音乐模块

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "BUZZER.h"

// 音符频率对照表(单位:Hz)
#define L1     262    // 低音1
#define L1_    277
#define L2     294
#define L2_    311
#define L3     300
#define L4     349
#define L4_    370
#define L5     392
#define L5_    415
#define L6     440
#define L6_    466
#define L7     494
#define N1     523    // 中音1
#define N1_    554
#define N2     587
#define N2_    622
#define N3     659
#define N4     698
#define N4_    740
#define N5     784
#define N5_    831
#define N6     880
#define N6_    932
#define N7     988
#define H1     1046    // 高音1
#define H1_    1109
#define H2     1175
#define H2_    1245
#define H3     1318
#define H4     1397
#define H4_    1480
#define H5     1568
#define H5_    1661
#define H6     1760
#define H6_    1865
#define H7     1976
#define END    0      // 结束标志

#define BPM 90                       // 整体节奏控制
#define BEAT_DURATION (60000/BPM)    // 四分音符基准时长

// 节拍类型重定义
typedef enum {
    T1_16 = BEAT_DURATION/4,    // 十六分音符
    T1_8  = BEAT_DURATION/2,    // 八分音符
    T3_8  = BEAT_DURATION*3/4,  // 附点八分音符
    T1_4  = BEAT_DURATION,      // 四分音符
    T1_2  = BEAT_DURATION*2,    // 二分音符
    T1    = BEAT_DURATION*4     // 全音符
} NoteDuration;

// 乐曲数据结构
typedef struct 
{
    uint16_t freq;      // 频率
    uint16_t duration;  // 持续时间(ms)
} Note;

const Note Music[] = {
    // 前奏
    {N5, T1_4}, {N6, T1_8}, {H1, T1_8}, {N6, T1_4}, {N5, T1_4}, {N3, T1_4},
    {N5, T1_4}, {N6, T1_8}, {H1, T1_8}, {N6, T1_4}, {N5, T1_4}, {N3, T1_4},

    // 主歌A段
    {N5, T3_8}, {N5, T1_8}, {N6, T1_4}, {N5, T1_4}, {N3, T1_4}, // 狼牙月 伊人憔悴
    {N5, T3_8}, {N5, T1_8}, {N6, T1_4}, {N5, T1_4}, {N3, T1_4}, // 我举杯 饮尽了风雪
    {N2, T1_8}, {N3, T1_8}, {N5, T1_4}, {N3, T1_4}, {N2, T1_4},  // 是谁打翻前世柜
    {L6, T1_8}, {N1, T1_8}, {N2, T1_4}, {N3, T1_4}, {N2, T1_4},  // 惹尘埃是非

    // 副歌B段
    {N5, T1_2}, {N5, T1_8}, {N6, T1_8}, {N5, T1_4}, {N3, T1_4},  // 你发如雪 凄美了离别
    {N5, T1_2}, {N5, T1_8}, {N6, T1_8}, {N5, T1_4}, {N3, T1_4},  // 我焚香感动了谁
    {N2, T1_8}, {N3, T1_8}, {N5, T1_4}, {N3, T1_4}, {N2, T1_4},  // 邀明月 让回忆皎洁
    {L6, T1_8}, {N1, T1_8}, {N2, T1_4}, {N3, T1_4}, {N2, T1_4},  // 爱在月光下完美

    // 间奏(钢琴solo简化)
    {N5, T1_8}, {N6, T1_8}, {H1, T1_8}, {N6, T1_8}, {N5, T1_8}, {N3, T1_8}, {N5, T1_4},
    {N5, T1_8}, {N6, T1_8}, {H1, T1_8}, {N6, T1_8}, {N5, T1_8}, {N3, T1_8}, {N5, T1_4},

    // 主歌A'段
    {N5, T3_8}, {N5, T1_8}, {N6, T1_4}, {N5, T1_4}, {N3, T1_4}, // 啦儿啦 铜镜映无邪
    {N5, T3_8}, {N5, T1_8}, {N6, T1_4}, {N5, T1_4}, {N3, T1_4}, // 扎马尾 你若撒野
    {N2, T1_8}, {N3, T1_8}, {N5, T1_4}, {N3, T1_4}, {N2, T1_4},  // 今生我把酒奉陪
    {0, T1_4}, {L6, T1_8}, {N1, T1_8}, {N2, T1_4}, {N3, T1_4},   // 休止+尾奏衔接

    // 尾声
    {N2, T1_2}, {N3, T1_4}, {N5, T1_4}, {N3, T1_4}, {N2, T1_2},
    {H1, T1_2}, {N6, T1_2}, {N5, T1_2}, {END, 0}  // 结束句    
};

void Play_Music(void)
{
	uint16_t i = 0;
	while(1)
	{
		if(Music[i].freq == END) break;
		
		if(Music[i].freq == 0) 
		{
			TIM_Cmd(TIM2, DISABLE);
		}
		else 
		{
            TIM_Configuration(Music[i].freq);
            TIM_Cmd(TIM2, ENABLE);
        }
		Delay_ms(Music[i].duration);
		i++;
	}
	TIM_Cmd(TIM2, DISABLE);
}


主函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "BUZZER.h"
#include "MUSIC.h"
#include "KEY.h"

uint8_t KeyNum;

int main(void)
{
	KEY_Init();
	OLED_Init();
	RCC_Configuration();
	GPIO_Configuration();
	
	while(1)
	{
		Play_Music();
	}
}

你可能感兴趣的:(stm32,嵌入式硬件,单片机)