回 帖 发 新 帖 刷新版面

主题:8255 PPI 延迟有问题

下面是一个驱动扬声器发声的程序,感觉延迟的时间不对,
有三个循环层
BX是入口参数,最外层
CX是让WAIT_10MS 产生10MS时间延迟的倍数
wait_10ms子程序是产生15.08毫秒的过程

假如:BX=25
一个音符的延迟时间=25*663*15.08=0.25S

这里我试过几次,BX,CX参数放大后都能增加延迟时间,
问题应该在WAIT_10MS的子程序里

我也不知道是什么原因,还有我的MASM5.0编译出来的代码
在DEBUG里调试,IN和OUT指令老是抹去他本身指令的下一条指令的显示
但程序应该正常,还有有时候查看修改的I/O端口数据也不对

往高手指点:代码如下
DATA    SEGMENT                                         ; ;定义声音频率数据块
MUS_FREQ        DW      330,294,262,294,3 DUP(330)
        DW      294,294,294,330,392,392
        DW      330,294,262,294,4 DUP(330)
        DW      294,294,330,294,262,0FFFFH

MUS_TIME        DW      6 DUP(25),50                   ; ;定义对应声音延迟数据块
        DW      2 DUP(25,25,50)
        DW      12 DUP(25),100
DATA    ENDS



CODE    SEGMENT

MAIN    PROC    FAR
    ASSUME  CS:CODE,DS:DATA
START:
    MOV     AX,DATA
    MOV     DS,AX

    LEA     SI,MUS_FREQ              
    LEA     BP,DS:MUS_TIME
BEGIN1:
    MOV     DI,[SI]               ;  ;DI为频率
    MOV     BX,DS:[BP]            ;  ;BX为延迟,BX中的每一次调用延迟10MS的子程序
    CALL    SOUNDF
    INC     SI
    INC     SI
    INC     BP
    INC     BP
    CMP     [SI],0FFFFH
    JZ      OVER
    JMP     BEGIN1


OVER:   MOV     AH,4CH
    INT     21H
MAIN    ENDP    





;______________________________
;DI = sound frequency
;BX = delay  time

SOUNDF  PROC    NEAR
    PUSH    DI
    PUSH    BX
    PUSH    AX


;initializing the counter2

    MOV     DX,12H
    MOV     AX,348CH     ;12348CH=1.1931817MHz
    DIV     DI           ;the result in AX is outer frequency

    PUSH    AX        ;save it    

    MOV     AL,10110110B  ;set controll word
    OUT     43H,AL
    POP     AX            ;restore outer frequency

    OUT     42H,AL        ;send it to PORT 42H
    MOV     AL,AH
    OUT     42H,AL        ;first write LSB, write MSB next


;turn the speaker on

    IN      AL,61H       ;get the setting of PROT B
    MOV     AH,AL        ;save it

    OR      AL,00000011B ;set PB0 and PB1 to bit 1
    
    OUT     61H,AL       ;out it to PROT 61H
    
    
;WAIT  时间延迟代码段********************************

WAIT1:  MOV     CX,663       ;633*15US=10MS CX为663倍15.08us = 10ms(此处如果放大,延迟有效果)
    CALL    WAIT_10MS
    DEC     BX           ;BX为延迟时间的入口参数(此处放大,延迟也有效果)
    JZ      EXIT
    JMP     WAIT1
     
EXIT:
    MOV     AL,AH        ;restore out PORT of PPI
    OUT     61H,AL

    POP     AX
    POP     BX
    POP     DI

    RET
SOUNDF  ENDP

;____________________________


WAIT_10MS PROC NEAR

    PUSH    AX
    
WAIT3:  
    IN      AL,61H      ; ;获取61H端口数据
    AND     AL,10H        ;  ;测试61H端口的BP4      
    CMP     AL,AH         ;  ;与以前的比较,看是否改变(此位每15.08US刷新一次)
    JE      WAIT3           
    MOV     AH,AL
    LOOP    WAIT3

    POP     AX
    RET       

WAIT_10MS ENDP

;**********
CODE    ENDS
    END     START

回复列表 (共7个回复)

沙发

整段代码是没有问题的。你觉得延迟不对,与你所认为一拍为多长时间有关。


示例代码没有说明设计多少毫秒为一拍。通常来说,我们习惯的一拍的时间长度为550ms到700ms之间。你可以据此对代码的延迟进行修改。

此代码对延迟和频率的算法复杂了一点,本可以简单得多的。

板凳

拍子可以通过修改其他参数也可以实现延迟时间更长

但这个代码与我本意不同

我的算法原理是
利用端口61H(PPI的输出寄存器)的第4位每隔15.08毫秒触发一次,
具体如何改变的第4位的值不大清楚,
如果监测该位,就能得到一个15.08微秒一次的触发信号。
15.08*663得到一个10毫秒的一个延迟
在于数据段的延迟再相乘,变可得到无硬件关系的延迟。

我大概算过了,应该是WAIT_10MS子程序的15.08微秒的延迟并未实现,
所以导致了拍子如此的快,如果我把663该为9000左右就差不多了。

这个可能是我不清楚那个硬件支持的61H端口第4位是如何改变的有关

谁能说明一下或者利用这个硬件支持的延迟写一个小的例子让我看一下

3 楼

61h的PB4位用于监测DRAM的刷新时钟,是由8254的定时器1产生的,为动态RAM提供刷新的定时信号。你提供的例子在DOS中是完全没有问题的,拍子并没有变快,在xp的命令提示符中则变快了许多。

在wait3的循环中加入一变量记录循环的次数,发现dos下的循环次数大约2600次,而xp下则刚好是663次,这说明xp中这个定时信号加快了,从原来的15.085微秒变成了4微秒左右。为什么会加快了,偶手头没有任何资料说明其原因,从其用途上推测,本来是不应该加快的。

4 楼


WAIT_10MS PROC NEAR

    PUSH    AX
    PUSH    DX
    SUB     DX,DX
    
WAIT3:  IN      AL,61H      ; ;获取61H端口数据
    AND     AL,10H        ;  ;测试61H端口的BP4      
    CMP     AL,AH         ;  ;与以前的比较,看是否改变(此位每15.08US刷新一次)
    INC     DX
    JE      WAIT3           
    MOV     AH,AL
    LOOP    WAIT3

    CALL    PRIN_COUNT

    POP     DX
    POP     AX
    RET       

WAIT_10MS ENDP

;**********

PRIN_COUNT PROC NEAR     ;用于输出DX的值在显示器上。DX为测试比较次数

    PUSH    DX
    PUSH    CX
    PUSH    BX
    PUSH    AX
       
    MOV     AH,2
    

    MOV     BX,DX
    MOV     CL,12
    ROR     DX,CL
    AND     DX,0001H
    ADD     DL,30H
    INT     21H

    MOV     DX,BX
    MOV     CL,8
    ROR     DX,CL
    AND     DX,0FH
    ADD     DL,30H
    INT     21H

    MOV     DX,BX
    MOV     CL,4
    ROR     DX,CL
    AND     DX,0FH
    ADD     DL,30H
    INT     21H

    MOV     DX,BX
    AND     DX,0FH
    ADD     DL,30H
    INT     21H

    MOV     DL,0AH
    INT     21H

    MOV     DL,0DH
    INT     21H
    
    POP     AX
    POP     BX
    POP     CX
    POP     DX
    RET
PRIN_COUNT      ENDP


这个我也加了一个DX作为比较次数记录。
我修改了几次CX外围的633的值,DX中的数据始终与它一致。
说明测试的端口61H只进行了一次,并未延时于15.08微秒。
可能我写的那个比较测试61H那点有问题。
估计是,现在没时间做修改。写给你看一下,
我想这个时间基准在所有操作系统上都应该是一样的,
要不还怎么叫通用程序??
希望继续关注

5 楼

你的代码写错啦,inc dx不能放在je wait3之前,否则je检测的是inc dx的结果,不是cmp al, ah的结果。把inc dx改到cmp al, ah之前。

6 楼

我写的是有点问题,
但INC DX 一般改变不了 zero flag。
该过来我也试过了,结果一样。

问题肯定是61H的BP4的位的变化问题上,
关键是不知道这个位是如何发生变化的
是每15.08微秒改变一下?
书上只说了触发一次,靠 怎么触发都不知道

7 楼

但INC DX 一般改变不了 zero flag。
-----------------------------
no! inc除了不改变c外,一样会影响其它标志的。


你装一个dos6.22然后运行一下就明白了,在dos6.22中是完全没有问题的,那个wait3循环在dos6.22中运行了2600多次。

我来回复

您尚未登录,请登录后再回复。点此登录或注册