单片机音乐程序的设计与实验

🏠 首页 《无线电》杂志 1992年 🔗 第3期 🔗 第24页 分类:无线电技术自学经验交流 🔗 周振安 🔗

(周振安)利用单片机(或单板机)奏乐大概是无线电爱好者感兴趣的问题之一。本文从单片机的基本发音实验出发,谈谈音乐程序的设计原理,并给出具体实例,以供参考。

1.单片机的基本发音实验

我们知道,声音的频谱范围约在几十~几千赫兹,若能利用程序来控制单片机某个口线的“高”电平或“低”电平,则在该口线上就能产生一定频率的矩形波,接上喇叭就能发出一定频率的声音。若再利用延时程序控制“高”“低”电平的持续时间,就能改变输出频率,从而改变音调。

图1
图1 🔍原图 (429×323)

例如,要产生200Hz的音频信号,按图1接入喇叭(若属临时实验,也可将喇叭直接接在P1口线上),实验程序为:

MUSIC2:CPL P1.4

MOV R3,#7DH

LCALL DEL

LJMP M

DEL:NOP

DEL3:MOV R4,#02H

DEL4:NOP

DJNZ R4,DEL4

NOP

DJNZ R3,DEL3

RET

其中子程序DEL为延时子程序,当R3为1时,延时时间约为20μs。R3中存放延时常数,对200Hz音频,其周期为1/200秒,即5ms。这样,当P1.4的高电平或低电平的持续时间为2.5ms,即R3的时间常数取2500/20=125(7DH)时,就能发出200Hz的音调。将上述程序键入学习机,并不断修改R3的常数可以感觉音调的变化

2.音乐程序的设计

乐曲中,每一音符对应着确定的频率。表1给出了C调时各音符频率及其相应的时间常数。

图2
图2 🔍原图 (947×471)

读者可以根据表1中所提供的常数,将其16进制代码送入R3,反复练习体会。根据表1可以奏出音符,仅这还不够,要准确奏出一首曲子,必须准确地控制乐曲节奏,即一音符的持续时间。

音符的节拍我们可以用定时器T0来控制。当T0送入不同的初值,就可产生不同的定时时间。例如某首歌曲的节奏为每分钟94拍,即每一拍为0.64秒。其它节拍与时间的对应关系见表2。

图3
图3 🔍原图 (1223×306)

但是,由于T0的最大定时时间只能为131ms,因此不可能直接用改变T0的时间初值来实现不同节拍。我们可以用T0来产生10ms的时间基准,然后设置一个中断计数器,通过判别中断计数器的值来控制节拍时间的长短。表2中也给出了各种节拍所对应的时间常数。例如对1/4拍音符,定时时间为0.16s,相应的时间常数为16(即10H);对3拍音符,定时时间为1.92s,相应时间常数为192(即C0H)。

我们将每一音符的时间常数和其相应的节拍时间常数作为一组,按顺序将乐曲中的所有常数排列成一个表,然后由查表程序依次取出,产生音符并控制节奏,就可实现演奏效果。

此外,结束符和休止符可以分别用代码00H和FFH来表示,若查表结果为00H,则表示曲子终了;若查表结果为FFH,则产生相应的停顿效果。

为了产生手弹的节奏感,在某些音符(例如两个相同音符)间插入一个时间单位的频率略有不同的音符。

程序框图如图2所示。

图4
图4 🔍原图 (849×1311)

下面给出程序清单,可直接在TD-Ⅲ型学习机上演奏,对其它不同型号的学习机,只需相应改变一下地址即可。本程序演奏的是民歌“八月桂花遍地开”,C调,节奏为94拍/分。读者也可自行找出一首歌,按表1和表2给定的常数,将乐曲翻译成码表输入机器,而程序不变。本实验方法简便,即使不懂音乐的人,将一首陌生的曲子翻译成代码也是易事,和着机器的演奏,学唱一首歌曲,其趣味无穷。
m侭m

程序清单:

l:*ORG 800BH

2:INC 20H;中断服务,中断计数器加1

3:MOV TH0,#0EDH;T0送初值

4:MOV TL0,#040H

5:RETI

6:ORG A000H

7:MOV TH0,#0EDH;T0初始化

8:MOV TL0,#040H

9:MOV TMOD,#01H

10:MOV IE,#82H

11:MUSICO:NOP

12:MOV DPTR,#DATA;表头地址→DPTR

13:MOV 20H,#00H;中断计数器清0

14:MOVB,#00H;表序号清0

15:MUSICI:NOP

16:MOVA,B

17:MOVCA,@A+DPTR;查表取代码→A

18:JZ END;是00H,则结束

19:CJNE A,#0FFH,MUSIC5;是FFH则停顿

20:LJMP MUSIC3

21:MUSIC5;NOP;是音符代码→R6

22:MOV R6,A

23:INC B

24:MOV A,B

25:MOVC A,@A+DPTR;取节拍常数代码→R7

26:MOV R7,A

27:SETB TR0;启动T0计数

28:MUSIC2:NOP

29:CPL P1.4;输出音频

30:MOV A,R6

31:MOV R3,A

32:LCALL DEL

33:MOV A,R7

34:CJNE A,20H,MUSIC2;中断计数器(20H)=R7否?不等,继续循环

35:MOV 20H,#00H;等于,则取下一代码

36:INC B

37:LJMP MUSIC1

38:MUSIC3:NOP

39:CLR TR0;休止100ms

40:MOV RZ,#0DH

41:MUSIC4:NOP

42:MOV R3,#0FFH

43:LCALL DEL

44:DJNZ R2,MUSIC4

45:INC B;取下一代码

46:LJMP MUSIC1

47:END:NOP

48: MOV R2,#64H;歌曲结束,延时1S后继续奏乐

49:MUSIC6:MOV R3,#00H

50:LCALL DEL

51:DJNZ R2,MUSIC6

52:LJMP MUSICO

53:DEL:NOP

54:DEL3;MOV R4,#02H;延时子程序

55:DEL4:NOP

56:DJNZ R4,DEL4

57:NOP

58:DJNZ R3,DEL3

59:RET

60:ORG A100H;歌曲代码表首址

61:DATA;DB 18H 30H 1CH 10H

62:DB 20H 40H 1CH 10H

63:DB 18H 10H 20H 10H

64:DB 1CH 10H 18H 40H

65:DB 1CH 20H 20H 20H

66:DB 1CH 20H 18H 20H

67:DB 20H 80H 0FFH 20H

68:DB 30H 1CH 10H 18H

69:DB 20H 15H 20H 1CH

70 20H 20H 20H 26H

71:DB 40H 20H 20H 2BH

72:DB 20H 26H 20H 20H

73:DB 20H 30H 80H 0FFH

74:DB 20H 20H 1CH 10H

75:DB 18H 10H 20H 20H

76:DB 26H 20H 2BH 20H

77:DB 30H 20H 2BH 40H

78:DB 20H 20H 1CH 10H

79:DB 18H 10H 20H 20H

80 26H 20H 2BH 20H

8l:DB 30H 20H 2BH 40H

82:DB 20H 30H 1CH 10H

83:DB 18H 20H 15H 20H

84:DB 1CH 20H 20H 20H

85:DB 26H 40H 20H 20H

86:DB 2BH 20H 26H 20H

87:DB 20H 20H 30H 80H

88:DB 20H 10H 1CH 10H

89:DB 20H 10H 1CH 10H

90 20H 20H 26H 20H

91:DB 2BH 20H 30H 20H

92:DB 2BH 40H 20H 15H

93:DB 1FH 05H 20H 10H

94:DB 1CH 10H 20H 20H

95:DB 26H 20H 2BH 20H

96:DB 30H 20H 2BH 40H

97:DB 20H 30H 1CH 10H

98:DB 18H 20H 15H 20H

99:DB 1CH 20H 20H 20H

100 26H 40H 20H 20H

101:DB 2BH 20H 26H 20H

102:DB 20H 20H 30H 30H

103:DB 20H 30H 1CH 10H

104:DB 18H 40H 1CH 20H

105:DB 20H 20H 26H 40H

106:DB 13H 60H 18H 20H

107:DB 15H 40H 13H 40H

108:DB 18H 80H 00H