STM32歌唱《孤勇者》(标准库)

您所在的位置:网站首页 播放歌曲雇佣者歌词 STM32歌唱《孤勇者》(标准库)

STM32歌唱《孤勇者》(标准库)

2024-07-17 08:21| 来源: 网络整理| 查看: 265

        先说一下自己玩两年的单片机的想法吧,玩了大概有两年了,从刚刚开始的不知所措,到现在的成熟,终于还是搞明白了一件事,编程思路,远远比源码更重要,所以,我接下来会给大家完整的介绍,完成此项目的心得,太心酸了。最后也会把main函数里面完整的代码粘出来。

        此项目是哔哩哔哩上面看到的一个小玩意,B站上面的利用的51单片机,而我移植他们的一部分程序,加载到32单片机上了。

        实验现象:

https://www.bilibili.com/video/BV1j34y1W7RU/?vd_source=f6d73e725f237ac544554b57b2c58f16

        首先,有一块带无源蜂鸣器的板子,一定是无源蜂鸣器,无源蜂鸣器,会根据加载不同频率的信号,发出不同的声音。

        然后,就是乐理知识,每一个音符的频率大小是多少,我也找出来了,这里有低音、中音、高音三种。最基础也就7个:哆来咪发唆啦西;但是这里面又多出来带#号的音符:例:低音4#:表示,比音调4高半个音,比音调5低半个音,就记住比前一个高,比后一个低就行了,咱们有不学音乐,大致了解就行了。

        还有就是对于音调的区分:在简谱中,不带点的基本符号叫做中音;在基本符号上面加上一个点叫高音;加两个点叫倍高音;加三个点叫超高音;在基本符号下面加一个点叫低音;加两个点叫倍低音;加三个点叫超低音。

        高音的音乐很少很少,而且《孤勇者》也没有用到高音,所以在程序中定义一个数组来存放这些基础音调的频率,我们演奏的歌曲的时候,需要哪个,直接调用,就可以完成曲子了。

基础符号后面的点表示的意思:

        那个点是附点,他的时值是他前面时值的一半。也就是说。如果附点前面音符是一拍,那么那个附点就是半拍。如果前面音符是2拍,那附点就是一拍时值。如果前面是四拍的音符,那附点就是2拍。如果附点前面时值是半拍,那么附点就是四分之一拍。

        基础音符的频率用一个数组来表示出来。有低音,中音,高音。大部分歌曲都是有这三种音符组成,大家也可以找一下别的歌曲的频率和音符。

我的程序中定义数组:

unsigned int music_table[] = { 130,139,147,156,165,175,185,196,208,220,233,247, //0-11 超低音 262,277,294,311,329,349,370,392,415,440,466,494, //12-23 低音,正常音符下面有一个点 523,554,587,622,659,698,740,784,830,880,932,988, //24-35 中音,正常音符 0, //0:不发声音,停止播放,在音乐中叫休止符 1046,1109,1175,1245,1319,1397,1480,1568,1661,1760,1865,1976// 高音,正常音符上面有一个点 };

         先解释,数组中数据怎么演奏出来吧,定义了两个数组,第一个数组表示基础音符的频率,第二个数组存放《孤勇者》乐谱的频率组合所对应第一个数组的地址。利用数组嵌套的方式去调用。

j=music_table[music[x]];

         最基础的源码贴出来了,该拿出来,《孤勇者》的乐谱了,我也找了出来;演奏的是我用红色框起来的那段高潮部分,我也用一个数组来保存这段乐谱:

有人看见就蒙圈了:我来解释一下数组里面数据什么意思;下面还有一个宏定义,来表示这些数据

B6N:表示音符6的低音;

B6H:表示音符6的高音;

36:表示第一个数组的第36的数据0;也就是刚刚上面代码中的休止符,表示停顿。

unsigned char music[] = { B6N,B7N,B1H,B2H,B7N,B1H,B1H,36, //爱 你 孤 身 走 暗 巷 B1H,B7N,B1H,B2H,B7N,B1H,B1H,36, //爱 你 不 跪 的 模 样 B1H,B2H,B3H,B2H,B3H,B2H,B3H,36, //爱 你 对 峙 过 绝 望 B3H,B2H,B3H,36,B5H,B5H,B3H,36, //不 肯 哭 一 场 B6N,B7N,B1H,B2H,B7N,B1H,B1H,36, //爱 你 破 烂 的 衣 裳 B1H,B7N,B1H,B2H,B7N,B1H,B1H,36, //却 敢 赌 命 运 的 枪 B1H,B2H,B3H,B2H,B3H,B2H,B3H,36, //爱 你 和 我 那 么 像 B3H,B2H,B3H,36,B5H,B5H,B3H,36,36, //缺 口 都 一 样 B5H,B3H,B3H,36,36,B5H,B3H,36,36, //去 吗 配 吗 B5H,B3H,B5H,B6H,B3H,B5H,36, //这 褴 褛 的 披 风 B5H,B3H,B5H,B3H, 36, //战 马 斩 啊 B5H,B3H,B5H,B6H,B3H,B5H,36, //以 最 卑 微 的 梦 B5H,B5H,B3H,B2H,B2H,B2H,B1H,B3H,B3H,B2H,B2H,B2H,B1H,B1H,B6N,36,36, //掷 那 黑 夜 中 的 呜 咽 与 怒 吼 B5H,B5H,B3H,B2H,B2H,B2H,B1H,B3H,B3H,B2H,B2H,B2H,B1H,B1H,B6N,36, //谁 说 站 在 光 里 的 才 算 英 雄 };

还有一个宏定义:

#define B6N 19 #define B7N 21 #define B1H 23 #define B2H 24 #define B3H 26 #define B4H 28 #define B5H 29 #define B6H 31

《孤勇者》对应的音符组合,每个音符的频率在第一个数组的位置。

接下来就是控制频率了,频率就是在一秒钟跳变了几次,所以我就直接利用延迟函数,来控制每次跳变的时间,也就是周期的一半:

j:表示频率,控制每个音符持续多长时间,控制每的音符的周期

i:也表示频率,控制while(i--)控制周期  delay_us(500000/j):1/262等于周期T(s),换成一半周期的,单位us的周期  

i=j*0.6;//半节拍(控制每个音符持续多少时间) while(i--)//控制周期(1s跳变多少次) { GPIO_Trgger(); delay_us(500000/j);// 1/262等于周期T(s),换成一半周期的,单位us的周期 }

 main函数的程序:没有多少新东西,就是那个时间控制的有点微妙,多看几遍;

#include "stm32f10x.h" #include "SysTick.h" #include "usart.h" #include "gpio.h" #define B6N 19 #define B7N 21 #define B1H 23 #define B2H 24 #define B3H 26 #define B4H 28 #define B5H 29 #define B6H 31 unsigned int music_table[] = {130,139,147,156,165,175,185,196,208,220,233,247,//0-11半音 262,277,294,311,329,349,370,392,415,440,466,494,//12-23 低音 523,554,587,622,659,698,740,784,830,880,932,988,0};//24-35 中音 unsigned char music[] = {B6N,B7N,B1H,B2H,B7N,B1H,B1H,36, //爱 你 孤 身 走 暗 巷 B1H,B7N,B1H,B2H,B7N,B1H,B1H,36, //爱 你 不 跪 的 模 样 B1H,B2H,B3H,B2H,B3H,B2H,B3H,36, //爱 你 对 峙 过 绝 望 B3H,B2H,B3H,36,B5H,B5H,B3H,36, //不 肯 哭 一 场 B6N,B7N,B1H,B2H,B7N,B1H,B1H,36, //爱 你 破 烂 的 衣 裳 B1H,B7N,B1H,B2H,B7N,B1H,B1H,36, //却 敢 赌 命 运 的 枪 B1H,B2H,B3H,B2H,B3H,B2H,B3H,36, //爱 你 和 我 那 么 像 B3H,B2H,B3H,36,B5H,B5H,B3H,36,36, //缺 口 都 一 样 B5H,B3H,B3H,36,36,B5H,B3H,36,36, //去 吗 配 吗 B5H,B3H,B5H,B6H,B3H,B5H,36, //这 褴 褛 的 披 风 B5H,B3H,B5H,B3H, 36, //战 马 斩 啊 B5H,B3H,B5H,B6H,B3H,B5H,36, //以 最 卑 微 的 梦 B5H,B5H,B3H,B2H,B2H,B2H,B1H,B3H,B3H,B2H,B2H,B2H,B1H,B1H,B6N,36,36, //掷 那 黑 夜 中 的 呜 咽 与 怒 吼 B5H,B5H,B3H,B2H,B2H,B2H,B1H,B3H,B3H,B2H,B2H,B2H,B1H,B1H,B6N,36, //谁 说 站 在 光 里 的 才 算 英 雄 }; int main(void) { uint16_t i=0,j=0; unsigned int x=0,endx=0; My_USART_Init(); SysTick_Init(72); My_GPIOInit(); endx = sizeof(music); while(1) { j=music_table[music[x]]; i=j*0.6;//半节拍(控制每个音符持续多少时间) while(i--)//控制周期(1s跳变多少次) { GPIO_Trgger(); delay_us(500000/j);// 1/262等于周期T(s),换成一半周期的,单位us的周期 } if(j==0)//休止符 { delay_ms(200); GPIO_Trgger_JQD(); } x++; if(x>=endx)x=0; } }



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3