教你制作单片机音乐文件
- 格式:pdf
- 大小:946.81 KB
- 文档页数:11
谢谢。
我们来算一下频率,程序中 voice=!voice;del(yj);//产生音阶频率 高低电平的时间延时由 del(yj)来确定,sound[1]0x18=24.在程序中仿真计算一下 del(250)的时间:
设置仿真环境的晶振 打开调试界面
先单条语句 运行到 del(250)
注意黄色箭头此时已经运行到 del(250)但这条还未运行,记录此时的时间是 0.00044900s(上图), 然后点 这样就直接越过 del(250)而不会跳到 del 函数中,记录时间为 0.00646000s(下图)
教你制作单片机音乐文件 作者:巩玉坤 QQ:420410977
打开乐谱编辑器
可以看到,此程序已经把文件框架写好啦,剩下的就是添加音符了。 注意下面几个部分:
上面标注了相应得简谱,不如先做个《八月桂花》的吧,下面是部分简谱:
看到第一音符是高音 1,八分音符加浮点,相当于一拍的 3/4,所以先点击 后点击
我们来算一下时间,0x30=48,即要产生 48 次时间中断使 zdjs 的值为 48,使 while(zdjs!=jp)不成立推出 循环,此时该音符停止进行下一个音符,该音符时间长度为 10.001ms*48=480.048ms。由音乐常识知音乐进 行时每分钟 120 拍,480.048ms*120=57.60576s,大约是一分钟
voice=!voice;del(yj);//产生音阶频率 } else //如果结束标识,则数组计数从头开始 {
dpjs=0; break; } } voice=0; del(jp); } } } time0() interrupt 1 using 1 //使用定时器中断 1 { TH0=0xd8, TL0=0xef; zdjs++; }
中断时间计算:TH0=0xd8, TL0=0xef;对应的十进制数为(1101 1000 1110 1111=55535) (2^16-55535)*(12/12Mhz)=10001*1us=10.001ms 即每 10.001ms 产生一次中断,将 zdjs 自加一次
以例程中数组 sound[]中的 sound[1]0x18,sound[2]0x30,来分析,知道他是简谱中的第一个音符 ,前面 sound[1]0x18 代表音阶(频率数据),后面 sound[2]0x30 代表节拍(延时数据),这个 3/4 拍数据
看到如下图
前面数组 0x18 即高音 do 的频率,后面 0x30 即为该音符的节拍时长。下一个音符为十六分音符 6,先点 后点
如果你对音乐简谱不熟悉,好说,只要安下面方法 像 下面有双横线的 1/4 拍 像 下面有单横线的 2/4 拍 像 下面有单横线,后面又有点的 3/4 拍 像 下面没横线的/1 拍
0x20,0x40,0x1c,0x10,
0x18,0x10,0x20,0x10,
0x1c,0x10,0x18,0x40,
0x1c,0x20,0x20,0x20,
0x1c,0x20,0x18,0x20,
0x20,0x80,0x20,0x30,
0x1c,0x10,0x18,0x20,
0x15,0x20,0x1c,0x20,
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit voice=P0^0; //定义输出端口
uchar code sound[]={
0xff,
//开始标识
0x18,0x30,0x1c,0x10,//格式为: 频率常数, 节拍常数, 频率常数, 节拍常数,
计算差值再除以 250 就可得到 del(1)约为 24.044us
那么 的音阶 sound[1]0x18=24,高低电平的延时为 24.044us*24=577.056us,则周期为 1154.112us, 对应频率为 1/1154.112us=866Hz
从音阶频率谱(如下)看出,其对应还不是很好4,但上面没有,可以用两个音符代替(不要求质量啦),
像
后面有短线的/2 拍
OK,下面是点玩所有音符的数组,改一下单片机的端口,可以保存为 C 文件直接成为源程序,也可以在窗 口中选中复制粘贴到你的程序文件中。
以下是程序分析:
/*12Mhz 晶振工作*/
zdjs=0; dpjs++; yj=sound[dpjs]; //放入音阶 dpjs++; jp=sound[dpjs]; //放入节拍 while(zdjs!=jp)//判断节拍是否结束,若没结束继续执行 {
if(yj!=0xff)//音阶不等于开始标识 {
if(yj!=0)//音阶不等于结束标识 {
0x20,0x20,0x26,0x40,
0x20,0x20,0x2b,0x20,
0x26,0x20,0x20,0x20,
0x30,0x80,0x20,0x20,
0x1c,0x10,0x18,0x10,
0x20,0x20,0x26,0x20,
0x2b,0x20,0x30,0x20,
0x2b,0x40,0x20,0x20, 0x1c,0x10,0x18,0x10, 0x20,0x20,0x26,0x20, 0x2b,0x20,0x30,0x20, 0x2b,0x40,0x20,0x30, 0x1c,0x10,0x18,0x20, 0x15,0x20,0x1c,0x20, 0x20,0x20,0x26,0x40, 0x20,0x20,0x2b,0x20, 0x26,0x20,0x20,0x20, 0x18,0x80,0x20,0x30, 0x1c,0x10,0x18,0x20, 0x15,0x20,0x1c,0x20, 0x20,0x20,0x26,0x40, 0x13,0x20,0x13,0x40, 0x18,0x20,0x15,0x40, 0x13,0x40,0x18,0x80, 0x00, //结束标识
}; uchar zdjs=0, jp;//结束标识 节拍 //延时函数 del(yj)//最好写成 void del(uchar yj) {
uchar yj2=2; while(yj!=0) {
while(yj2!=0) {
yj2--; } yj2=2; yj--; } } //主函数 void main(void) { uint dpjs=0;//标识数组中第几个数 uchar yj; //音阶 TMOD=0x01,IE=0x82;//定时器 T0 工作在方式 1,允许 T0 溢出中断并打开总中断 TH0=0xd8, TL0=0xef;//10.001ms 产生一次中断 TR0=1;//启动定时器 while(1) {