回 帖 发 新 帖 刷新版面

主题:求高手帮我设计一个报警器

求高手帮我设计一个报警器
在屏幕上显示一个闪烁的红色报警指示灯(形状不限),是否报警可由用户控制,并有报警声音
qqq

回复列表 (共11个回复)

沙发

;我写了一个看适合你不,按Esc退出,按住空格键就会不停的发出蜂鸣声。
;用Masm5.0编译,不足的地方是程序在处理不同的显卡时对闪烁处理的不是很好。
data    segment
    assume    ds:data
l_u    dw 300,160
r_d    dw 320,180
color    db 4    
speed    dw 1000h
ending    db 00h
EscFlag db 00h
data    ends
    
code    segment
    assume    cs:code
main    proc    far
    mov    ax,data
    mov    ds,ax    
    
        cli                                            ;关中断,IF=0
    mov        al,09h                
    mov        ah,35h
    int        21h                               ;取系统09H类型中断向量
    
    push       es                                 ;用堆栈保存
    push       bx
    push       ds                                 ;设置09H 类型中断向量
    mov        dx,offset NewInt9
    mov        ax,seg NewInt9
    mov        ds,ax
    mov        al,09h
    mov        ah,25h
    int        21h
    pop        ds
    in         al,21h                      ;设置8259A中断屏蔽字   
    and        al,11111101b           ;允许IR1键盘中断
        out     21h,al
           sti                                                ;开中断, IF= 1           
    
    mov    bh,07h
    mov    ax,0600h
    xor    cx,cx
    mov    dx,184fh
    int    10h
    
    mov    ax,0012h
    int    10h    
    
draw:    mov    si,word ptr r_d
    sub    si,word ptr l_u
    mov    cx,word ptr l_u
b_loop1:mov    di,word ptr r_d+2
    sub    di,word ptr l_u+2
    mov    dx,word ptr l_u+2
    mov    al,color
b_loop2:mov    ah,0ch
    int    10h
    inc    dx
    dec    di
    jnz    b_loop2
    inc    cx
    dec    si
    jnz    b_loop1    

    cmp    color,4
    je    setcolor
    mov    color,4
    jmp    redraw
setcolor:mov    color,0        
redraw:    call    delay    
    
    test    ending,80h             ;如果用户按下Esc键那么程序结束
    jz    draw
                   
    pop        dx                                 ;恢复系统09H类型中断向量   
    pop        ds
    mov       al,09h
    mov       ah,25h
    int     21h    
    
exit:    mov    ax,0003h
    int    10h                
    
    mov    ah,4ch
    int    21h    
main     endp    
delay    proc    near
    
    mov    cx,speed
d_time1:push    cx
    mov    cx,speed
d_time2:loop    d_time2            
    pop    cx
    loop    d_time1        
    ret

delay     endp
NewInt9    proc    far                               ;重写INT 09H键盘中断服务程序
    push    ax                    ;保存现场
    push    bx
    push    cx
    push    dx
    push    si
    push    di
    push    bp
    push    ds
    cli
    
    xor    cx,cx
NI_nody:in    al,64
    test    al,02
    loopnz    NI_nody
    
    in    al,60h           ;读入字符扫描码    
    
    cmp    al,81h           
    jnz    NI_mkbk             ;松开的不是Esc键
    
    or    ending,80h       
    jmp     NI_exit    
                   
NI_mkbk:and    al,7fh
    cmp    al,39h
    jne    NI_exit        
    in    al,61h
    and    al,11111100b    
    xor    al,2
    out    61h,al
    mov    cx,10
NI_beep:loop    NI_beep        
    and    al,11111100b
    out    61h,al        
        
NI_exit:mov     al,20h          ;发中断结束命令EOI
        out     20h,al
        sti        
        pop    ds
        pop    bp
        pop    di
        pop    si
        pop     dx                     ;恢复现场
        pop    cx
        pop    bx
        pop    ax        
        iret                               ;中断返回
NewInt9 endp
code    ends
    end    main

板凳

真是太感谢了 呵呵[em28][em28]

3 楼

不过好像显示不了那个报警指示灯啊

4 楼

你说的问题我解决掉了。在原来的基础上我改了三个地方,已经能够在屏幕的中间显示一个手指甲大小的红色方块,并且不断的闪烁。
我修改的三个地方是:
1、图形模式号原来是12H,现改为0EH,640*420,16色
2、坐标位置调整了一下,现改为:l_u    dw 300,70    ;左上角坐标;r_d    dw 320,80    ;右下角坐标
3、原来有一段程序是用来清屏的,主要通过滚屏实现清屏的,我估计原来的主要问题在于一是不同显卡的显示模式,二是滚屏把红色方块滚动过去了,你没看到,实际上已经有了。
============================================================================
改过的地方,我都做了记录。我相信应该没问了。
data    segment
    assume    ds:data
l_u    dw 300,70    ;左上角坐标        这里改过了!!!!!!!!!
r_d    dw 320,80    ;右下角坐标
color    db 4    
speed    dw 1000h
ending    db 00h
EscFlag db 00h
data    ends
    
code    segment
    assume    cs:code
main    proc    far
    mov    ax,data
    mov    ds,ax        
    
        cli                                            ;关中断,IF=0
    mov        al,09h                
    mov        ah,35h
    int        21h                               ;取系统09H类型中断向量
    
    push       es                                 ;用堆栈保存
    push       bx
    push       ds                                 ;设置09H 类型中断向量
    mov        dx,offset NewInt9
    mov        ax,seg NewInt9
    mov        ds,ax
    mov        al,09h
    mov        ah,25h
    int        21h
    pop        ds
    in         al,21h                      ;设置8259A中断屏蔽字   
    and        al,11111101b           ;允许IR1键盘中断
        out     21h,al
           sti                                                ;开中断, IF= 1           
;这里改过了!!!!!!!!原来这还有一小段清屏的代码.
    mov    ax,000eh             ;这里改过了!!!!原来的模式号为12h
    int    10h    
    
draw:    mov    si,word ptr r_d
    sub    si,word ptr l_u
    mov    cx,word ptr l_u
b_loop1:mov    di,word ptr r_d+2
    sub    di,word ptr l_u+2
    mov    dx,word ptr l_u+2
    mov    al,color
b_loop2:mov    ah,0ch
    int    10h
    inc    dx
    dec    di
    jnz    b_loop2
    inc    cx
    dec    si
    jnz    b_loop1    

    cmp    color,4
    je    setcolor
    mov    color,4
    jmp    redraw
setcolor:mov    color,0        
redraw:    call    delay        
    test    ending,80h             ;如果用户两次按下Esc键那么程序结束
    jz    draw
                   
    pop        dx                                 ;恢复系统09H类型中断向量   
    pop        ds
    mov       al,09h
    mov       ah,25h
    int     21h    
    
exit:    mov    ax,0003h
    int    10h                
    
    mov    ah,4ch
    int    21h    
main     endp    
delay    proc    near
    
    mov    cx,speed
d_time1:push    cx
    mov    cx,speed
d_time2:loop    d_time2            
    pop    cx
    loop    d_time1        
    ret

delay     endp
NewInt9    proc    far                               ;重写INT 09H键盘中断服务程序
    push    ax                    ;保存现场
    push    bx
    push    cx
    push    dx
    push    si
    push    di
    push    bp
    push    ds
    cli
    
    xor    cx,cx
NI_nody:in    al,64
    test    al,02
    loopnz    NI_nody
    
    in    al,60h           ;读入字符扫描码    
    
    cmp    al,81h           
    jnz    NI_mkbk             ;松开的不是Esc键
    
    or    ending,80h       
    jmp     NI_exit    
                   
NI_mkbk:and    al,7fh
    cmp    al,39h
    jne    NI_exit        
    in    al,61h
    and    al,11111100b    
    xor    al,2
    out    61h,al
    mov    cx,10
NI_beep:loop    NI_beep        
    and    al,11111100b
    out    61h,al        
        
NI_exit:mov     al,20h          ;发中断结束命令EOI
        out     20h,al
        sti        
        pop    ds
        pop    bp
        pop    di
        pop    si
        pop     dx                     ;恢复现场
        pop    cx
        pop    bx
        pop    ax        
        iret                               ;中断返回
NewInt9 endp        
code    ends
    end    main

5 楼

3Q了
不过能不能让那个红色方块和声音同步啊,也就是说按空格键之后才出现闪烁的红块,
而松开之后则消失

6 楼

;搞定了。
data    segment
    assume    ds:data
l_u    dw 300,70    ;左上角坐标
r_d    dw 320,80    ;右下角坐标
color    db 0        ;开始时显示为黑色的方块,按下空格键就黑红交替显示了
speed    dw 1000
ending    db 00h
EscFlag db 00h
data    ends
    
code    segment
    assume    cs:code
main    proc    far
    mov    ax,data
    mov    ds,ax        
    
        cli                                            ;关中断,IF=0
    mov        al,09h                
    mov        ah,35h
    int        21h                               ;取系统09H类型中断向量
    
    push       es                                 ;用堆栈保存
    push       bx
    push       ds                                 ;设置09H 类型中断向量
    mov        dx,offset NewInt9
    mov        ax,seg NewInt9
    mov        ds,ax
    mov        al,09h
    mov        ah,25h
    int        21h
    pop        ds
    in         al,21h                      ;设置8259A中断屏蔽字   
    and        al,11111101b           ;允许IR1键盘中断
        out     21h,al
           sti                                                ;开中断, IF= 1           
        
    mov    ax,000eh        ;设置显示模式0Eh
    int    10h    
    
draw:    mov    si,word ptr r_d        ;在屏幕中间画一个手指甲大小的方块
    sub    si,word ptr l_u
    mov    cx,word ptr l_u
b_loop1:mov    di,word ptr r_d+2
    sub    di,word ptr l_u+2
    mov    dx,word ptr l_u+2
    mov    al,color
b_loop2:mov    ah,0ch
    int    10h
    inc    dx
    dec    di
    jnz    b_loop2
    inc    cx
    dec    si
    jnz    b_loop1    


    call    delay            ;延时
    test    ending,80h             ;如果用户两次按下Esc键那么程序结束
    jz    draw
                   
    pop        dx                                 ;恢复系统09H类型中断向量   
    pop        ds
    mov       al,09h
    mov       ah,25h
    int     21h    
    
exit:    mov    ax,0003h        ;重置显示模式号
    int    10h                
    
    mov    ah,4ch
    int    21h    
main     endp    
delay    proc    near
    
    mov    cx,speed
d_time1:push    cx
    mov    cx,speed
d_time2:loop    d_time2            
    pop    cx
    loop    d_time1        
    ret

delay     endp
NewInt9    proc    far                               ;重写INT 09H键盘中断服务程序
    push    ax                    ;保存现场
    push    bx
    push    cx
    push    dx
    push    si
    push    di
    push    bp
    push    ds
    cli
    
    xor    cx,cx        ;设置循环计数检测64h号I/O端口状态
NI_nody:in    al,64h            
    test    al,02
    loopnz    NI_nody
    
    in    al,60h           ;读入字符扫描码    
    
    cmp    al,81h           
    jnz    NI_mkbk             ;松开的不是Esc键
    
    or    ending,80h       ;设置程序结束标志
    jmp     NI_exit    
                   
NI_mkbk:cmp    al,0b9h        ;空格键的按下时扫描码是39h,按住不松手是39h,松开时扫描码是0b9h
    jne    NI_space
    mov    color,0
    jmp    NI_exit
NI_space:cmp    al,39h        ;按住不松手时空格键的扫描码是39h
    jne    NI_exit

    cmp    color,4        ;原来时红色就变成黑色,原来是黑色就变成红色
    je    NI_color
    mov    color,4
    jmp    NI_sing
NI_color:mov    color,0        
            
NI_sing:in    al,61h        ;这里是用来发出声音的
    and    al,11111100b    
    xor    al,2
    out    61h,al
    mov    cx,10
NI_beep:loop    NI_beep        ;用来延时的
    and    al,11111100b
    out    61h,al        
        
NI_exit:mov     al,20h          ;发中断结束命令EOI
        out     20h,al
        sti        
        pop    ds
        pop    bp
        pop    di
        pop    si
        pop     dx                     ;恢复现场
        pop    cx
        pop    bx
        pop    ax        
        iret                               ;中断返回
NewInt9 endp        
code    ends
    end    main

7 楼

给你这个看看,下面是关于键盘扫描码的介绍。

在Scan Code Set 1中,对于绝大多数键而言,其Make Code,Break Code,以及Repeat Code都是单字节的。其规则为:如果Make Code为nn,则其Repeat code与Make Code相同也是nn,而其Break Code则是将nn与80h进行按位OR运算,也就是将Make Code的最高位bit-7设置为1。比如:键"A"的Make Code位1Eh,其Repeat Code也为1Eh,而其Break Code则为1Eh|80h=9Eh。

还有一些键的Scan Code是双字节的。其规则为:它们的第一个字节都是E0h,对于第2个字节,其规则与单字节Scan Code的规则一样。


对PrtSc/SysRq键而言,其make code = E02AE037,repeat code = E037, break code = E0B7E0AA。

Pause/Break键没有Repeat Code,也没有Break Code,只有Make Code。其Make Code很长,为E11D45E19DC5。


8 楼

楼上的真是横人,哈哈哈
辛苦了,太感谢了 !!!

9 楼

不必客气,我也学到了不少东西。

10 楼

我还想问一下为什么那个红色方块在有的电脑上显示的挺好的,而在有的电脑上却显示不出来或者方块不闪烁,这个和显示器的分辨率有关吗?与程序里的图形模式号有什么关系吗?

我来回复

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