电子钟-汇编程序

    技术2022-05-11  89

    电子钟-汇编程序

            最近一段时间,在做一个题目,主要实现汇编语言下面的电子钟功能.提供主要的设置时间,设置闹铃,显示时间等功能。本来想从网上找个参考,也好让自己更快的完成任务,也更快的入手.没想到,这么大一个Internet竟然没有让我发现一个很好的参考,说的准确一点,其实是根本没有发现任何一个参考. 只有一个是没有完成的,只有大致轮廓,不过我觉得不可行,索性自己,查阅IBM-PC汇编语言程序设计,最后写了个出来,拿出来供大家学习参考.同时如有不妥善指出,希望大家批评指正..主要目的是为了促进提高大家的学习.

           下面是程序,已经在MASM5下编译运行通过..但有个缺点,也是明显的,就是CPU占用率太多.日后有时间再更正好了.

    --------------------------------------------------------------------------------------------------------------------------------------------------

    (请尊重原创,如果引用,请注明出处.)

    ;*************************************************************************** ;Author: ;Date  : 2005/12/24 ;College: Zhejiang University of Science and Technology ;Subject:A simple Colck program writen by Asmble language. ;function: Display Time ;                Set Time ;                Set Clock Ring ;                Set Display Style ;*************************************************************************** ;程序简介: ; 采用驻留中断程序的方式,将系统定时器提供给用户的ICH中断进行重新设计,加载新的 ; 处理程序,使得每秒得到中断。主程序首先注册新的中断处理程序,从系统取得系统时间 ; 然后无限等待,直到在中断程序中检测到有按键事件的发生,然后,主程序取消中断处理程序, ; 开始判断输入的键,然后根据相应的按键,提供相应的设计功能。 ; 中断处理程序每次得到系统定时器的中断时,判断是否到达1秒(约18.2次为1秒)。如果到达 ; 则,更新时间,存入数据区,然后更新数据的显示。当有按键事件发生时,设置数据区的按键 ; 标记为'真'。当主程序检查到该标记为真时,则取消中断程序的驻留。然后处理相应的事件。 ; ;主要步骤: ; 1.定义显示界面 ; 2.调用系统时间,并将得到的二进制数值转换成ASCII码,将数据存入内存 ; 3.定时的将存在内存区的时间数用显示字符串的形式显示出来(采用ICH中断) ; 4.获取键盘按键值,判断键值决定是否退出系统或执行其他功能 ; 5.时间设定功能,通过键盘设定时,分,秒(时:分:秒) ; 6.闹钟功能,定时报声(时:分) ;  ;存在的缺点: ; 1.对输入时间的格式没有严格控制,比如输入11:11:11 同11'11'11,或 11,11,11 ;   同样的效果; ; 2.当程序运行时,由于主程序无限循环,然后等待中断刷新时间,因为无限循环,因此 ;   占用CPU使用时间比较多。以后扩展可采用一些方式比如,WAIT,HLT等功能实现资源的 ;   节省。 ; 3.有些函数可以进一步进行抽象和整合。从而使得代码数量减少。 ; ;参考书籍:IBM-PC汇编语言程序设计(第2版),沈美明,温冬婵,清华大学出版社 ;    296页,中断向量的设置与恢复; ;    301页,定时器中断程序 ;    389页,通用发声程序 ;***************************************************************************  .model small ;-------------------------------------------------------------------------  .stack ;-------------------------------------------------------------------------  .data

    HOUR     db  ? MIN         db  ? SEC        db  ? MSEC     db  ?  

    NHOUR         db 0 ;设置时间使用 NMIN              db 0   ;设置时间使用 NSEC             db 0 ;设置时间使用

    RHOUR         db 1 ;设置闹铃时间使用 RMIN               db 1 ;设置闹铃时间使用 RSEC             db 1 ;设置闹铃时间使用

    FUNKEY db ? ;功能设置使用

    keySw    db 00h ;是否按键开关 RingSw db 00h ;闹铃开关 

    SWITCH db 0FFh ;刷新开关,真,则不断在定时器中断函数中刷新,否则不刷新

     n db 0dh,0ah,'$'  count dw 1    sMsg         db '****  welcome to Simple clock   ****',0dh,0ah,'$'  qMsg         db '**** Please Input q to quit  ****',0dh,0ah                     db '  ','**** Input s to set new Time ****',0dh,0ah                     db '  ','**** Input r to set ringTime ****',0dh,0ah,'$'  setTMsg   db 'Please Input new Time(HH:MM:SS)',0dh,0ah,'$'  setRMsg   db 'Please Input Ring Time(HH:MM)',0dh,0ah,'$'    authorMsg db '---------------------------------------',0dh,0ah             db 'Author:ChengZengcun',0dh,0ah             db 'E-mail:bohemia1985@163.com',0dh,0ah             db 'Zhejiang University of Science and Technology',0dh,0ah             db 'Version 1.0',0dh,0ah             db 'Date:2005/12/23',0dh,0ah             db '---------------------------------------',0dh,0ah,'$'   ;-------------------------------------------------------------------------  .code  

    PUSHA     MACRO        PUSH DS               PUSH      AX               PUSH      BX               PUSH      CX               PUSH      DX           ENDM

    POPA      MACRO               POP DX               POP CX               POP BX               POP AX        POP DS           ENDM

    ;---------------------------------------------------------------------------- ;Main program

    main proc far     start:          mov ax,@data ;allot data segment          mov ds,ax          push ds  ;store the ds

    ;get the System time          call  GETTIME ;取得系统时间          call initUI  ;初始化界面

    ;save old interrupt vector          mov al,1ch  ;al<=vector number          mov ah,35h  ;to get interrupt vector          int 21h  ;call DOS

             push es  ;save registers for restore(old base address)          push bx  ;save offset of interrupt 1CH          push ds

    ;set new interrupt vector          mov dx,offset tUpdate ;dx<=offset of procedure ring          mov ax,seg tUpdate ;ax<=segment of procedure ring          mov ds,ax  ;ds<=ax           mov al,1ch  ;al<=vector#          mov ah,25h  ;to set interrupt vector          int 21h  ;call DOS

             pop ds  ;restore ds          in al, 21h  ;set interrupt mask bits          and al, 11111100b          out 21h,al          sti

      delay:           PUSHA              cmp ds:[keySw],0FFh ;check if any key is pressed         jz exitdelay ;exit delay if any key is pressed

       ringP:   ;闹铃判断           ;mov dl,ds:[MIN]            mov dl,ds:[RHOUR] ;判断闹铃时间(小时)          cmp dl,ds:[HOUR]          jne noRing          mov bl,ds:[RMIN]    ;判断闹铃时间(分钟)          cmp bl,ds:[MIN]          jne noRing

             mov dh,ds:[RingSw] ;check if the Ring Switch is On.(只要调用SETRTIME就会打开闹铃开关)          cmp dh,00h          jz noRing            call  GENSOUND ;call GENSOUND to make clock ring noRing:             POPA          ;wait          jmp delay

    exitdelay:          POPA

            ;restore old interrupt vector          pop dx  ;restore registers(restore the old offset)          pop ds      ;restore old base of interrupt          mov al, 1ch  ;al<=vector#          mov ah, 25h  ;to restore interrupt           int 21h  ;call DOS

             pop ds ;restore ds 

    ;读敲入的按键           mov ah,07h            int 21h          ;mov al,ds:[FUNKEY]          cmp al,'s'          jne next1  

    ;判断读入字符然后进行相应处理,此时中断函数已经取消,只是单线程

    setT:          ; mov ah,07h  ;读字符         ; int 21h          mov ds:[FUNKEY],al             call SETTIME ;调用子函数设置时间         ; mov ah,01h         ; int 21h          mov ds:[keySw],00h          jmp start next1:          cmp al,'r'          jnz next2          mov ds:[FUNKEY],al

             call SETRING;调用字函数设置闹铃时间          mov ds:[keySw],00h

             jmp start

    next2: cmp al,'q'          je endmain          mov ds:[keySw],00h          jmp start   endmain:            mov ax,4c00h ;exit          int 21h main endp

    ;------------------------------------------------------------------------ ;定时中断程序() ; ;Introduction: ;在系统定时器(中断类型为8)的中断处理程序中,有一条中断指令INT 1CH, ;时钟中断每发生一次(约每秒发生18.2次,即55ms发生一次)都要嵌套调用 ;一次中断类型1CH的处理程序。在ROM BIOS例程中,1CH的处理程序只有一条IRET, ;实际上它并没有作任何工作,只是为用户提供了一个中断类型号。如果用户有某种 ;定时周期性的工作需要完成,就可以利用系统定时器的中断间隔,用自己设计的 ;处理程序来代替原有的1CH的中断程序。 ; 本程序就是将原有1CH中断程序进行替换,实现了定时更新时间。采用DOS ;中断驻留中断程序。 ;

    tUpdate proc near          push ds  ;save the working registers          push ax          push bx          push cx          push dx            mov ax, @data ;allot data segment          mov ds, ax           sti

            ;judge if it is time for cUpdate          dec count  ;count for timer interval(约18.2次为1秒)          jnz exit  ;exit if not for 1 second          mov count,18 ;control ring interval delay(10s)

            ;call the CALTIME          call  CALTIME  ;更新时间

    ;检测刷新开关是否打开          mov bl,ds:[SWITCH]          cmp bl,00          jz exit

    ;检测是否有按键按下,取适当的值进行退出控制  PUSHA          MOV      AH, 0BH         ;检测是否输入消息(按键消息)          INT      21H          INC  AL          JNZ      nokey            mov  ds:[keySw],0FFh ;设置已经被按键          POPA          jmp exit nokey:          POPA

             call DISPLYH  ;显示小时          call DISPLYM  ;显示分钟          call DISPLYS  ;显示秒   exit:           cli          mov al,20h  ;set EOI          out 20h,al            pop dx   ;restore the reg.          pop cx          pop bx          pop ax          pop ds          iret   ;interrupt return tUpdate endp

    ;-------------------------------------------------------------------- ;关闭定时刷新开关 closeSw proc near          PUSHA          mov bl,0h          mov ds:[SWITCH],bl ;关闭刷新开关          POPA          ret closeSw endp ;---------------------------------------------------------- ;打开定时刷新开关 openSw proc near          PUSHA          mov bl,0FFh          mov ds:[SWITCH],bl ;打开刷新开关          POPA          ret openSw endp ;--------------------------------------------------------------------------- ;初始化显示界面,可以在此处添加额外的设置选项 initUI proc near          PUSHA    ;设置显示方式(40×25 黑白文本,16级灰度)          mov ah,0h          mov al,00h          int 10h    ;显示头标题          mov dh,00h          mov dl,02h          call MOVCUR          mov dx,offset sMsg ;dx<=offset of sMsg          mov ah,09h  ;to display sMsg          int 21h   ;call DOS    ;显示结尾标题          mov dh,05h          mov dl,02h         call MOVCUR          mov dx,offset qMsg ;dx<=offset of qMsg          mov ah,09h  ;to display qMsg          int 21h   ;call DOS 

     ;显示作者信息          mov dh,09h          mov dl,00h          call MOVCUR          mov dx,offset authorMsg ;dx<=offset of authorMsg          mov ah,09h  ;to display authorMsg          int 21h   ;call DOS 

             POPA          ret initUI endp ;-------------------------------------------------------------------------- ;移动光标(dh:row,dl:col) ; dh ;参数设置行 ; dl ;参数设置列 MOVCUR proc near          PUSHA          ;设置光标位置          mov ah,2h          mov bh,0          int 10h          POPA          ret  MOVCUR endp ;------------------------------------------------------------------------- ;显示小时 DISPLYH     PROC     NEAR           

                PUSHA          ; 设置光标位置          mov dh,2h ;set Row  No.          mov dl,10d ;set Column NO.          call MOVCUR          mov dh,0          mov dl,ds:[HOUR]          call output ;调用output函数输出小时          mov dl,':'          mov ah,02h          int 21h             POPA          RET DISPLYH ENDP

    ;---------------------------------------------------------- ;显示分钟

    DISPLYM PROC NEAR                      PUSHA          ;设置光标位置          mov dh,2h ;set Row  No.          mov dl,13d ;set Column NO.          call MOVCUR          mov dh,0          mov dl,ds:[MIN]          call output          mov dl,':'          mov ah,02h          int 21h

             POPA          RET DISPLYM ENDP

    ;---------------------------------------------------------- ;显示秒 DISPLYS PROC NEAR                      PUSHA          ;设置光标位置          mov dh,2h ;set Row  No.          mov dl,16d ;set Column NO.          call MOVCUR          mov dh,0          mov dl,ds:[SEC]          call output         POPA          ret DISPLYS endp ;---------------------------------------------------------- ;调用DOS中断取得系统时间 GETTIME PROC NEAR                    PUSHA          mov ah,2ch  ;get the System time,CH:CL=(H:M),DH:DL=(s:1/100s)          int 21h          mov ds:[HOUR],CH ;取得小时          mov ds:[MIN],CL ;取得分钟         ; dec DH  ;延迟1秒          mov ds:[SEC],DH ;取得秒          mov ds:[MSEC],DL 

            POPA          ret GETTIME endp

    ;---------------------------------------------------------- ;调整时间,累加秒,分,时

    CALTIME proc near                    PUSHA   ;调整秒          inc ds:[SEC]          cmp ds:[SEC],60d          jb endc          mov ds:[SEC],0h      setM:   ;调整分钟          inc ds:[MIN]          cmp  ds:[MIN],60d          jb endc          mov ds:[MIN],0h      setH:   ;调整小时          inc  ds:[HOUR]          cmp ds:[HOUR],24d          jb endc          mov ds:[HOUR],0h    endc:          POPA         ret CALTIME endp ;--------------------------------------------------------------------------- ;设置时间 SETTIME proc near          PUSHA          call closeSw ;关闭定时刷新          mov dh,11h          mov dl,00h          call MOVCUR ;移动光标             mov dx,00h          mov ah,09h  ;输出提示信息,提示输出设置时间          mov dx,offset setTMsg          int 21h            call READNT ;读取时间(HH:MM:SS)    ;设置时间          mov ch,ds:[NHOUR] ;HOUR           mov cl,ds:[NMIN] ;MIN          mov dh,ds:[NSEC] ;SECOND          mov dl,0h   ;1/100 SECOND          mov ah,2Dh          int 21h

             cmp al,00h          je SetSuccess             mov ah,02h  ;设置时间中断调用失败处理          mov dl,'!'          int 21h    SetSuccess:          call openSw ;打开刷新开关            POPA          ret SETTIME endp ;--------------------------------------------------------------------- ;设置闹铃时间: SETRING proc  near          PUSHA          call closeSw ;关闭定时刷新          mov dh,11h          mov dl,00h          call MOVCUR ;移动光标             mov dx,00h          mov ah,09h  ;输出提示信息,提示输出设置时间          mov dx,offset setRMsg          int 21h            call READRINGT ;读取闹铃时间(HH:MM)            mov ds:[RingSw],0FFH ;设置闹铃开关为 '开'   rSetSuccess:          call openSw ;打开刷新开关            POPA          ret SETRING endp ;------------------------------------------------------------------ ;读取时间(从ASCII码到16进制数值的转换)(HH:MM:SS) READNT proc near          PUSHA          mov ah,01h            int 21h          mov bx,0h        ;bx存放得到的数值(16进制)  loop1: cmp al,'0'  ;读取小时         jl endloop1         cmp al,'9'                         jg endloop1         sub al,30h        ;transform from char to number         cbw         xchg ax,bx         mov cx,0ah        ;put 10d into cx         mul cx              xchg   ax,bx         add bx,ax         mov ah,01h        ;put the read interrupt type                           int 21h           ;call the DOS interrupt                   jmp loop1        ;存取小时 endloop1:            mov ds:[NHOUR],bl;           mov bx,0h;                 loop2:                 mov ah,01h            int 21h      ;bx存放得到的数值(16进制)         cmp al,'0'   ;读取分钟         jl endloop2         cmp al,'9'                         jg endloop2         sub al,30h        ;transform from char to number         cbw         xchg ax,bx         mov cx,0ah        ;put 10d into cx         mul cx              xchg    ax,bx         add bx,ax                jmp loop2             ;存取分钟 endloop2:          mov ds:[NMIN],bl          mov bx,0h     loop3:           mov ah,01h            int 21h     ;bx存放得到的数值(16进制)           cmp al,'0'   ;读取秒         jl rlast         cmp al,'9'                         jg rlast                  sub al,30h        ;transform from char to number         cbw         xchg ax,bx         mov cx,0ah        ;put 10d into cx         mul cx              xchg   ax,bx         add bx,ax                 jmp loop3

    rlast:                  ;存取秒         mov ds:[NSEC],bl                         POPA          ret READNT endp ;---------------------------------------------------------------------------- ;读取闹铃时间 READRINGT proc  near          PUSHA          mov ah,01h            int 21h          mov bx,0h        ;bx存放得到的数值(16进制)  rloop1:           cmp al,'0'   ;读取小时         jl rendloop1         cmp al,'9'                         jg rendloop1         sub al,30h        ;transform from char to number         cbw         xchg ax,bx         mov cx,0ah        ;put 10d into cx         mul cx              xchg   ax,bx         add bx,ax         mov ah,01h        ;put the read interrupt type                           int 21h           ;call the DOS interrupt                   jmp rloop1         ;存取小时 rendloop1:           mov ds:[RHOUR],bl;          mov bx,0h;                 rloop2:                  mov ah,01h            int 21h     ;bx存放得到的数值(16进制)           cmp al,'0'    ;读取分钟         jl rendloop2         cmp al,'9'                         jg rendloop2         sub al,30h        ;transform from char to number         cbw         xchg ax,bx         mov cx,0ah        ;put 10d into cx         mul cx              xchg    ax,bx         add bx,ax                jmp rloop2             ;存取分钟 rendloop2:          mov ds:[RMIN],bl

             POPA          ret READRINGT endp ;----------------------------------------------------------------------------- ;闹铃发声程序 ; ;DI,保存发声频率,CX,BX指定发声程序的持续时间 GENSOUND proc near          PUSHA          push  DI

     ;set the frequency          mov di,020h          mov bx,0FFh

             mov al,0b6h  ;write timer mode reg.          out 43h,al          mov dx,12h  ;timer divisor          mov ax,348ch ;1193100HZ/freq          div di          out 42h,al  ;write timer2 count low byte          mov al,ah           out 42h,al  ;write timer2 count high byte          in al,61h  ;get current port setting          mov ah,al  ;and save it in ah          or al,03h  ;turn speaker on          out 61h,al     waitsound:          mov cx,500h  ;wait for specified intevral           delaySound:          loop delaySound          dec  bx          jnz waitsound          mov al,ah  ;recover value of port          out 61h,al          pop DI             POPA          ret GENSOUND endp ;--------------------------------------------------------------------------- ;输出字符(dx中存放十进制数值) output   proc    near  PUSHA         mov     ax,dx         ;put the final num into ax         mov     dx,00h                     mov     cx,0h  trans:                        mov     bx,000ah      ;this loop put the char into memory         div      bx           ;divide 10d         add     dl,30h        ;transform to character      mov dh,0h         push    dx         inc      cx         mov     dx,00h          cmp     ax,00h         jg      trans              cmp cx,01h          jg print

     addZero:       ;增加前导0,,比如:02         mov dh,0            mov dl,'0'          push  dx          inc  cx   print:                       ;this loop output the char         cmp     cx,0h          jle     endout         pop     dx  mov dh,0         dec     cx         mov     ah,02h         int     21h           ;call DOS output ability                  jmp     print  endout:               POPA         ret output  endp    

    ;----------------------------------------------------------  end start  ;end assemble

     .end


    最新回复(0)