| 网站首页 | 业界新闻 | 群组 | 人才 | 技术文章 | 下载频道 | 博客 | 代码贴 | 编程论坛
共有 390 人关注过本帖
标题:请教:王爽课程设计2的时钟显示功能在更改程序小逻辑后不会自动跳动,请大神 ...
只看楼主 收藏
lishua
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2017-7-14
  问题点数:0  回复次数:9   
请教:王爽课程设计2的时钟显示功能在更改程序小逻辑后不会自动跳动,请大神帮忙看一看,多谢
问题是:因为按照课程设计,按2进入dos界面后,会把之前选择时的按键如3、2、F1等在c:\后显示出来,为了进入dos后不显示这些按键,计划在按2进入dos之前把这些按键对应的键盘缓冲都清掉。
我不明白的是下面红色和绿色两种做法,都可以达到去除缓冲区的目的。但是如果按照蓝色的做法,没有红色的部分,按3进入时钟显示界面后,时间会自己一直跳动;
而如果把蓝色的部分注释掉,使用红色的部分(即进入自定义的中断例程后一开始就删除键盘的缓冲),那么进入时钟界面后,时钟界面只显示一次当前的时间,时间不会跳动。想请教一下,不知道这个删除键盘缓冲区的位置怎么会对时钟显示有的影响?
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
  db 4 dup (0)
datasg ends
stacksg segment
  dw 32 dup (0)
stacksg ends
codesg segment
  start:;write to the floppy
          mov ax,cs
          mov es,ax
          mov bx,offset floppy
           
          mov dl,0
          mov dh,0
          mov cl,1
          mov ch,0
          mov al,2
          mov ah,3
          int 13h
           
          mov ax,4c00h
          int 21h
  
 org 7c00h
 floppy:jmp short beg
origin_int9 dw 0,0
dis_choice db 0
is_clock db 0
format2 db 'YE/MO/DA hh:mm:ss',0
         ;mov ax,stacksg
          ;mov ss,ax
          ;mov sp,32*2
          ;mov ax,datasg
      beg:;将第二个扇区读入内存
          mov ax,0
          mov es,ax
          mov bx,7c00h+200h
          mov dx,0
          mov cx,2
          mov ax,0201h
          int 13h
           
          mov dis_choice,1
          call display
           
          ;替换9号中断
          mov ax,0
           mov es,ax
          mov ax,es:[9*4]
          mov origin_int9,ax
          mov ax,es:[9*4+2]
          mov origin_int9[2],ax
           
          cli
          mov word ptr es:[9*4],offset s9_beg
           mov word ptr es:[9*4+2],cs
           sti
           
        s3:nop
           jmp short s3
            
 s9_beg:push bp
         mov bp,sp
         add bp,2
         push ax
         push ds
         push bx
         push si
         push cx
         push es
         push di
         
         in al,60h
        mov bl,al
          pushf
         ;mov si,offset origin_int9
          call dword ptr origin_int9;here the book use 'cs' register
 
          ;mov ah,0
          ;int 16h

          cmp bl,2h
         je reset
         cmp bl,3h
         je sys
         cmp bl,4
         je clock
         cmp is_clock,1
         jne s10
         cmp bl,3Bh
         je c_f1
         cmp bl,1h
         jne s10
         jmp near ptr c_esc
     s10:jmp near ptr s4
  reset:mov ax,ss
          mov ds,ax
          mov word ptr ds:[bp],0
          mov word ptr ds:[bp+2],0ffffh
          jmp near ptr s4
    sys:;
        ;恢复int 9
        mov ax,0
        mov es,ax
        mov ax,origin_int9
          mov es:[9*4],ax
          mov ax,origin_int9[2]
          mov es:[9*4+2],ax
          ;删除键盘缓冲区
          mov ah,0
          int 16h

          ;int 13h 读硬盘
        mov dx,0080h
        mov cx,0001h
        mov bx,7c00h
        ;es的值已设置过
        mov ax,0201h
        ;模拟int 13h指令
        pushf
        ;pushf
        ;pop ax
        ;and ah,11111100b
        ;push ax
        ;popf
        push es
        push bx
        mov dis_choice,0
        call display
        jmp dword ptr es:[13h*4]
  clock:mov is_clock,1
          mov ah,0
          int 16h

          mov ax,ss
          mov ds,ax
          mov word ptr ds:[bp],offset clock_dis
          mov ax,cs
          mov word ptr ds:[bp+2],ax
          mov dis_choice,0
          call display
          jmp short s4
   c_f1:mov ah,0
          int 16h

           mov ax,0b800h
        mov es,ax
        mov di,160*12+62+1
        mov si,0
 cf1_s1:cmp byte ptr format2[si],0
        je s4
        add byte ptr es:[di],1
        inc si
        add di,2
        jmp short cf1_s1
  c_esc:mov ah,0
          int 16h

          mov is_clock,0
        ;清除屏幕先
          mov ax,0b800h
        mov es,ax
        mov di,160*12+62
        mov si,0
cesc_s1:cmp byte ptr format2[si],0
        je cesc_s3
        mov es:[di],0720h
        inc si
        add di,2
        jmp short cesc_s1
cesc_s3:mov dis_choice,1
        call display
          mov ax,ss
          mov ds,ax
          mov word ptr ds:[bp],offset s3
          mov ax,cs
          mov word ptr ds:[bp+2],ax
          jmp short s4
     s4:pop di
         pop es
         pop cx
         pop si
          pop bx
          pop ds
          pop ax
          pop bp
          iret
  s9_se:nop
   
  ;dis_choice为参数:1为显示,0为清屏
  display:jmp short dis_beg
  ad dw f1,f2,f3,f4
  f1 db '1) reset pc',0
  f2 db '2) start system',0
  f3 db '3) clock',0
  f4 db '4) set clock',0  
  dis_beg:push ax
            push es
            push di
            push cx
            push si
            push bx
            push dx
            mov ax,0b800h
            mov es,ax
            mov cx,0    ;行数计数器
            mov si,0    ;每行地址的指针
       next:mov di,10*160+32*2
          mov ax,160
           mul cx
          add di,ax
 
            mov bx,ad[si]
            add si,2
         s0:mov al,cs:[bx]
            cmp al,0    ;一行是否结束
            je s1
            add bx,1
            ;display功能选择
            cmp dis_choice,1
            je s2
            mov byte ptr es:[di],' '
            jmp short s5
         s2:mov es:[di],al
         s5:add di,2
            jmp short s0
       s1:add cx,1
          cmp cx,4
          je dis_end
          jmp short next
  dis_end:pop dx
            pop bx
            pop si
            pop cx
            pop di
            pop es
            pop ax
            ret
            
clock_dis:jmp short s7
format db 'YE/MO/DA hh:mm:ss',0
position db 9,8,7,4,2,0
     s7:mov bx,0
        mov si,0
        mov cx,6
     s9:mov al,position[bx]
        out 70h,al
        in al,71h
        mov ah,al
        push cx
        mov cl,4
        shr ah,cl
        pop cx
        and al,00001111b
         
        add ah,30h
        add al,30h
         
        mov format[si],ah
        mov format[si+1],al
        add si,3
        inc bx
        loop s9
         
        mov ax,0b800h
        mov es,ax
        mov di,160*12+62
        mov si,0
     s8:cmp byte ptr format[si],0
        je s7
        mov al,format[si]
        mov es:[di],al
        inc si
        add di,2
        jmp short s8
codesg ends
end start
由于使用代码格式无法再自定义蓝色和红色,所以在下面那个帖子中我会用代码格式把这个再发一遍,方便大家看
另外附上我在标号s7的地方加上下面的代码进行过的一次调试
mov ax,0b800h
mov es,ax
inc byte ptr es:[160*24+158]
观察按3以后s7是不是一直在执行。结果是右下角的符号每次按3会快速变化一下,然后就不变了。比如第一次按3后显示'G',按esc退出第二次按3进去,变成一个乱码,然后再按esc再按3进入,又是变了一下就停了。为啥每次都是只执循环限次数呢?这可能就是带来上面的问题原因

[此贴子已经被作者于2017-7-14 22:41编辑过]

2017-07-14 22:07
lishua
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2017-7-14
  得分:0 
下面是用[程序代码]格式发的代码,跟上面一样
程序代码:

assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
  db 4 dup (0)
datasg ends
stacksg segment
  dw 32 dup (0)
stacksg ends
codesg segment
  start:;write to the floppy
          mov ax,cs
          mov es,ax
          mov bx,offset floppy
           
          mov dl,0
          mov dh,0
          mov cl,1
          mov ch,0
          mov al,2
          mov ah,3
          int 13h
           
          mov ax,4c00h
          int 21h
  
 org 7c00h
 floppy:jmp short beg
origin_int9 dw 0,0
dis_choice db 0
is_clock db 0
format2 db 'YE/MO/DA hh:mm:ss',0
         ;mov ax,stacksg
          ;mov ss,ax
          ;mov sp,32*2
          ;mov ax,datasg
      beg:;将第二个扇区读入内存
          mov ax,0
          mov es,ax
          mov bx,7c00h+200h
          mov dx,0
          mov cx,2
          mov ax,0201h
          int 13h
           
          mov dis_choice,1
          call display
           
          ;替换9号中断
          mov ax,0
           mov es,ax
          mov ax,es:[9*4]
          mov origin_int9,ax
          mov ax,es:[9*4+2]
          mov origin_int9[2],ax
           
          cli
          mov word ptr es:[9*4],offset s9_beg
           mov word ptr es:[9*4+2],cs
           sti
           
        s3:nop
           jmp short s3
            
 s9_beg:push bp
         mov bp,sp
         add bp,2
         push ax
         push ds
         push bx
         push si
         push cx
         push es
         push di
         
         in al,60h
        mov bl,al
          pushf
         ;mov si,offset origin_int9
          call dword ptr origin_int9;here the book use 'cs' register

          ;mov ah,0
          ;int 16h
          cmp bl,2h
         je reset
         cmp bl,3h
         je sys
         cmp bl,4
         je clock
         cmp is_clock,1
         jne s10
         cmp bl,3Bh
         je c_f1
         cmp bl,1h
         jne s10
         jmp near ptr c_esc
     s10:jmp near ptr s4
  reset:mov ax,ss
          mov ds,ax
          mov word ptr ds:[bp],0
          mov word ptr ds:[bp+2],0ffffh
          jmp near ptr s4
    sys:;
        ;恢复int 9
        mov ax,0
        mov es,ax
        mov ax,origin_int9
          mov es:[9*4],ax
          mov ax,origin_int9[2]
          mov es:[9*4+2],ax
          ;删除键盘缓冲区
          mov ah,0
          int 16h
          ;int 13h 读硬盘
        mov dx,0080h
        mov cx,0001h
        mov bx,7c00h
        ;es的值已设置过
        mov ax,0201h
        ;模拟int 13h指令
        pushf
        ;pushf
        ;pop ax
        ;and ah,11111100b
        ;push ax
        ;popf
        push es
        push bx
        mov dis_choice,0
        call display
        jmp dword ptr es:[13h*4]
  clock:mov is_clock,1
          mov ah,0
          int 16h
          mov ax,ss
          mov ds,ax
          mov word ptr ds:[bp],offset clock_dis
          mov ax,cs
          mov word ptr ds:[bp+2],ax
          mov dis_choice,0
          call display
          jmp short s4
   c_f1:mov ah,0
          int 16h
           mov ax,0b800h
        mov es,ax
        mov di,160*12+62+1
        mov si,0
 cf1_s1:cmp byte ptr format2[si],0
        je s4
        add byte ptr es:[di],1
        inc si
        add di,2
        jmp short cf1_s1
  c_esc:mov ah,0
          int 16h
          mov is_clock,0
        ;清除屏幕先
          mov ax,0b800h
        mov es,ax
        mov di,160*12+62
        mov si,0
cesc_s1:cmp byte ptr format2[si],0
        je cesc_s3
        mov es:[di],0720h
        inc si
        add di,2
        jmp short cesc_s1
cesc_s3:mov dis_choice,1
        call display
          mov ax,ss
          mov ds,ax
          mov word ptr ds:[bp],offset s3
          mov ax,cs
          mov word ptr ds:[bp+2],ax
          jmp short s4
     s4:pop di
         pop es
         pop cx
         pop si
          pop bx
          pop ds
          pop ax
          pop bp
          iret
  s9_se:nop
   
  ;dis_choice为参数:1为显示,0为清屏
  display:jmp short dis_beg
  ad dw f1,f2,f3,f4
  f1 db '1) reset pc',0
  f2 db '2) start system',0
  f3 db '3) clock',0
  f4 db '4) set clock',0  
  dis_beg:push ax
            push es
            push di
            push cx
            push si
            push bx
            push dx
            mov ax,0b800h
            mov es,ax
            mov cx,0    ;行数计数器
            mov si,0    ;每行地址的指针
       next:mov di,10*160+32*2
          mov ax,160
           mul cx
          add di,ax
 
            mov bx,ad[si]
            add si,2
         s0:mov al,cs:[bx]
            cmp al,0    ;一行是否结束
            je s1
            add bx,1
            ;display功能选择
            cmp dis_choice,1
            je s2
            mov byte ptr es:[di],' '
            jmp short s5
         s2:mov es:[di],al
         s5:add di,2
            jmp short s0
       s1:add cx,1
          cmp cx,4
          je dis_end
          jmp short next
  dis_end:pop dx
            pop bx
            pop si
            pop cx
            pop di
            pop es
            pop ax
            ret
            
clock_dis:jmp short s7
format db 'YE/MO/DA hh:mm:ss',0
position db 9,8,7,4,2,0
     s7:mov bx,0
        mov si,0
        mov cx,6
     s9:mov al,position[bx]
        out 70h,al
        in al,71h
        mov ah,al
        push cx
        mov cl,4
        shr ah,cl
        pop cx
        and al,00001111b
         
        add ah,30h
        add al,30h
         
        mov format[si],ah
        mov format[si+1],al
        add si,3
        inc bx
        loop s9
         
        mov ax,0b800h
        mov es,ax
        mov di,160*12+62
        mov si,0
     s8:cmp byte ptr format[si],0
        je s7
        mov al,format[si]
        mov es:[di],al
        inc si
        add di,2
        jmp short s8
codesg ends
end start
2017-07-14 22:42
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:153
专家分:833
注 册:2016-5-15
  得分:0 
先不管代码,楼主要理解的是,键盘缓冲是一个什么样的机制.
每次按键盘都会触发int9,int9处理这个键,若是可读取的字符,就会放在键盘缓冲,
直到键盘缓冲满溢,才会发出嘟嘟的警示声.
int16h,ah=0可以读出键盘缓冲一个键值,读后键盘缓冲会减去一个键
假若键盘缓冲里有9个键,int16h要读取9次才可以完全清除键盘缓冲的键.
所以单一次int16h,并不能 [保证] 完全清除键盘缓冲

完全清除键盘缓的代码,有好几种方式,就上面的原理,可以这样写

readkey:
mov ah,1 ;检查有否按键
int 16h
jz nokey ;没有按键
mov ah,0 ;读一个键
int 16h
jmp short readkey ;回去再检查

nokey:
...
...
2017-07-27 06:52
lishua
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2017-7-14
  得分:0 
回复 3楼 Valenciax
对不起,是我描述的不够清楚,引起了您的误解
其实按照课程设计2,启动以后就进入了菜单选择界面,这时我们不按键盘的话,就不会触发int 9;所以,这里其实确实是只清除一次,不应该写成“清空键盘缓冲区”。我想问的是,为什么清除每次按键的缓冲的位置不同,会引起按3进入时钟显示后,显示效果不一样?按我对代码的理解,这两种写法应该不对影响到clock_dis才对
多谢版主大大啊
2017-07-28 14:13
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:153
专家分:833
注 册:2016-5-15
  得分:0 
没有实测楼主的程式,只凭常理回答好了.

1.
删除一次也好,删除多次也好,楼上的检查按键代码都合适.

2.
按一个键实际会触动int9两次,第1次是按下,第2次是松开.
2017-07-28 20:43
lishua
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2017-7-14
  得分:0 
嗯,我再测一下
多谢版主
2017-07-31 10:03
lishua
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2017-7-14
  得分:0 
我又测了一下,感觉这不是个好问题,算是有点超出了设计本身的范围了,回头我弄明白是怎么回事了再来结贴
2017-08-04 22:32
lishua
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2017-7-14
  得分:0 
回复 3楼 Valenciax
我想我明白您的意思了,确实,在进入dos前可以清一下缓冲区,问题就解决了

与之有关联的,我一直有点想不明白的问题是:在王爽课程设计2要求我们设计的这样一个程序中,除了我们本身按的键,计算机还会有其他往键盘缓冲区中写数据(类似按键)的操作吗?不然的话,我每次在新的int 9中断例程开头都mov ah,0;int 16h应该不会对程序其他地方有影响才对,多谢多谢
2017-08-07 16:55
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:153
专家分:833
注 册:2016-5-15
  得分:0 
理想和实际有差距,理想的情况是只有[一个]按键,但实际上,键盘的灵敏度(物理上的),
按压键时间较长(连按),或多次按键或没有按键(有些键盘须大力按)....这都会影响int9被触动的次数和缓冲的键值,
无论怎样,程式也要考虑最坏的情况,3楼的先侦查再完全清除键盘缓冲有其必要.
2017-08-08 06:28
lishua
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2017-7-14
  得分:0 
受教受教,
2017-08-08 15:26









关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.039817 second(s), 8 queries.
Copyright©2004-2017, BCCN.NET, All Rights Reserved