【汇编语言课程设计】电子时钟(基于8086平台)

主文件

;***********************************************************
; 版权所有 (C)2018, WangMeow
;
; 文件名称: main.asm
; 内容摘要:该代码为主程序,用于调用其他功能子程序
; 当前版本: V1.0
; 作   者: WangMeow
; 完成日期: 20180701
;**********************************************************
extrn s1:far,clean:far  ;主程序可调用的外部子程序有显示时间子程序和清屏子程序
assume cs:code,ss:stack,ds:data

stack segment stack
	db 100h dup(0)
stack ends

data segment
	 menu db 10,13,10,13,'      ----------WangMeow.Clock_System----------'
	      db 10,13
	      db 10,13,'          --------------Menu---------------          '
	      db 10,13,'                    1.Show time.'
	      db 10,13,'                    2.Set alarm clock.'
	      db 10,13,'                    0.exit.'
	      db 10,13,'          ---------------------------------          '
	      db 10,13,'          Please choose one of 0~2:','$'
	table dw pro1,pro2

	 tip1 db 10,13,'          Input error!','$'
	 tip2 db 10,13,'          Please set the hour:','$'
	 tip3 db 10,13,'          Please set the minute:','$'
	 
	 hour dw 64h
	 minute dw 64h

data ends


code segment
main proc

aton macro     ;宏定义:将ASCII转换成数字
	sub al,30h
endm

ntoad macro    ;宏定义:将数字转换成各子程序的偏移地址
	shl al,1
	mov bl,al
	mov bh,0
	sub bx,2
endm

outscr macro x		   ;宏定义:输出字符串到屏幕
	lea dx,x           ;ds:dx = 输出字符串的首地址
	mov ah,9           ;调用21h中断的9号功能,输出字符串
	int 21h
endm

inputb macro
mov ah,0ch    ;调用21h中断的c号功能,从键盘读入字符,al保存读入字符的ASCII码
 mov al,01h
int 21h
endm

start:   
    run:
		 mov ax,data   ;设置数据段
		 mov ds,ax

		 outscr menu   ;宏调用     
      	 
		 inputb        ;宏调用

      	 aton          ;宏调用 
      	 cmp al,1      ;输入输入的不在[1,2]这个区间,那么去处理
      	 jb deal
      	 cmp al,2
      	 ja deal

      	 ntoad         ;宏调用

      	 call far ptr clean        ;调用清屏子程序
      	 mov si,00h                ;这里si的作用相当于flag
      	 call word ptr table[bx]   ;使用代码的直接定址表调用子程序

		 jmp run                   ;主程序持续运行


    deal:;用来处理非正常输入
    	 cmp al,0      ;如果是输入是0,程序正常退出
    	 je exit

    	 outscr tip1    ;如果是非正常输入,输出错误提示
    	 
    	 jmp run
    	 
    exit:;程序正常退出
    	 mov ax,4c00h
    	 int 21h

main endp
;*****************************************************************
; 子程序:pro1
; 功能:负责远间调用S1子程序,负责显示时间和时间对比
; 入口参数:无
; 出口参数:无
;*****************************************************************
pro1 proc near         ;PRO1子程序,显示时钟
	 call far ptr s1   ;调用S1子程序
	 ret
pro1 endp

;*****************************************************************
; 子程序:pro2
; 功能:负责设置闹钟,实现小时和分钟的输入
; 入口参数:无
; 出口参数:0:[0200]存放小时的低位,0:[0201]存放小时的高位
; 0:[0202]存放分钟的低位,0:[0203]存放分钟的高位
;调用注意事项:近调用,ret返回
;*****************************************************************
pro2 proc near         ;调用PRO2子程序,用来输入要设置的时间
	  mov ax,0h        ;将输入的时间保存到0:0200h这个物理地址里面
      mov es,ax
      mov bx,0200h
	  
	  outscr tip2      ;宏调用
	  mov cx,2         ;循环两次输入字符
	  mov si,1

  l1: inputb                   ;宏调用,输入小时
      mov es:[bx+si],al        ;将输入的小时的高位存到0201h里面,低位存到0200h里面
      dec si
      loop l1
      
      add bx,2                 ;偏移地址+2
      outscr tip3              ;宏调用
      mov cx,2		           ;循环两次输入字符
      mov si,1

  l2: inputb                   ;宏调用,输入分钟
      mov es:[bx+si],al        ;将输入的分钟的高位保存到0203h里面,低位保存到0202h里面
      dec si 
      loop l2
      ret

pro2 endp

code ends
end start

其他子文件 

;***********************************************************
; 版权所有 (C)2018, Wang Miao
;
; 文件名称: show.asm
; 内容摘要:该代码为子程序,用于动态时间显示以及时间对比
; 当前版本: V1.0
; 作   者: 汪淼
; 完成日期: 20180701
;**********************************************************
public s1    ;显示时间子程序
extrn clean:far,music:far   ;显示时间子程序可调用的外部子程序有清屏子程序和音乐子程序

assume cs:code
code segment
s1 proc

show macro x,col    ;宏定义,使用70h和71h端口获取系统时间
      mov al,x
      out 70h,al
      in al,71h
      
      mov ah,al     ;13---18行代码是把系统时间的高位保存到ah,低位保存到al
      mov cl,4
      shr ah,cl
      and al,00001111b
      add ah,30h
      add al,30h
      mov bx,0b800h
      mov es,bx

      mov byte ptr es:[160*12+col*2],ah ;两个字节代表屏幕的一列,将代表时间的字符放入屏幕显示缓冲区
      mov byte ptr es:[160*12+col*2+2],al
endm

sym macro
	mov byte ptr es:[160*12+32*2],'/'   ;美化时间显示
	mov byte ptr es:[160*12+35*2],'/'
	mov byte ptr es:[160*12+38*2],' '
	mov byte ptr es:[160*12+41*2],':'
	mov byte ptr es:[160*12+44*2],':'
endm

start:
	call disptime
	mov ah,01h          ;检查是否有键盘输入
	int 16h

	jz start            ;表示位ZF = 1时,无键盘输入,继续显示时间
	mov ah,00h          ;如果有键盘输入
	int 16h

	cmp al,27           ;ESC的ASCII是27(10进制)
	jnz start           ;如果按住的键盘不是ESC,继续显示时间
	call far ptr clean  ;如果是ESC,那么返回主程序
	retf


;*****************************************************************
; 子程序:disptime
; 功能:负责动态显示时间
; 入口参数:日期在70h端口处的地址
; 出口参数:无
;*****************************************************************
disptime proc near
		 show 9,30         ;年
         show 8,33         ;月
         show 7,36         ;日
         show 4,39         ;小时
         call judge1       ;判断设置的小时与当前显示的是否一致
         show 2,42         ;分钟
         call judge2	   ;判断设置的分钟与当前显示的是否一致
         show 0,45         ;秒
         sym               ;符号

         cmp si,01h        ;如果flag = 1,说明闹钟与显示时间一直,响铃
         je alarm
         ret

  alarm: call far ptr music  
  		 ret
disptime endp

;*****************************************************************
; 子程序:judge1
; 功能:负责判断设置的小时是否与显示的小时一直
; 入口参数:0:[0200]存放的小时的低位,0:[0201]存放的小时的高位
; 出口参数:无
;*****************************************************************
judge1 proc near          ;判断小时的子程序
		mov dx,0h
	  	mov es,dx
	  	mov bp,0200h

	  	mov ch,es:[bp]
	  	cmp ch,al         ;al是小时的低位
	  	jne nset

	  	inc bp
	  	mov ch,es:[bp]
	  	cmp ch,ah         ;ah是小时的高位
	  	jne nset

	  	jmp set
judge1 endp

;*****************************************************************
; 子程序:judge2
; 功能:负责判断设置的分钟是否与显示的分钟一直
; 入口参数:0:[0202]存放的分钟的低位,0:[0203]存放的分钟的高位
; 出口参数:无
;*****************************************************************
judge2 proc near         ;判断分钟的子程序
		mov dx,0h
	  	mov es,dx
	  	mov bp,0202h

	  	mov ch,es:[bp]
	  	cmp ch,al
	  	jne nset

	  	inc bp
	  	mov ch,es:[bp]
	  	cmp ch,ah
	  	jne nset

	  	jmp set
judge2 endp

return: ret         ;这里标注一下,感谢贺老师的深刻教会,不应该在这里破坏函数的一体性

set:  mov si,01h
      jmp return    ;这里标注一下,感谢贺老师的深刻教会,不应该在这里破坏函数的一体性
nset:
 	  mov si,00h
 	  jmp return    ;这里标注一下,感谢贺老师的深刻教会,不应该在这里破坏函数的一体性

s1 endp

code ends
end start
;***********************************************************
; 版权所有 (C)2018, Wang Miao
;
; 文件名称: cls.asm
; 内容摘要:该代码为子程序,用于清屏
; 当前版本: V1.0
; 作   者: 汪淼
; 完成日期: 20180701
;**********************************************************
public clean ;清屏子程序
.8086
.MODEL small
.stack 10h
.code
;*****************************************************************
; 子程序:clean
; 功能:负责实现清屏功能
; 入口参数:无
; 出口参数:无
;*****************************************************************
clean proc

start: 
	  mov ah,0fh         ;读取显示器模式,dosbox中显示模式是80x25     
	  int 10h
	  mov ah,0h          ;设置显示器模式
	  int 10h

   	  retf

clean endp

end start
;***********************************************************
; 版权所有 (C)2018, Wang Miao
;
; 文件名称: mus.asm
; 内容摘要:该代码为子程序,用于音乐响铃
; 当前版本: V1.0
; 作   者: 汪淼
; 完成日期: 20180701
;**********************************************************
public music  ;音乐子程序
.8086
.MODEL small
.stack 100h

.data
mus_freq dw 524,524,784,784,880,880,784   ;闹钟的音乐,这里的音乐是一闪一闪亮晶晶
         dw 698,698,659,659,587,587,524
         dw 784,784,698,698,659,659,587
         dw 784,784,698,698,659,659,587
         dw 524,524,784,784,880,880,784
         dw 698,698,659,659,587,587,524
         dw -1

mus_time dw 3 dup(25,25),25                ;音乐节奏(音长)
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25
         dw 3 dup(25,25),25

.code
music proc
start:

    mov ax, @data
    mov ds, ax

    lea si, mus_freq
    lea di, mus_time

play:
    mov dx, [si]
    cmp dx, -1       ;如果是最后一个音符,那么结束演奏
    je end_play                     
    call sound       ;否则,调用演奏子程序
    add si, 2
    add di, 2
    jmp play

;*****************************************************************
; 子程序:sound
; 功能:负责演奏一个音符
; 入口参数:si - 要演奏的音符的频率的地址 di - 要演奏的音符的音长的地址
; 出口参数:无
;*****************************************************************
sound:
    push ax
    push dx
    push cx

    ;8253 芯片(定时/计数器)的设置
    mov al,0b6h       ;8253初始化
    out 43h,al        ;43H是8253芯片控制口的端口地址
    mov dx,12h
    mov ax,34dch
    div word ptr [si] ;计算分频值,赋给ax。[si]中存放声音的频率值。
    out 42h, al       ;先送低8位到计数器,42h是8253芯片定时器通道2的端口地址
    mov al, ah
    out 42h, al       ;后送高8位计数器

    ;设置8255芯片, 控制扬声器的开/关
    in al,61h   ;读取8255 B端口原值      PB口的最低两位:PB0:控制8253定时器,PB1:控制喇叭发声
    mov ah,al   ;保存原值
    or al,3     ;使低两位置1,以便打开开关
    out 61h,al  ;开扬声器, 发声

    mov dx, [di]       ;保持[di]时长
wait1:
    mov cx, 28560      ;1s = 1428次循环,这里设置一首音乐20s
delay:
    nop
    loop delay
    dec dx
    jnz wait1

    mov al, ah         ;取回8255的PB口原值
    out 61h, al        ;回复8255PB口,停止发声

    pop cx
    pop dx
    pop ax
    ret

end_play:
    retf

music endp

end start

猜你喜欢

转载自blog.csdn.net/m0_37624640/article/details/81262232