PWM用定时器0作时钟源可改变频率,用于输出音符频率,占空比输出音符音长
电路图:
BUZZ.C
/*
* 文 件 名:BUZZ.C
* 芯 片:STC12C5A60S2
* 晶 振:12MHz
* 创 建 者:冷月
* 创建日期:2010.9.1
* 修 改 者:
* 修改日期:
* 功能描述:利用STC单片机的PWM使蜂呜器演奏乐曲
* PWM用定时器0作时钟源可改变频率,用于输出音符频率,占空比输出音符音长
*/
#include <STC12C5A.H>
#include <string.h>
#include "Delay.h"
#include "PCA.H"
#include "Music.h"
#include "key.h"
#define uchar unsigned char
#define uint unsigned int
//低音频率音符表,中音=低音*2,高音=低音*4
uint code lowSoundFreTab[12] =
{
262,
277,
293,
311,
329,
349,
370,
392,
415,
440,
466,
494,
};
//标准音符在频率音符表位置,freTabXY[0]不用,
uchar freTabXY[8] =
{
0, 0, 2, 4, 5, 7, 9, 11,
};
//几分音符 = 2^n,n为数组下标
uchar noteLenTab[7] =
{
1, 2, 4, 8, 16, 32, 64,
};
//根据演奏调号和演奏音区生成新的频率音符表
uint newSoundFreTab[12];
//一分音符的音长约为160ms
#define ONE_NOTE_LEN 160
//四分音符的音长约为
#define FOUR_NOTE_LEN ONE_NOTE_LEN/4
//函数原型申明
void PlayMusic(uchar *music, uchar startFre, uchar upDownTone);
void CreatNewFreTab(uchar startFre, uchar upDownTone);
uint GetTone(uchar tone);
uint Getlen(uchar noteLen, uint *length);
/*
* 函 数 名:main
* 功能描述:程序入口
* 输入参数:无
* 返 回 值:无
*/
void main(void)
{
InitTimer1();
PCA_Init(1, PWM, 0x80, 0x80, CLK2);
InitTimer0();
while (1)
{
switch (theMusic)
{
case 0:
PlayMusic(laoHu, 3, 0);
break;
case 1:
PlayMusic(girl, 0, 0);
break;
case 2:
PlayMusic(sameSong, 0, 0);
break;
case 3:
PlayMusic(twoButterfly, 0, 0);
break;
case 4:
PlayMusic(qiuTian, 7, 0);
break;
case 5:
PlayMusic(lvHua, 2, 0);
break;
case 6:
PlayMusic(woHeNi, 2, 0);
break;
case 7:
PlayMusic(xingYue, 4, 0);
break;
case 8:
PlayMusic(juHua, 7, 0);
break;
}
DelayMs1T(1000);
}
}
/*
* 函 数 名:PlayMusic
* 功能描述:播放一首歌曲
* 输入参数:music:歌曲数组
* startFre:起始调,0~11;
* upDownTone:升降调,1-降8度,2-不变,3-升8度
* 返 回 值:无
*/
void PlayMusic(uchar *music, uchar startFre, uchar upDownTone)
{
uint musicPos = 0; //当前播放歌曲位置
uint musicLen = 0; //歌曲长度
uint fre; //音符频率
uint length; //音符长度
uint len1; //音符发音时长
uint len2; //音符不发音时长
uchar i;
CreatNewFreTab(startFre, upDownTone);
while (music[musicLen] != 0) //计算歌曲长度,即有多少音符
{
musicLen += 2;
}
while (musicPos < musicLen)
{
fre = GetTone(music[musicPos]); //音符频率
len1 = Getlen(music[musicPos+1], &length); //音符发音时长
len2 = length - len1; //音符不发音时长
Set_PWM_Fre(fre);
Set_PWM1(50); //发音
for (i=0; i<len1; i++)
{
DelayMs1T(10);
}
Set_PWM1(0); //不发音
for (i=0; i<len2; i++)
{
DelayMs1T(10);
}
musicPos += 2; //指向下一个音符
if (keyFlag == 1) //有按键按下
{
keyFlag = 0;
return;
}
}
}
/*
* 函 数 名:CreatNewFreTab
* 功能描述:根据演奏调号和演奏音区生成新的频率音符表
* 输入参数:startFre:起始调,0~11;
* upDownTone:升降调,1-降8度,2-不变,3-升8度
* 返 回 值:无
*/
void CreatNewFreTab(uchar startFre, uchar upDownTone)
{
uchar i, j;
for (i=0; i<12; i++)
{
j = i + startFre;
if (j < 12)
{
newSoundFreTab = lowSoundFreTab[j];
}
else
{
j = j - 12;
newSoundFreTab = lowSoundFreTab[j] * 2;
}
if (upDownTone == 1)
{
newSoundFreTab >>= 1; //频率减半
}
else if (upDownTone == 3)
{
newSoundFreTab <<= 1; //频率加倍
}
}
}
/*
* 函 数 名:GetTone
* 功能描述:获取音符频率
* 输入参数:tone:音符音调
* 返 回 值:fre:音符频率
*/
uint GetTone(uchar tone)
{
uint fre;
uchar thirdTone; //音调百位,0-不升半音,1-升半音
uchar secondTone; //音调十位,1-低音,2-中音,3-高音
uchar firstTone; //音调个位,音符,1~7
thirdTone = tone / 100;
secondTone = tone /10 %10;
firstTone = tone % 10;
fre = newSoundFreTab[ freTabXY[firstTone]+thirdTone ];
switch (secondTone)
{
case 2:
fre <<= 1; //中音 = 低音×2
break;
case 3:
fre <<= 2; //高音 = 低音×4
break;
}
return fre;
}
/*
* 函 数 名:Getlen
* 功能描述:获取音符发音时长
* 输入参数:noteLen:音符音长
* lengh:连音音符演奏的长度
* 返 回 值:len1:发音时长
*/
uint Getlen(uchar noteLen, uint *length)
{
uint len1; //音符发音时长
uint blankLen; //普通音最长间隔标准
uchar thirdNote; //音长百位,0-无符点,1-有符点
uchar secondNote; //音长十位,0-普通,1-连音,2-顿音
uchar firstNote; //音长个位,几分音符
thirdNote = noteLen / 100;
secondNote = noteLen / 10 % 10;
firstNote = noteLen % 10;
blankLen = FOUR_NOTE_LEN * 1/5;
(*length) = ONE_NOTE_LEN / noteLenTab[firstNote]; //连音音符演奏的长度
if (thirdNote == 1) //符点:演奏长度是原长度的1.5倍
{
(*length) += 3/2;
}
if (secondNote == 0) //普通音符的演奏长度
{
if (noteLenTab[firstNote] < 4) //小于16分音符时发音长度
{
len1 = (*length) - blankLen;
}
else //大于16分音符时发音长度
{
len1 = (*length) * 4/5;
}
}
else if (thirdNote == 2) //顿音,演奏长度是原长度的1半
{
len1 = (*length) / 2;
}
else //连音,演奏时不需要停顿直接到下一个音符
{
len1 = (*length);
}
return len1;
}
乐谱数据在Music.h:
用户1205822 2012-8-24 14:42
用户230358 2010-11-27 23:39
用户967537 2010-11-23 18:53