STM32-PWM驱动无源蜂鸣器播放周杰伦的《发如雪》
创作时间:
作者:
@小白创作中心
STM32-PWM驱动无源蜂鸣器播放周杰伦的《发如雪》
引用
CSDN
1.
https://blog.csdn.net/weixin_45651178/article/details/146080287
本文将介绍如何使用STM32微控制器驱动无源蜂鸣器播放周杰伦的《发如雪》。文章将详细讲解音符频率对照表、GPIO和TIM初始化、音乐模块以及主函数的实现。
C调音符与频率对照表
// 音符频率对照表(单位: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 // 结束标志
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();
}
}
热门推荐
单利复利的计算方法有何不同?这些不同对财务规划有何影响?
新手必读:购买紫砂壶的方法与避坑指南
时钟如何驱动CPU工作?从基础原理到性能优化的全面解析
为什么有些企业更倾向于使用外包而不是劳务派遣?
如何表示歉意?提供有效道歉的技巧与建议
寒山湖旅游全攻略:景点、路线与美食一网打尽
女性健身饮食一周食谱
张馨予:风情万种背后的生活哲学与蜕变之旅
孩子叛逆暴力有什么特征及如何处理?
创业企业融资难的原因
每天要吃多少水果?补多少维C?很多人都没做到
智慧教育平台助力初中历史教学:以甲午中日战争为例
蛇皮果的营养价值,蛇皮果怎么吃,蛇皮果的吃法
武汉百年老街重焕新生 成文化打卡新地标
Excel排班表怎么自动生成
Excel自动化值班表:公式、VBA宏、模板等实用技巧
《彩虹六号围攻》全干员特点与技能详解及战术思路
三国杀提升好感度的最快方法是什么?
世界口腔健康日 | 乳牙很重要!别忽视宝宝的“小牙齿”
租房电费不合理?一文帮你维权
营收净利双降,中国中免加速境外扩张寻增量
人民币大消息!内地和香港监管机构宣布六项措施 深化两地金融市场互联互通
贴近大自然的蔬食盛宴!台东蔬食餐厅"舒食男孩"如何善用在地食材与当季蔬果?
开发商给的赔偿不满意怎么办
铃兰的养殖方法和注意事项
如何推动科技板块的发展与创新?这种发展与创新对经济增长有何作用?
如何提升白酒香味:传统工艺与现代科技的完美结合
阿森纳争冠希望渺茫,5年8亿投入却难挽颓势,阿尔特塔去留成疑
如何合理规划公积金还款计划?这些还款策略的优缺点有哪些?
远程服务器返回错误403怎么解决?