教你制作单片机音乐文件
作者:巩玉坤
QQ:420410977
打开乐谱编辑器
可以看到,此程序已经把文件框架写好啦,剩下的就是添加音符了。
注意下面几个部分:
上面标注了相应得简谱,不如先做个《八月桂花》的吧,下面是部分简谱:
看到第一音符是高音 1,八分音符加浮点,相当于一拍的 3/4,所以先点击
后点击
看到如下图
前面数组 0x18即高音 do的频率,后面 0x30即为该音符的节拍时长。下一个音符为十六分音符 6,先点
后点
如果你对音乐简谱不熟悉,好说,只要安下面方法
像 下面有双横线的 1/4拍
像 下面有单横线的 2/4拍
像 下面有单横线,后面又有点的 3/4拍
像 下面没横线的/1拍
像 后面有点的本来是 1拍半,即/1,加 2/4,但上面没有,可以用两个音符代替(不要求质量啦),
像 后面有短线的/2拍
OK,下面是点玩所有音符的数组,改一下单片机的端口,可以保存为 C 文件直接成为源程序,也可以在窗
口中选中复制粘贴到你的程序文件中。
以下是程序分析:
/*12Mhz晶振工作*/
#include
#define uint unsigned int
#define uchar unsigned char
sbit voice=P0^0; //定义输出端口
uchar code sound[]={
0xff, //开始标识
0x18,0x30,0x1c,0x10,//格式为: 频率常数, 节拍常数, 频率常数, 节拍常数,
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,
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)
{
zdjs=0;
dpjs++; yj=sound[dpjs]; //放入音阶
dpjs++; jp=sound[dpjs]; //放入节拍
while(zdjs!=jp)//判断节拍是否结束,若没结束继续执行
{
if(yj!=0xff)//音阶不等于开始标识
{
if(yj!=0)//音阶不等于结束标识
{
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代
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
音阶(频率数据),后面 sound[2]0x30代表节拍(延时数据),这个 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);//产生音阶频率
高低电平的时间延时由 del(yj)来确定,sound[1]0x18=24.在程序中仿真计算一下 del(250)的时间:
设置仿真环境的晶振
打开调试界面
先单条语句 运行到 del(250)
注意黄色箭头此时已经运行到 del(250)但这条还未运行,记录此时的时间是 0.00044900s(上图),
然后点 这样就直接越过 del(250)而不会跳到 del函数中,记录时间为 0.00646000s(下图)
计算差值再除以 250就可得到 del(1)约为 24.044us
那么 的音阶 sound[1]0x18=24,高低电平的延时为 24.044us*24=577.056us,则周期为 1154.112us,
对应频率为 1/1154.112us=866Hz
从音阶频率谱(如下)看出,其对应还不是很好呀,呵呵,有待改进!!
谢谢。