这是本人一个产品中的音乐单元,很完整,供参考.
中央c组里的A=440Hz<br />12个半音阶相邻关系是12√2 (2开12次方≈1.0594631)<br />例如 A=440Hz<br /> bB=440Hz x 1.0594631 = 466.16Hz <br /> B=466.16Hz x 1.0594631 = 493.88Hz<br /> C=493.88Hz x 1.0594631 = 523.25Hz<br /><br />这是本人一个产品中的音乐单元,单音演奏的,多重和音不宜用这方法,一般用硬件的音源加单片机控制方法完成,有兴趣可去合泰网站<a href="http://www.holtek.com.cn/docum/consumer/8950.htm" target=_blank>http://www.holtek.com.cn/docum/consumer/8950.htm</a>看看.ht8950提供了一个产生乐音包络用的硬件平台(a/d,d/a等),用软波表数据来完成音阶及包络,单片机只是进行控制,以前8bit声卡中ym3812与此差不多功能.<br /><br />中央C的A音为440Hz,半音价之间关系为2开12次方(12√2=1.05946)<br />中央C的#A音为440Hz*1.05946=466.163Hz<br />中央C的B音为440Hz*1.05946*1.05946=493.883Hz<br />用定时器来模拟这个频率,精度取决于时钟快慢,一般小数点后保留一位,音准已可忍受了,生日快乐芯片是小数点前一位的,耳朵容易听坏的拉.<br /><br />cpu用89c51,p1.7输出乐音,接无源蜂鸣器的驱动三极管基极<br /><br /> ORG 0000H<br /> AJMP CSH ;主程序进入点<br /> ORG 000BH<br /> LJMP TIM0 ;定时中断T0入口<br />;<br />;**********<br />;* 初始化 *<br />;**********<br />;<br /> ORG 0020H<br />CSH: MOV R0,#7FH ;内部RAM(00H~7FH)清零<br />CSH1: MOV @R0,#00H<br /> DJNZ R0,CSH1<br /> MOV SP,#60H ;堆栈60H~7FH,【使用89C51】<br /> MOV TMOD,#01H ;TMOD=11H,T0作16位计数器(4M晶振)<br /> CLR TCON.4 ;T0禁止动作<br /> SETB IE.1 ;T0允许中断<br /> SETB PT0 ;T0中断优先<br /> SETB IE.7 ;系统允许中断<br />;<br />;**********<br />;* 主程序 *<br />;**********<br />;<br />MAIN: MOV 5CH,#00 ;取简码谱指针<br /> LCALL MUSIC<br /> MOV 5CH,#49 ;取简码谱指针<br /> LCALL MUSIC<br /> MOV 5CH,#66 ;取简码谱指针<br /> LCALL MUSIC<br /> MOV 5CH,#100 ;取简码谱指针<br /> LCALL MUSIC<br /> MOV 5CH,#108 ;取简码谱指针<br /> LCALL MUSIC<br /> MOV 5CH,#136 ;取简码谱指针<br /> LCALL MUSIC<br /> MOV 5CH,#174 ;取简码谱指针<br /> LCALL MUSIC<br /> AJMP MAIN<br />;<br />;*************************<br />;* 音乐子程序 MUSIC *<br />;* 入口: 5CH←简码谱指针 *<br />;*************************<br />;<br />MUSIC: MOV A,5CH ;简码谱指针装入A<br /> MOV DPTR,#TABLE ;至TABLE取简码<br /> MOVC A,@A+DPTR<br /> MOV R2,A ;取到的简码暂存于R2<br /> JZ END1 ;是否取到00(结束码)?<br /> ANL A,#0FH ;不是,则取低四位(节拍码)<br /> MOV R6,A ;将节拍码存入R6<br /> MOV A,R2 ;将取到的简码再装入R2<br /> SWAP A ;高低四位交换<br /> ANL A,#0FH ;取低四位(音符码)<br /> JNZ SING ;取到的音符码是否为0?<br /> CLR TR0 ;是,则不发音<br /> AJMP D1 ;跳到D1<br />;<br />SING: DEC A ;取到的音符码减1<br /> MOV 4BH,A ;存入(4BH)<br /> RL A ;乘2<br /> MOV DPTR,#TABLE1 ;至TABLE1取相对的高字节计数值<br /> MOVC A,@A+DPTR<br /> MOV TH0,A ;取到的高字节存入TH0<br /> MOV 4AH,A ;取到的高字节存入(4AH)<br /> MOV A,4BH ;再装入取到的音符码<br /> RL A ;乘2<br /> INC A ;加1<br /> MOVC A,@A+DPTR ;至TABLE1取相对的低位<br /> MOV TL0,A ;取到的低字节存入TL0<br /> MOV 49H,A ;取到的低字节存入(49H)<br /> SETB TR0 ;启动TIMER0<br />D1: CALL DELAY ;基本单位时间1/4拍187毫秒<br /> INC 5CH ;取简码谱指针加1<br /> AJMP MUSIC ;取下一个码<br />DD1: RET<br />;<br />STOP: NOP<br />; JB P3.7,STOP1 ;在软件延时中掺插做其他动作<br />; SETB P2.7 ;P2.7←"1"<br /> NOP<br /> NOP<br />STOP0: NOP<br /> RET<br />STOP1: NOP<br />; JB P3.6,STOP0 ;在软件延时中掺插做其他动作<br />; SETB P2.6 ;P2.6←"1"<br /> RET<br />;<br />END1: CLR TR0 ;停止TIMER0<br /> RET<br />;<br />TIM0: PUSH A ;将A的值暂存于堆栈区<br /> PUSH PSW ;将PSW的值暂存于堆栈区<br /> MOV TL0,49H ;重设计数值<br /> MOV TH0,4AH<br /> CPL P1.7 ;将输出端P1.7取反(P1.7接至无源蜂鸣器)<br /> POP PSW ;至堆栈区取回PSW的值<br /> POP A ;至堆栈区取回A的值<br /> RETI ;返回主程序<br />;<br />DELAY: MOV R7,#02 ;187毫秒<br />D2: MOV R4,#24<br />D3: MOV R3,#48<br /> DJNZ R3,$<br /> ACALL STOP ;在软件延时中掺插做其他动作<br /> DJNZ R4,D3<br /> DJNZ R7,D2<br /> DJNZ R6,DELAY ;决定节拍<br /> RET<br />; .5 .6 .7 1<br />TABLE1: DW 65111,65150,65199,65217 ;4M晶振时的定时中断时间常数<br />; 2 3 4 5 ;若采用其它频率,则要根据乐音的<br /> DW 65252,65283,65297,65323 ;频率计算,例中央C的A音为440Hz,<br />; 6 7 1` 2` ;440Hz=2.273ms,把T0设置为2.273ms<br /> DW 65347,65367,65377,65394 ;中断即可发出A音.<br />; 3` 4` #6<br /> DW 65410,65417,65357<br />;<br />;***************************************************************<br />;* 音符代码 1 2 3 4 5 6 7 8 9 A B C D E F 0 *<br />;* 音高 .5 .6 .7 1 2 3 4 5 6 7 1` 2` 3` 4` 5` 休止 *<br />;*-------------------------------------------------------------*<br />;* 节拍代码 1 2 3 4 5 6 8 A C F *<br />;* 节拍 1/4 2/4 3/4 1 1(1/4) 1(1/2) 2 2(1/2) 3 3(3/4) *<br />;*-------------------------------------------------------------*<br />;* 结束代码 00H *<br />;*-------------------------------------------------------------*<br />;* 乐谱格式 每字节的高字节为音符代码,低字节为节拍代码 *<br />;*-------------------------------------------------------------*<br />;* 例子: ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ *<br />;* DB A4H,02H,84H,02H,A4H,02H,84H,02H,D8H,04H,00H *<br />;* ⑴ A→唱"7" , 4→ 1 拍 *<br />;* ⑵ 0→休止 , 2→2/4拍 *<br />;* ⑶ 8→唱"5" , 4→ 1 拍 *<br />;* ⑷ 0→休止 , 2→2/4拍 *<br />;* ⑸ A→唱"7" , 4→ 1 拍 *<br />;* ⑹ 0→休止 , 2→2/4拍 *<br />;* ⑺ 8→唱"5" , 4→ 1 拍 *<br />;* ⑻ 0→休止 , 2→2/4拍 *<br />;* ⑼ D→唱"3`", 8→ 2 拍 *<br />;* ⑽ 0→休止 , 4→ 1 拍 *<br />;* ⑾ 00H→乐曲结束 *<br />;***************************************************************<br />;<br />TABLE:<br />;【00】<br /> DB 98H,02H,B4H,01H,94H,01H,68H,02H,94H,01H<br /> DB 64H,01H,48H,02H,64H,01H,44H,01H,28H,02H<br /> DB 64H,01H,94H,01H,B4H,01H,94H,01H,B4H,01H<br /> DB 94H,01H,B4H,01H,D4H,01H,94H,01H,64H,01H<br /> DB 44H,01H,64H,01H,98H,02H,01H,01H,00H<br />;【49】<br /> DB A4H,02H,84H,02H,A4H,02H,84H,02H,D8H,04H<br /> DB C8H,01H,01H,01H,01H,01H,00H<br />;【66】<br /> DB 42H,52H,62H,72H,82H,92H,A2H,B2H,42H,52H<br /> DB 62H,72H,82H,92H,A2H,B2H,00H<br />;【100】<br /> DB 61H,81H,B1H,D1H,B1H,81H,61H,00H<br />;【108】<br /> DB 11H,41H,61H,81H,61H,41H,11H,00H<br />;【136】<br /> DB 24H,04H,34H,04H,44H,04H,54H,04H,64H,04H,44H,04H,64H,04H,94H,04H<br /> DB 83H,01H,93H,01H,83H,01H,63H,01H,46H,02H,66H,02H<br /> DB 91H,21H,91H,21H,91H,21H,91H,21H,94H,00H<br />;【174】<br /> DB 94H,04H,A4H,04H,B4H,04H,C4H,04H,D4H,04H<br /> DB B4H,04H,D8H,08H,C4H,04H,F4H,04H,CCH,00H<br />;<br /> END<br /><br /><br />
|
|