如何编写51单片机音乐程序

如何编写51单片机音乐程序,第1张

设计的相关音乐说明

要产生音频脉冲,只要算出某一音频的周期(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。

扩展资料

功能特性

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集成电路,串行通讯稳定可靠,绝非一般三极管的简易电路可比。

参考资料来源:百度百科-51单片机

#define uchar unsigned char //定义一下方局皮便使用

#define uint unsigned int

#define ulong unsigned long

#include <reg52.h>//包括一个52标准内核的头文件

char code dx516[3] _at_ 0x003b//这是为了仿真设置的

sbitBEEP=P1^7//喇叭输出脚

sbit P10=P1^0

sbit K1= P3^2

sbit K2= P3^5

sbit K3= P2^4

sbit K4= P2^5

uchar th0_f//在中断中装载的T0的值高8位

uchar tl0_f//在中断中装载的T0的值低8位

//T0的值,及输出频率对照表

uchar code freq[36*2]={

0xA9,0xEF,//00220HZ ,1 //0

0x93,0xF0,//00233HZ ,1#

0x73,0xF1,//00247HZ ,2

0x49,0xF2,//00262HZ ,2#

0x07,0xF3,//00277HZ ,3

0xC8,0xF3,//00294HZ ,4

0x73,0xF4,//00311HZ ,4#

0x1E,0xF5,//00330HZ ,5

0xB6,0xF5,//00349HZ ,5#

0x4C,0xF6,//00370HZ ,6

0xD7,0xF6,//00392HZ ,6#

0x5A,0xF7,//00415HZ ,7

0xD8,0xF7,//00440HZ 1 //12

0x4D,0xF8,//00466HZ 1#//13

0xBD,0xF8,//00494HZ 2 //14

0x24,0xF9,//00523HZ 2#//15

0x87,0xF9,//00554HZ 3 //16

0xE4,0xF9,//00587HZ 4 //17

0x3D,0xFA,//00622HZ 4#//18

0x90,0xFA,//00659HZ 5 //19

0xDE,0xFA,//00698HZ 5#//20

0x29,0xFB,//00740HZ 6 //21

0x6F,0xFB,//00784HZ 6#//22

0xB1,0xFB,//00831HZ 7 //23

0xEF,0xFB,//00880HZ `1

0x2A,0xFC,//00932HZ `1#

0x62,0xFC,//00988HZ `2

0x95,0xFC,//01046HZ `2#

0xC7,0xFC,//01109HZ `3

0xF6,0xFC,//01175HZ `4

0x22,0xFD,//01244HZ `4#

0x4B,0xFD,//01318HZ `5

0x73,0xFD,//01397HZ `5#

0x98,0xFD,//01480HZ `6

0xBB,0xFD,//01568HZ `6#

0xDC,0xFD,//01661HZ `7//35

}

//定时中断0,用于产生唱歌频率

timer0() interrupt 1

{

TL0=tl0_fTH0=th0_f //调入预银腊槐定时值

BEEP=~BEEP //取反音乐输出IO

}

//******************************

//音乐符号串解释函数

//入口:要解释的音乐符号串,输出的音调串,输出的时长串

changedata(uchar *song,uchar *diao,uchar *jie)

{

uchar i,i1,j

char gaodi//高低+/-12音阶

uchar banyin//有没有半个升音阶

uchar yinchang//音长

uchar code jie7[8]={0,12,14,16,17,19,21,23}//C调的7个值

*diao=*song

for(i=0,i1=0)

{

gaodi=0//高低=0

banyin=0//半音=0

yinchang=4//音长1拍

if((*(song+i)=='|') || (*(song+i)==' ')) i++

//拍子间隔和一个空锋友格过滤

switch(*(song+i))

{

case ',': gaodi=-12i++//低音

break

case '`': gaodi=12i++//高音

break

}

if(*(song+i)==0) //遇到0结束

{

*(diao+i1)=0//加入结束标志0

*(jie+i1)=0

return

}

j=*(song+i)-0x30i++//取出基准音

j=jie7[j]+gaodi//加上高低音

yinc: switch(*(song+i))

{

case '#': //有半音j加一个音阶

i++j++

goto yinc

case '-': //有一个音节加长

yinchang+=4

i++

goto yinc

case '_': //有一个音节缩短

yinchang/=2

i++

goto yinc

case '.': //有一个加半拍

yinchang=yinchang+yinchang/2

i++

goto yinc

}

*(diao+i1)=j//记录音符

*(jie+i1)=yinchang//记录音长

i1++

}

}

//******************************************

//奏乐函数

//入口:要演奏的音乐符号串

void play(uchar *songdata)

{

uchar i,c,j=0

uint n

uchar xdata diaodata[112]//音调缓冲

uchar xdata jiedata[112] //音长缓冲

changedata(songdata,diaodata,jiedata)//解释音乐符号串

TR0=1

for(i=0diaodata[i]!=0i++) //逐个符号演奏

{

tl0_f=freq[diaodata[i]*2]//取出对应的定时值送给T0

th0_f=freq[diaodata[i]*2+1]

for(c=0c<jiedata[i]c++) //按照音长延时

{

for(n=0n<32000n++)

if((!K1)||(!K2)||(!K3)||(!K4))//发现按键,立即退出播放

{

TR0=0

return

}

}

TR0=0

for(n=0n<500n++) //音符间延时

TR0=1

}

TR0=0

}

//仙剑

uchar code xianjian[]={

"|3_3_3_2_3-|2_3_2_2_,6,6_,7_|12_1_,7,6_,5_|,6---|"

"3_3_3_2_3.6_|5_6_5_5_22_3_|45_4_32_1_|3.--3_|"

"67_6_55_3_|5--3_5_|26_5_32_3_|3---|"

"26_6_6-|16_6_66_7_|`17_6_76_7_|3.--3_|"

"67_6_55_3_|5--3_5_|67_6_76_7_|3---|"

"26_6_6-|16_6_66_7_|`17_6_7.5_|6---|"

}

uchar code song3[]={

"5-5_3_2_1_|3---|6-6_4_2_1_"

",7--,5_|1.3_5.1_|,7.3_5 5_|"

"6.7_`1.6_|6_5_5-3_2_|1.1_13_2_|"

"1.1_12_3_|2.1_,62_3_|2-- ,5_|"

"1.3_5.1_|,7.3_55_|6.7_`1.6_|"

"6_5_5-3_2_|1.1_13_2_|1.1_12_3_"

"2.,6_,71_2_|1--"

}

//世上只有妈妈好

uchar code mamahao[]={

"6.5_35|`16_5_6-|35_6_53_2_|1_,6_5_3_2-|"

"2.3_55_6_|321-|5.3_2_1_,6_1_|,5--"

}

//三个按键选择三首不同的音乐播放,一个键停止播放

void main(void) // 主程序

{

TMOD = 0x01 //使用定时器0的16位工作模式

TR0 = 0

ET0 = 1 //定时器0中断

EA = 1 //打开总中断

while(1)

{

if(!K1)

{

while(!K1)

play(xianjian) //播放音乐

}

if(!K2)

{

while(!K2)

play(song3) //播放音乐

}

if(!K3)

{

while(!K3)

play(mamahao) //播放音乐

}

}

}

一、设计题目:

设计一简易电子琴,要求能够发出1、2、3、4、5、6、7等七个音符。

使用元件:AT89C51、LM324,喇叭,按键等

二、 设计目的

(1)能够对电子电路、电子元器件、印制电路板等方面的知识有进一步的认识,独立对其进行测试与检查。

(2)熟悉8051单片机的内部结构和功能,合理使用其内部寄存器,能够完成相关软件编程设计工作。

(3)为实现预期功能,能够对系统进行快速的调试,并能够对出现的功能故障进行分析,及时修改相关软硬件。

(4)对软件编程、排错调试、焊接技术、相关仪器设备的使用技能等方面得到较全面的锻炼和提高。

三、系统硬件图

原嫌码理:

(一) 音乐产生原理及硬件设计

由于一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利昌者高用单片机的定时/计数器T0来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。

本次设计中单片机晶振为12MHZ,那么定时器的计数周期为1MHZ,假如选择工作方式1,那T值便为T= 216--5﹡105/相应的频率 ,那么根据不同的频率计算出应该赋给耐尺定时器的计数值,列出不同音符与单片机计数T0相关的计数值如下表所示:

音符 频率(HZ) 简谱码(T值)

中 1 DO 523 64580

中 2 RE 587 64684

中 3 M 659 64777

中 4 FA 698 64820

中 5 SO 784 64898

中 6 LA 880 64968

中 7 SI 988 65030

采用查表程序进行查表时,可以为这个音符建立一个表格,有助于单片机通过查表的方式来获得相应的数据:

TABLE DW 64580,64684,64777,64820,64898,64968,65030

源程序:

方案一:产生按键音符

ORG 0000H

LJMP MAIN

ORG 000BH

LJMP BREAK

MAIN: MOV TMOD,#01H 设置定时器0的工作方式

SETB EA

SETB ET0 设置定时器0中断

SETB TR0 启动定时器0

WAIT1: LCALL KEY 调用KEY子程序,判断有键按下否?第几个键?

CLR EA 屏蔽中断

CJNE R3,#00H,WAIT1 如果R3=0,表示有键按下

MOV A,22H 将22H里存放的按键号送给A

RL A 因为查表里都是字,所以得乘2查得数据

MOV DPTR,#TABLE 指向表头

MOVC A,@A+DPTR 查表

MOV TH0,A 将数据高位送TH0

MOV 21H,A 将高位备份

MOV A,22H 将22H里存放的按键号送给A

RL A 因为查表里都是字,所以得乘2查得数据

INC A 取低位数据

MOVC A,@A+DPTR

MOV TL0,A

MOV 20H,A

WAIT2: LCALL KEY

SETB EA

CJNE R3,#00H,WAIT1

JMP WAIT2

KEY: MOV R3,#00H KEY子程序,判断有键按下否?第几个键?

MOV R1,#0FFH

MOV R0,#00H

MOV A,R1

MOV P2,A

MOV A,P2

CLR C

CPL C 利用标志位CY来判断是哪个键按下

MOV R2,#08H

WAIT3: RLC A 移位判断

JNC STORE

INC R0

DJNZ R2,WAIT3

STORE: MOV 22H,R0将按键号存22H,R3=0有键按下

MOV R3,#00H

RET

BREAK: PUSH ACC 中断产生方波,从P1.0口输出

PUSH PSW

MOV TL0,20H

MOV TH0,21H

CPL P1.0

POP PSW

POP ACC

RETI

TABLE: DW 65030,64968,64898,64820,64777,64684,64580 7,6,5,4,3,2,1

END

方案二:产生按键音符

ORG 0000H

SJMP START

ORG 000BH

AJMP INT_0

ORG 0030H

START: MOV P1,#00H

SETB EA

SETB ET0 计数器0

MOV TMOD,#02H

MOV TH1,#09CH

MOV TL1,#09CH 定时器初植

CLR TR0定时器不允许

SCAN: 键盘扫描

MOV A,P2 判断键盘按下,跳到SCAN_1,若未按,继续扫描

CJNE A,#0FFH,SCAN_1

NOP

SJMP SCAN

SCAN_1:ACALL DELAY 是不是真的要按下?如果是,则跳转SU_KEY查询是哪个按下?

MOV A,P2

CJNE A,#0FFH,SU_KEY

NOP

SJMP SCAN

SU_KEY:JNB P2.1,MU_1 判断是哪个键按下?

JNB P2.2,MU_2

JNB P2.3,MU_3

JNB P2.4,MU_4

JNB P2.5,MU_5

JNB P2.6,MU_6

JNB P2.7,MU_7

SJMP SCAN

R1信号周期

MU_1: MOV R1,#19如果第一个按键按下,则R1=19,同时程序转NEXT

SJMP NEXT

MU_2: MOV R1,#17

SJMP NEXT

MU_3: MOV R1,#15

SJMP NEXT

MU_4: MOV R1,#14

SJMP NEXT

MU_5: MOV R1,#13

SJMP NEXT

MU_6: MOV R1,#11

SJMP NEXT

MU_7: MOV R1,#10

SJMP NEXT

NEXT: MOV A,R1

MOV R0,A

SETB TR0 启动定时器0

NEXT_1:MOV A,P2 没键按下继续执行,有键按下,返回读引脚

CJNE A,#0FFH,NEXT_1

ACALL DELAY

MOV A,P2 真的没键按下?

CJNE A,#0FFH,NEXT_1

CLR TR0不响

AJMP SCAN 扫描键盘去

INT_0: 中断程序

DJNZ R0,RE R0不等于0时,返回

CPL P1.0

MOV A,R1

MOV R0,A

RE: RETI

DELAY:MOV R7,#100延长时间等待,键盘消抖

D1: MOV R6,#10

D2: DJNZ R6,D2

DJNZ R7,D1

RET

END

生日快乐歌:(扩展功能部分程序)

ORG 0000H

JMP MAIN

ORG 000BH

JMP TT0

MAIN: MOV TMOD,#01H ;设置定时器0工作方式

MOV IE,#82H;设置中断

MAIN0:MOV 30H,#00H

NEXT: MOV A,30H

MOV DPTR,#TABLE ;查表

MOVC A,@A+DPTR

MOV R2,A

JZ STOP

ANL A,0FH

MOV R5,A

MOV A,R2

SWAP A

ANL A,#0FH

JNZ SING

CLR TR0

JMP W1

SING: DEC A

MOV 22H,A

RL A

MOV DPTR,#TABLE1 ;查表

MOVC A,@A+DPTR

MOV TH0,A

MOV 21H,A

MOV A,22H

RL A

INC A

MOVC A,@A+DPTR

MOV TL0,A

MOV 20H,A

SETB TR0

W1: CALL DELAY

INC 30H

JMP NEXT

STOP: CLR TR0

JMP MAIN0

TT0: PUSH ACC;中断服务程序

PUSH PSW

MOV TL0,20H

MOV TH0,21H

CPL P1.0

POP PSW

POP ACC

RETI

DELAY:MOV R7,#2 ;延时187ms

W2: MOV R4,#187

W3: MOV R3,#248

DJNZ R3,$

DJNZ R4,W3

DJNZ R7,W2

DJNZ R5,DELAY

RET

TABLE1:DW 64260,64400,64524,64580;音符计数植

DW 64684,64777,64820,64898

DW 64968,65030,65058,65110

DW 65157,65178,65217

TABLE:DB 82H,01H,81H,94H,84H ;节拍表

DB 0B4H,0A4H,04H

DB 82H,01H,81H,94H,84H

DB 0C4H,0B4H,04H

DB 82H,01H,81H,0F4H,0D4H

DB 0B4H,0A4H,94H

DB 0E2H,01H,0E1H,0D4H,0B4H

DB 0C4H,0B4H,04H

DB 82H,01H,81H,94H,84H

DB 0B4H,0A4H,04H

DB 82H,01H,81H,94H,84H

DB 0C4H,0B4H,04H

DB 82H,01H,81H,0F4H,0D4H

DB 0B4H,0A4H,94H

DB 0E2H,01H,0E1H,0D4H,0B4H

DB 0C4H,0B4H,04H

DB 00H

END 谢谢希望采纳


欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/yw/12536186.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存