汇编实验——乐曲程序(两只老虎)

    xiaoxiao2021-12-14  18

           首先需要知道的是PC机是通过什么来发声的,8255(A)可编程序外围接口芯片(PPI)。PPI有三个八位寄存器,两个用于输入,一个用于输出,而输出寄存器的I/O端口为61h,这是会在程序中体现的,而该输出寄存器端口号的第0位和第1位是选择扬声器的驱动方式。用汇编实现发声系统程序,有两种方式,一种是位触发方式,另一种是定时器方式。

           其中位触发方式直接使61h的PB1交替置1和0来实现脉冲电流,控制扬声器从而交替打开和关闭,产生不同音高和不同音长的声音。

           而定时器方式需要用到定时器内部的Counter2和控制寄存器,它们分别对应的端口号是42h43h。在该方式中需要将一个控制字送入43h中(类似于计算机组成原理中的ROM微指令),控制字为8位,由高到低,前两位选择计数器,第3、4位选择计数器读写指示位,第5、6和7位选择操作模式(输出脉冲的形状),最后一位选择计数值格式(0为二进制,1为BCD码格式),另外42h存放的是计算得到的延迟时间。当然61h的0和1位需要都置为1。

           实现了输出一个简谱音符的同时响相应的音,之前将输出音符放在了扬声器输出声音的后面,出现了声音延迟于音符输出,在数据段mes存放数据的开头增加一个空格依然无法同步,原因很简单,在主程序段中,di、bx和si是同步增加的,程序会将空格字符与一个声音对应起来。

           最后,不要问我为什么后面输出的低阶sol没有显示成5下有个小点~~

           下面是“两只老虎”的参考代码:

    ;************************************************************************************ datasg segment        mus_freq   dw 262,294,330,262,262,294,330,262      ;频率决定音高                   dw 330,349,392,330,349,392,392,440                   dw 392,349,330,262,392,440,392,349                   dw 330,262,294,196,262,294,196,262

           mus_time   dw 2500,2500,2500,2500,2500,2500,2500,2500,2500,2500    ;节拍决定音长                   dw 5000,2500,2500,5000,1200,1200,1200,1200,2500,2500                   dw 1200,1200,1200,1200,2500,2500,2500,2500,5000,2500,2500,5000

        mes    db 31h,32h,33h,31h,31h,32h,33h,31h,33h,34h,35h,33h,34h,35h,35h,36h       db 35h,34h,33h,31h,35h,36h,35h,34h,33h,31h,32h,35h,31h,32h,35h,31h,'$'      datasg ends ;************************************************************************************ ;************************************************************************************ codesg segment     main    proc   far          assume cs:codesg,ds:datasg    org    100h     ;链接器将之后的程序放在0100h的开始位置 ;-----------------------------------------------------  start:          push ds    sub  ax,ax    push ax    mov  ax,datasg    mov  ds,ax ;              lea  di,mus_freq   ;频率             lea  bx,mus_time   ;节拍    lea  si,mes    ;音符             mov  cx,32d; ;-----------------------------------------------------  new_shot:               push cx       call sound    add  di,2       add  bx,2    add  si,1    mov  cx,0ffffh ;-----------------------------------------------------  silent:    loop silent          pop  cx    loop new_shot    mov  al,48h          out  61h,al                mov  ah,4ch    int  21h           ret  main endp   ;----------------------------------------------------- sound proc near

       mov  ah,02h    ;利用中断21h的02功能调用,显示音符简谱    and  si,00ffh    mov  dx,[si]    int  21h

       in  al,61h    and  al,11111100b   sing:       xor  al,2    ;将PB1置1,打开扬声器    out  61h,al

       push ax    call widnth    pop  ax    mov  cx,dx   waits:       loop waits    ;循环延迟,由此控制开关电路所产生脉冲的频率       dec  WORD PTR [bx]  ;实现相应节拍的声音    jnz  sing

              and  al,11111100b  ;关闭扬声器    out  61h,al    ret       ;一轮实现了一个音的输出    sound endp ;-----------------------------------------------------  ;----------------------------------------------------- widnth proc near     ;控制脉宽的计数值             mov  ax,2801        push bx     ;保存的是节拍    mov  bx,50             mul  bx    div  WORD PTR [di]  ;除以了相应的频率    mov  dx,ax    pop  bx    ret widnth endp ;----------------------------------------------------- codesg ends   ;************************************************************************************     end start ;************************************************************************************

    
    转载请注明原文地址: https://ju.6miu.com/read-964102.html

    最新回复(0)