Ⅰ 这是一个利用89C52RC单片机蜂鸣器演奏生日快乐歌。请高手帮我解释一下:整体思想,再在每一步添加注释。
#include<reg51.h>
sbit speaker=P1^6;
unsigned char timer0h,timer0l,time;
//生日歌,这三个字节一组,分别定义:旋律(1234567)、高低音(低音、中音、高音)、节奏(长度)
code unsigned char sszymmh[]={5,1,1, 5,1,1, 6,1,2, 5,1,2, 1,2,2, 7,1,4,
5,1,1, 5,1,1, 6,1,2, 5,1,2, 2,2,2, 1,2,4,
5,1,1, 5,1,1, 5,2,2, 3,2,2, 1,2,2, 7,1,2, 6,1,2,
4,2,1, 4,2,1, 3,2,2, 1,2,2, 2,2,2, 1,2,4};
// 音阶频率表 高八位,也就是发音对应频率的高八位
code unsigned char FREQH[]={0xF2,0xF3,0xF5,0xF5,0xF6,0xF7,0xF8, 0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,0xFC, //1,2,3,4,5,6,7,8,i
0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,} ;
// 音阶频率表 低八位,也就是发音对应频率的低八位
code unsigned char FREQL[]={0x42,0xC1,0x17,0xB6,0xD0,0xD1,0xB6,0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,0x8F, //1,2,3,4,5,6,7,8,i
0xEE,0x44, 0x6B,0xB4,0xF4,0x2D,0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16, };
void delay(unsigned char t) //延时程序
{
unsigned char t1;
unsigned long t2;
for(t1=0;t1<t;t1++)
{
for(t2=0;t2<8000;t2++)
{ ; } }
TR0=0;
}
void t0int() interrupt 1 //定时器0中断服务程序,控制声音打频率
{ TR0=0;
speaker=!speaker;
TH0=timer0h;
TL0=timer0l;
TR0=1;
}
void song() //启动演奏当前频率
{ TH0=timer0h; //当前频率的高八位
TL0=timer0l; //当前频率的低八位
TR0=1; //启动定时器0
delay(time); //延时当前频率的演奏时间
}
void main(void)
{
unsigned char k,i;
TMOD=1; //置CT0定时工作方式1 EA=1; ET0=1;//IE=0x82 //CPU开中断,CT0开中断
while(1)
{
i=0;
while(i<75)
{ //音乐数组长度 ,唱完从头再来
k=sszymmh[i]+7*sszymmh[i+1]-1; //取当前节奏的频率地址
timer0h=FREQH[k]; //取当前频率高八位
timer0l=FREQL[k]; //取当前频率低八位
time=sszymmh[i+2]; //取当前频率的时长
i=i+3; //三个字节一组
song(); //演奏当前频率,共75/3,25个曲调。
}
}
}
//程序的设计思路就是将一首乐曲分成三个变量来控制,分别是曲调、所在音区、时长。而控制曲调的因素也就是频率又分成高八位和第八位两个表,每演奏一个曲调,就根据该曲调的三个变量来取值。
Ⅱ 如何编写51单片机音乐程序
设计的相关音乐说明
要产生音频脉冲,只要算出某一音频的周期(1/频率),然后将此周期除以2,即为半周期时间。利用半周期时间定时这个半周期时间,每当计时到后就将输出的I/O反向,然后重复计时此半周期再对I/O反向,就可以在I/O脚上得到此频率的脉冲。
记数脉冲值与频率的关系公式如:N=Fi/2/Fr。N:记数值;Fi:内部计时依次为1us,故其频率为1 MHZ;Fr:要产生的频率。
其记数值的求法如:T=65536-N=65536-Fi/2/Fr。例:设K=65536,F=1000000=Fi=1 MHZ。求低音DO(26HZ),中音DO(523HZ),高音DO(1046HZ)的记数值。
每个音符使用1个音节,字节的高四位代表音符的高低,低四位代表音符的节拍。如果1拍为0.4秒,1/4拍为0.1秒,假设1/4拍为 DELAY,则1拍为4 DELAY。
(2)生日快乐歌的51单片机音乐程序扩展阅读:
功能特性
1,可以仿真63K程序空间,接近64K 的16位地址空间;
2,可以仿真64Kxdata 空间,全部64K 的16位地址空间;
3,可以真实仿真全部32 条IO脚;
4,完全兼容keilC51 UV2 调试环境,可以通过UV2 环境进行单步,断点, 全速等操作;
5,可以使用C51语言或者ASM汇编语言进行调试 ;
6,可以非常方便地进行所有变量观察,包括鼠标取值观察,即鼠标放在某 变量上就会立即显示出它此的值;
7,可选 使用用户晶振,支持0-40MHZ晶振频率;
8,片上带有768字节的xdata,您可以在仿真时选 使用他们,进行xdata 的仿真;
9,可以仿真双DPTR 指针;
10,可以仿真去除ALE 信号输出. ;
11,自适应300-38400bps 的所有波特率通讯;
12,体积非常细小,非常方便插入到用户板中.插入时紧贴用户板,没有连接电缆,这样可以有效地减少运行中的干扰,避免仿真时出现莫名其妙的故障;
13,仿真插针采用优质镀金插针,可以有效地防止日久生锈,选择优质园脚IC插座,保护仿真插针,同时不会损坏目标板上的插座. ;
14,仿真时监控和用户代码分离,不可能产生不能仿真的软故障;
15,RS-232接口不计成本采用MAX202集成电路,串行通讯稳定可靠,绝非一般三极管的简易电路可比。
Ⅲ 求单片机LED灯闪烁生日快乐代码。谢谢
生日快乐歌曲C代码
/*******************************************/
#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit beep = P1^5;
uchar code SONG_TONE[]={212,212,190,212,159,169,212,212,190,212,142,159,
212,212,106,126,159,169,190,119,119,126,159,142,159,0};
uchar code SONG_LONG[]={9,3,12,12,12,24,9,3,12,12,12,24,
9,3,12,12,12,12,12,9,3,12,12,12,24,0};
//延时
void DelayMS(uint x)
{
uchar t;
while(x--) for(t=0;t<120;t++);
}
void PlayMusic()
{
uint i=0,j,k;
while(SONG_LONG[i]!=0||SONG_TONE[i]!=0)
{ //播放各个音符,SONG_LONG 为拍子长度
for(j=0;j<SONG_LONG[i]*20;j++)
{
beep=~beep;
//SONG_TONE 延时表决定了每个音符的频率
for(k=0;k<SONG_TONE[i]/3;k++);
}
DelayMS(10);
i++;
}
}
void main()
{
beep=0;
while(1)
{
PlayMusic(); //播放生日快乐
DelayMS(500); //播放完后暂停一段时间
}
}
Ⅳ 单片机怎么实现演奏两首歌(生日快乐+两只老虎) 汇编语言
;音乐生日快乐的播放
numtim equ 20h
EQUei equ 21h
EQUwei equ 22h
EQUnled equ 23h
EQU 000hORGp startJMPg 00bh
jORGtim0
oJMP100h
ORGart:; JB P3.7,$ ;检测播放按键是否按下
mov tmod,#00000001b
MOV mov ie,#10000010b
MOV mov numtim,#01h
startMOVov 30h,#00h
nextMOVv a,30h
mov MOVr,#table
MOVovc a,@a+dptr
mov r2,a
jz eMOV
anl aJZ0fh
mov r5,a
mov aMOV
swap MOV anl a,#0fh
jnz sing
clr tJNZ
jmp d1
sing: dec aJMP mov 22h,DEC rl aMOV mov dptr,#table1
MOVmovc a,@a+dptr
mov th0,a
mov MOV,a
mov MOV2h
rl aMOV inc a
movc a,@INCptr
mov tl0,a
mov MOV,a
setbMOV0
d1:lcall delay
inc 30h
jmp neINC
end0:clr JMP
jmp start0
tim0:puJMPacc
pushPUSH
mov PUSH2PSW
MOV th0,21h
MOV p1.6 ;由该口输出音频数据
pop psw
pop acc
POPrPSW
dPOPy: mov r7,#02h
d2: mov r4,#1MOV
d3: mov r3,#MOV
djnz r3,MOV djnz r4,d3
djnz r7,d2
djnz r5,delay
ret
table1: RET ;音乐码表
dw 64260,64400,64524,64580
DW dw 64684,64777,64820,64898
DW dw 64968,65030,65058,65110
DW dw 65157,65178,65217
table:dDW82h,01h,81h,94h,84h
DB 0b4h,0a4h,04h
db 82hDB1h,81h,94h,84h
DB 0c4h,0b4h,04h
db 8DB,01h,81h,0f4h,0d4h
DBdb 0b4h,0a4h,94h
db 0e2DB01h,0e1h,0d4h,0b4h
DB db 0c4h,0b4h,04h
db 8DB,01h,81h,94h,84h
DB 0b4h,0a4h,04h
db 82hDB1h,81h,94h,84h
DB 0c4h,0b4h,04h
db 8DB,01h,81h,0f4h,0d4h
DBdb 0b4h,0a4h,94h
db 0e2DB01h,0e1h,0d4h,0b4h
DB db 0c4h,0b4h,04h
db 00DB
TABLE2:DB 0C0H,0F9H,DB4H,0B0H,99H,92H,8DB,0F8H,80H,90H
end
END
我只有生日快乐的程序,希望对你有帮助,从我这个程序你了解了原理,你就可以随意搞了,玩熟悉了就简单了!
Ⅳ 求: 用51单片机c语言操作使蜂鸣器奏出“祝你生日快乐”音乐的全部程序!
#include <REGX51.H>
unsigned char num1=0;
unsigned char num2=0;
//sbit P34 = P3^4; //定义用来软件复位
//**************************************************************************
#define SYSTEM_OSC 12000000//11059200// //定义晶振频率12000000HZ
#define SOUND_SPACE 4/5 //定义普通音符演奏的长度分率,//每4分音符间隔
//sbit BeepIO = P3^4; //定义输出管脚
sbit BeepIO = P1^5; //定义输出管脚
unsigned int code FreTab[12] = { 262,277,294,311,330,349,369,392,415,440,466,494 }; //原始频率表
unsigned char code SignTab[7] = { 0,2,4,5,7,9,11 }; //1~7在频率表中的位置
unsigned char code LengthTab[7]= { 1,2,4,8,16,32,64 };
unsigned char code led[8]= { 0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01 };
unsigned char Sound_Temp_TH0,Sound_Temp_TL0; //音符定时器初值暂存
unsigned char Sound_Temp_TH1,Sound_Temp_TL1; //音长定时器初值暂存
//**************************************************************************
//生日快乐
unsigned char code Music_birth[]={ 0x0F,0x03, 0x0F,0x03, 0x10,0x02, 0x0F,0x02, 0x15,0x02,
0x11,0x01, 0x0F,0x02, 0x0F,0x02, 0x10,0x02, 0x0F,0x02,
0x16,0x02, 0x15,0x01, 0x0F,0x03, 0x0F,0x03, 0x19,0x02,
0x17,0x02, 0x15,0x02, 0x11,0x0C, 0x10,0x02, 0x18,0x03,
0x18,0x03, 0x17,0x02, 0x15,0x02, 0x16,0x02, 0x15,0x0B,
0x00,0x00 };
void InitialSound(void)
{
BeepIO = 1;
Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256; // 计算TL1应装入的初值 (10ms的初装值)
Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256; // 计算TH1应装入的初值
TH1 = Sound_Temp_TH1;
TL1 = Sound_Temp_TL1;
TMOD |= 0x11; //两个定时器都工作在16位计数/计时器模式
ET0 = 1;
ET1 = 0;
TR0 = 0;
TR1 = 0;
EA = 1;
}
void BeepTimer0(void) interrupt 1 using 1 //音符发生中断
{
BeepIO = !BeepIO;
TH0 = Sound_Temp_TH0;
TL0 = Sound_Temp_TL0;
}
//**************************************************************************
void Play(unsigned char *Sound,unsigned char Signature,unsigned Octachord,unsigned int Speed)
{
unsigned int NewFreTab[12]; //新的频率表
unsigned char i,j,k,l;
unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD;
for(i=0;i<12;i++) // 根据调号及升降八度来生成新的频率表
{
j = i + Signature;
if(j > 11)
{
j = j-12;
NewFreTab[i] = FreTab[j]*2;
}
else
NewFreTab[i] = FreTab[j];
if(Octachord == 1)
NewFreTab[i]>>=2;
else if(Octachord == 3)
NewFreTab[i]<<=2;
}
SoundLength = 0;
while(Sound[SoundLength] != 0x00) //计算歌曲长度
{
SoundLength+=2;
}
Point = 0;
Tone = Sound[Point];
Length = Sound[Point+1]; // 读出第一个音符和它时时值
LDiv0 = 12000/Speed; // 算出1分音符的长度(几个10ms)
LDiv4 = LDiv0/4; // 算出4分音符的长度
LDiv4 = LDiv4-LDiv4*SOUND_SPACE; // 普通音最长间隔标准
TR0 = 0;
TR1 = 1;
while(Point < SoundLength)
{
SL=Tone%10; //计算出音符
SM=Tone/10%10; //计算出高低音
SH=Tone/100; //计算出是否升半
CurrentFre = NewFreTab[SignTab[SL-1]+SH]; //查出对应音符的频率
if(SL!=0)
{
if (SM==1) CurrentFre >>= 2; //低音
if (SM==3) CurrentFre <<= 2; //高音
Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//计算计数器初值
Sound_Temp_TH0 = Temp_T/256;
Sound_Temp_TL0 = Temp_T%256;
TH0 = Sound_Temp_TH0;
TL0 = Sound_Temp_TL0 + 12; //加12是对中断延时的补偿
//音乐彩灯的闪烁
k=l;
k=Temp_T%8;
if(k==l) k=k+2;
P0=led[k];
}
SLen=LengthTab[Length%10]; //算出是几分音符
XG=Length/10%10; //算出音符类型(0普通1连音2顿音)
FD=Length/100;
LDiv=LDiv0/SLen; //算出连音音符演奏的长度(多少个10ms)
if (FD==1)
LDiv=LDiv+LDiv/2;
if(XG!=1)
if(XG==0) //算出普通音符的演奏长度
if (SLen<=4)
LDiv1=LDiv-LDiv4;
else
LDiv1=LDiv*SOUND_SPACE;
else
LDiv1=LDiv/2; //算出顿音的演奏长度
else
LDiv1=LDiv;
if(SL==0) LDiv1=0;
LDiv2=LDiv-LDiv1; //算出不发音的长度
if (SL!=0)
{
TR0=1;
for(i=LDiv1;i>0;i--) //发规定长度的音
{
while(TF1==0);
TH1 = Sound_Temp_TH1;
TL1 = Sound_Temp_TL1;
TF1=0;
}
}
if(LDiv2!=0)
{
TR0=0; BeepIO=1;
for(i=LDiv2;i>0;i--) //音符间的间隔
{
while(TF1==0);
TH1 = Sound_Temp_TH1;
TL1 = Sound_Temp_TL1;
TF1=0;
}
}
Point+=2;
Tone=Sound[Point];
Length=Sound[Point+1];
}
BeepIO = 1;
}
//**************************************************************************
void delay() //为了显示的延迟
{
unsigned int j;
// for (i=0;i<50;i++)
for (j=0;j<30;j++);
}
void main()
{
IT0=1; IT1=1; //外部中断下降沿触发
EX0=1;EX1=1;
EA=1; //开总中断
InitialSound();
Play(Music_birth,4,2,300);
}