电子闹钟程序的设计(2020年大三上学期期末汇编课设)
摘要
设计一个电子闹钟,用汇编语言编写电子闹钟程序,在唐都实验箱上实现硬件接线,通过对计数器8254,可编程并行接口芯片8255以及中断控制芯片8259的应用,实现调用显示子程序、调用闹钟子程序、调用整点报时子程序、暂停子程序、播放音乐子程序、删除闹钟子程序、时间清零子程序(秒表),其中,程序不断反复扫描小键盘的按键是否被按下,按下不同的按键将会进入不同的子程序中。在达到完成电子闹钟课设的基本要求的基础上进一步有了新的如播放音乐,清零,暂停等新的创新。
关键词:电子闹钟 汇编语言 8259 8255
1.前言
1.1项目背景
在学习了汇编语言程序设计和接口技术并进行了基础的软件编程、硬件接线实验之后,需要对其有更加深入的了解,于是我们在此次汇编语言与接口技术课程设计的过程中选择了电子闹钟这个题目,在分析电子闹钟的需求分析以及实现原理的基础上,深入了解并掌握汇编程序设计,掌握接口的实际应用,设计出一个可以实现设置闹钟,定点报时,整点报时的闹钟。
1.2目的意义
在汇编语言与接口技术课程设计–电子闹钟的设计与实现过程中,培养设计汇编语言程序的能力,初步的设计构思及创新能力,设计和应用计算机接口的实践能力。在掌握汇编语言指令的用法、汇编语言程序设计的基本设计方法和结构以及Intel 8259A、8255、8253接口芯片的功能和控制方法的基础上,结合电子闹钟的设计与实现,深入理解并掌握80X86汇编语言的相关知识及上述接口电路的工作原理。
在实验中分工合作,共同完成系统设计与实现。在团队合作中,完成个体、团队成员或负责人的任务和职责。增强总结、规纳、整理、交流、倾听他人意见等团队协作的能力。
在实验总结中掌握研究技术报告的撰写方法,提高综合应用已有知识解决实际问题的能力,增强专业技术能力和综合素质。
2.主要任务
2.1项目概述
电子闹钟程序的实现由硬件接线和汇编语言程序编写两部分完成。在分析电子闹钟的工作原理后确定要使用的芯片以及使用方式,在MASM上完成电子闹钟汇编语言程序的编写与调试,在唐都实验箱中实现硬件接线以及基础的输入输出测试,在WMd86中实现汇编语言电子闹钟程序与硬件接口的结合,通过编写代码并进行调试实现在唐都仪器实验箱的数码显示器上输出电子时钟时间,在小键盘上实现外部输入时钟初始时间、闹钟响铃时间,在蜂鸣器上实现播放音乐的功能,从而实现电子闹钟设置初始时间,设置闹钟,删除闹钟,暂停时间,定点报时,整点报时,播放音乐的功能。
2.2需求分析
电子闹钟作为闹钟,需要实现最基础的功能就是定时功能,在闹钟设定的时间播放指定音乐。在此基础之上我们希望闹钟的音乐可选,而不是局限于单一的蜂鸣音。具体的功能分析如下。
**1.定时闹钟:**从外部输入闹钟提醒的时间,在时钟走到对应时间时播放设置的音乐。 需要将闹钟提醒的时间存储起来,同时与显示的时间不断进行对比,看是否与设定时间一致。
**2.时钟运行:**电子闹钟需要像普通的时钟一样具有基本的指示时间的功能,能够实现每过一秒秒钟加1,每过一分钟加1,每过一个小时时钟加1.
**3.显示时间:**在七段数码管上显示当前时间,需要用到六个七段数码管来实现时,分,秒的显示。
**4.整点报时:**在整点发出蜂鸣声提示。
**5. 设置时间:**闹钟的初始时间可以由外部键盘输入的数据决定,不输入时默认从00时00分00秒开始运行。
**6.暂停时间:**可以点击外部键盘特定的键,实现暂停。
**7.删除闹钟:**点击外部键盘特定的键,可以将之前存入的闹钟时间删除掉,到了特定时间将不再响铃。
**8.播放音乐:**按下外部键盘的特定两个键可以播放两首歌,一个键对应一首歌。同时,按下另一个暂停音乐的键可以停止播放音乐。
9.秒表计时功能:同时也是对时间的清零功能,通过小键盘上的某一特定按键来实现。
3.总体设计
3.3功能设计
我们将电子闹钟的实现分为中央总控模块,设定时间模块,设定闹钟模块,以及其他模块如秒表计时,删除闹钟,播放音乐等,其他模块的功能都有实现,在软件设计章节有详细描述。
(1)中央总控模块
中央总控模块(如图3.1-1)需要首先对各个芯片实现初始化,设置初始时间,并且开始调用8254,8259A开始计时,此时系统需要在外部显示时间并完成整点报时,如果此时接收到外部键入指令,则调用相应子模块(更改)设置初始时间,设置闹钟时间或者设置音乐。之后不断将当前时间与设置闹钟时间进行比较,相同则开始报时。当整点报时和定点报时冲突时,我们设置定点报时具有优先级。
中央总控模块中又包含显示时间子模块、时钟运行子模块、整点报时子模块、暂停时间子模块、删除闹钟子模块、播放音乐子模块六大子模块。
(2)设置初始时间模块
由于设置初始时间模块(图3.1-2)和设置闹钟时间模块的基本原理相同,都是用户从外部以时:分:秒的格式将时间键入,程序将其存放在指定的存储器中以供之后电子闹钟对于时间的调用,二者只有存储的地址不同这一个区别,因此我们只以设置初始时间为例介绍这两个模块。
图3.1-2设置初始时间模块流程图
(3)音乐播放子模块流程图
音乐播放子模块(图3.1-3)一个音符对应一个频率,将对应一个音符频率的方波通到扬声器上,就可以发出这个音符的声音,音乐播放模块实际上就是按照事先存储在存储单元中的频率表计算出每个音符对应的计数初值,然后依次写入8254的计数器。将时间表中相对时间值代入延时程序来实现演奏时间。
图3.1-3音乐播放模块流程图
(4)设置音乐子模块流程图
设置音乐子模块(图3.1-4)设置音乐模块需要提供预设音乐的标号以及存储地址,在提示用户选取音乐标号后将对应的音乐存储在调用的位置即可。
图3.1-4设置音乐模块流程图
3.1硬件设计
可编程并行接口8255实现基本的输入输出。电子闹钟有基本的输入输出,即从外部输入电子闹钟的初始时间,输入设置闹钟的时间,输出当前时钟时间以及在整点或定点时输出报时声。将8255A与键盘即数码管显示单元相连,编写相应的实验程序,就可以扫描键盘输入,并将扫描结果送数码管显示。通过唐都实验箱右下角的4×4键盘实现外部输入,从而设置电子闹钟的初始时间以及设置闹钟时间。
可编程计数器8254以及中断控制器8259配合实现闹钟的正常运行,电子闹钟需要每过1s秒钟加1,将8254的计数器0设为方式三,并对其进行计数初值的设置,可以实现每1ms发出一次方波,结合8259的中断配合程序循环,可以实现经过100次中断后秒钟加1,即每过1s秒钟加1。
可编程计数器8254还用来实现音乐播放模块。利用8254的方式三,将频率的计数初值写入计数器就可以产生对应频率的方波。一个音符对应一个频率,将对应一个音符的方波通到连通器上,就可以发出这个音符的声音。
硬件设计接线图如(图3.1-5)
图3.1-5 硬件设计接线图
4.详细设计
4.1整体思路
开始时设定程序中将会用到的各个变量,同时初始化用到的计数器8254,输入输出芯片8255,,设置KK1和KK2对应的中断,进一步进入主程序。
整个主程序将会反复调用显示子程序、调用闹钟子程序、调用整点报时子程序、暂停子程序、播放音乐子程序、删除闹钟子程序、时间清零子程序(秒表)。按下不同的按键将会进入不同的子程序中。
程序不结束,将会一直执行下去,直到关闭实验箱开关。
4.2实验线路设计
(1)时钟显示部分功能实现线路设计:
通过对计数器8254设定计数值对脉冲进行计数,在程序里,8254工作于计数器0,方式3。接入的CLK为1MHz,设计数初值为10000用来产生10ms的脉冲,每100次中断计数一次,产生的记数时间正好是时钟每秒走过的时间。计数器1,方式3接入1MHz,OUT1链接蜂鸣器,来完成音乐播放的功能。
通过对中断控制器8259设置初始化命令字初值来控制中断。初始化MIR7端口,OUT0链接MIR7,1秒产生一次中断。程序中通过移位指令来实现时、秒、分的个位和十位的独自存储,将分、秒的个位十位分别存入指定的内存空间中。比较转移指令来完成秒和分的累加。
七段数码管由8255并行接口的A口进行灯的选择,通过B口输出要显示的段码。这样就在6个七段数码管上分别显示时、分和秒。当1S时间到时,修改当前数码管数值,10秒时将秒的低位清零,高位加1,分和时亦是如此;到达60秒时,将秒清零,分加1,到达60分时,将分清零,小时加1,到达24小时则全部清零。
显示模块是将显示缓冲区的数值送到LED显示的功能模块,显示缓冲区是由六个字节构成,分别保存小时的高位和低位,分钟的高位和低位,秒钟的高位和低位。硬件上由六个LED构成,软件上由扫描显示的方法实现。
(2) 定时闹钟功能实现线路设计:
首先要完成数码管显示单元按键的连接和设计,让16个按键分别为0-F;让KK1链接SIR1,初始化SIR1端口,再利用实验平台的单次脉冲输入KK1产生一次中断,这样就可以设置闹钟时间了。
定时模块是为8259提供中断请求信号的。由一片8254实现,选用计时器0,工作在方式3,由于时钟应该1秒走动一次,所以输出值应为1S,其输出信号可作为8259的中断请求信号。
将设置好的时间储存起来,时刻与当前的时间进行比较,当时间一样时,计数器1工作,蜂鸣器蜂鸣,播放音乐,这就完成了闹钟响铃功能。
其中响音乐时,一个音符对应一个频率,将对应一个音符频率的方波通到扬声器上,就可以发出这个音符的声音。将一段乐曲的音符对应频率的方波依次送到扬声器,就可以演奏出这段乐曲。利用8254的方式3——“方波发声器”,将相应一种频率的计数初值写入计数器,就可产生对应频率的方波。
(3) 整点报时功能实现线路设计:
时钟的分和秒部分与零进行比较,当他们都相等时,就代表到达整点了,可以响铃了。整点报时就完成了。
(4)设置时间功能的实现线路设计:
用到了数码管显示单元的按键部分,只要利用之前的设计就好了,KK2链接MIR6端口,这次使用单次脉冲输入的KK2产生中断设置时间,再将设置的时间存储在时间变量中,时间就设置好了。
(5)总体线路图及其工作原理
A口工作与方式0,作为数码管控制及输出单元
B口工作与方式0,作为输出口与数码管相连
C口工作在方式0,低四位作为输入端口
计数器0:工作方式3,CLK为1MHZ,计数初值为10000,先读写低八位后读写高八位 00110110 36H 计数格式采用2进制
计数器1:工作方式3,CLK为1MHZ,计数初值为10000,先读写低八位后读写高八位 01110110 76H 计数格式采用2进制
工作原理如下:
PB0-7对应一个数码管的各个段,PA0-5分别控制留六个七段数码管,同时PA0-3和PC0-3对应实验箱的44小键盘用来输入时间。
首先通过kk2给8259一个中断脉冲,从而用小键盘可以输入时间,通过数据总线传到CPU。这时初始时间就设置好了。当秒的个位累加到10时十位加1并将个位清零,当秒累计到60时将分的个位加一,同时秒清零;当分和秒都记到60时,时钟个位加1并且分秒清零;小时记到24时将时,分,秒清零重新计时。
如果要设置闹钟时,要用kk1给8259一次脉冲,使8259产生一次中断,从而在小键盘上输入时间。
当将设置好的时间储存起来,时刻与当前的时间进行比较,当时间一样时,计数器1工作,蜂鸣器蜂鸣,播放音乐,这就完成了闹钟响铃功能。
时钟的分和秒部分与零进行比较,当他们都相等时,就代表到达整点了,可以响铃了。整点报时就完成了。
4.3软件设计
4.3.1初始化
首先要初始化8255,8259,8253三个芯片,写SIR1,MIR6,MIR7三个中断端口的初始化:
MOV DX, CON8254 ;8254
MOV AL, 36H ;计数器0,方式3
OUT DX, AL
;分频
MOV DX, A8254
MOV AX,10000
OUT DX, AL
MOV AL,AH
OUT DX, AL
;8255初始化------------->设置控制字
MOV AL,81H
MOV DX,MY8255_CON
OUT DX,AL
;MIR7中断---------取MIR7的段基址和偏移地址到003CH开始的空间
MOV AX, 0000H
MOV DS, AX
MOV AX, OFFSET MIR7 ;取中断入口地址
MOV SI, 003CH ;中断矢量地址
MOV [SI], AX ;填IRQ7的偏移矢量
MOV AX, SEG MIR7 ;段地址
MOV SI, 003EH
MOV [SI], AX ;填IRQ7的段地址矢量
;MIR6中断---------取MIR6的段基址和偏移地址到0038H开始的空间
MOV AX, OFFSET MIR6 ;取中断入口地址
MOV SI, 0038H ;中断矢量地址
MOV [SI], AX ;填IRQ6的偏移矢量
MOV AX, SEG MIR6 ;段地址
MOV SI, 003AH
MOV [SI], AX ;填IRQ6的段地址矢量
;SIR1中断---------取SIR1的段基址和偏移地址到0038H开始的空间
MOV AX, OFFSET SIR1 ;取中断入口地址
MOV SI, 00C4H ;中断矢量地址
MOV [SI], AX ;填SIR1的偏移矢量
MOV AX, SEG SIR1 ;段地址
MOV SI, 00C6H
MOV [SI], AX ;填SIR1的段地址矢量
;8259初始化
MOV AL, 11H
OUT 20H, AL ;ICW1
MOV AL, 08H
OUT 21H, AL ;ICW3
MOV AL,04H
OUT 21H,AL ;ICW2
MOV AL, 03H
OUT 21H, AL ;ICW4
;初始化从片8259
MOV AL, 11H
OUT 0A0H, AL ;ICW1
MOV AL, 30H
OUT 0A1H, AL ;ICW2
MOV AL, 02H
OUT 0A1H, AL ;ICW3
MOV AL, 01H
OUT 0A1H, AL ;ICW4
MOV AL, 0FDH
OUT 0A1H,AL ;OCW1 = 1111 1101
MOV AX,SEG N_TIME ;取N_TIME的段地址
MOV DS,AX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV [SI+1],1
STI ;可以响应可屏蔽中断请求
4.3.2主程序
主程序AA1将会反复调用显示子程序、调用闹钟子程序、调用整点报时子程序、暂停子程序、播放音乐子程序、删除闹钟子程序、时间清零子程序(秒表)。按下不同的按键将会进入不同的子程序中:
AA1:
CALL DISP ;调用显示子程序(disp)
CALL BJ ;调用闹钟(bj)
CALL ZDBS ;调用整点报时(ZDBS)
CALL CLP ;暂停和继续
CALL QL ;时间初始化(秒表)
CALL DG1 ;播放音乐1
CALL DG2
CALL DG3
CALL CLCLOCK ;清空闹钟
JMP AA1
按下KK1或KK2进入设置时间或设置闹钟模块,分别对应代码中的STR1和MIR6,这两大模块均是根据实验指导书上44矩阵键盘来完成的,它会调用显示子程序、清屏、扫描有无键按下、有键按下在扫描是哪个键按下的、最后存入相应的变量空间中,两大模块基本一致,只是存入的变量空间不同,也就是PUTBUF子程序不同:
MIR6 PROC
CLI
PUSH AX
PUSH SI
MOV AX,DATA
MOV DS,AX
MOV SI,3000H
MOV AL,00H
MOV [SI],AL ;清显示缓冲
MOV [SI+1],AL
MOV [SI+2],AL
MOV [SI+3],AL
MOV [SI+4],AL
MOV [SI+5],AL
MOV DI,3005H
MOV DX,MY8255_CON ;写8255控制字
MOV AL,81H
OUT DX,AL
BEGIN: CALL DIS ;调用显示子程序
CALL CLEAR ;清屏
CALL CCSCAN ;扫描
JNZ INK1
JMP BEGIN
INK1: CALL DIS
CALL KEYDALLY
CALL KEYDALLY
CALL CLEAR
CALL CCSCAN
MOV AX,SEG DUAN ;取DUAN的段地址
MOV DS,AX
MOV SI,OFFSET DUAN ;取DUAN的地址偏移量,用于技计数
MOV AL,[SI]
INC AL
MOV [SI],AL
CMP AL,7 ;AL与6相比较
JE B2
JNZ INK2 ;有键按下,转到INK2
JMP BEGIN
;========================================
;确定按下键的位置
;========================================
B2: MOV AL,0
MOV [SI],AL
POP AX
POP SI
IRET
INK2: MOV CH,0FEH
MOV CL,00H
COLUM: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
L1: TEST AL,01H ;is L1?
JNZ L2
MOV AL,00H ;L1
JMP KCODE
L2: TEST AL,02H ;is L2?
JNZ L3
MOV AL,04H ;L2
JMP KCODE
L3: TEST AL,04H ;is L3?
JNZ L4
MOV AL,08H ;L3
JMP KCODE
L4: TEST AL,08H ;is L4?
JNZ NEXT
MOV AL,0CH ;L4
KCODE: ADD AL,CL
CALL PUTBUF
PUSH AX
KON: CALL DIS
CALL CLEAR
CALL CCSCAN
JNZ KON
POP AX
NEXT: INC CL
MOV AL,CH
TEST AL,08H
JZ KERR
ROL AL,1
MOV CH,AL
JMP COLUM
KERR: JMP BEGIN
;========================================
;键盘扫描子程序
;========================================
CCSCAN: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
RET
;========================================
;清屏子程序
;========================================
CLEAR: MOV DX,MY8255_B
MOV AL,00H
OUT DX,AL
RET
;========================================
;显示子程序
;========================================
DIS: PUSH AX
MOV SI,3000H
MOV DL,0DFH
MOV AL,DL
AGAIN: PUSH DX
MOV DX,MY8255_A
OUT DX,AL
MOV AL,[SI]
MOV BX,OFFSET TAB
AND AX,00FFH
ADD BX,AX
MOV AL,[BX]
MOV DX,MY8255_B
OUT DX,AL
CALL KEYDALLY
INC SI
POP DX
MOV AL,DL
TEST AL,01H
JZ OUT1
ROR AL,1
MOV DL,AL
JMP AGAIN
OUT1: POP AX
RET
;====== 延时子程序 ======
KEYDALLY: PUSH CX
MOV CX,0006H
D1: MOV AX,009FH
D2: DEC AX
JNZ D2
LOOP D1
POP CX
RET
;========================================
;存键盘值到相应位的缓冲中
;========================================
PUTBUF: MOV SI,DI
MOV [SI],AL
MOV CX,SEG DUAN ;取DUAN的段地址
MOV DS,CX
MOV SI,OFFSET DUAN ;取DUAN的地址偏移量
MOV BX,[SI]
MOV CX,SEG N_TIME ;取DUAN的段地址
MOV DS,CX
MOV SI,OFFSET N_TIME ;取DUAN的地址偏移量
MOV [SI+BX],AL
MOV DX,[SI+BX]
DEC DI
CMP DI,2FFFH
JNZ GOBACK
MOV DI,3005H
GOBACK: RET
4.3.3整点报时
整点报时子程序就是将存入变量MIN,SEC中的分秒与零比较,如果都为零则发出嗡鸣声:
ZDBS PROC ;整点报时
MOV AL,MIN
CMP AL,00H
JNZ LP2
MOV AL,SEC
CMP AL,00H
JNZ LP2
MOV DX, CON8254 ;8254
MOV AL, 76H ;计数器1,方式3
OUT DX, AL
ZD1:
MOV DX, B8254
MOV AL, 00H
OUT DX, AL
MOV AL, 09H
OUT DX, AL
MOV AL,SEC
CMP AL,05H
JE OUTZD
CALL DISP
JMP ZD1
OUTZD:
MOV AX,00H
OUT DX,AL
MOV AL,AH
OUT DX,AL
RET
LP2: RET
ZDBS ENDP
4.3.4显示时间
显示模块DISP就是是调用显示子程序,通过TAB表中的数据,将当前的时分秒通过8255A和8255B端口输出到七段数码管中。
DISP PROC的代码及注释如下:
PUSH BX
PUSH DI
PUSH AX
PUSH SI
MOV DX,MY8255_B
MOV AX,SEG TAB
MOV DS,AX
MOV BX,OFFSET TAB
MOV AL,SEC
AND AL,0FH ;与低四位相与
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0DFH
OUT DX,AL
CALL DALLY
MOV AL,SEC
AND AL,0F0H
ror al,04
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0EFH
OUT DX,AL
CALL DALLY
MOV AL,MIN
AND AL,0FH
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0F7H
OUT DX,AL
CALL DALLY
MOV AL,MIN
AND AL,0F0H
ror al,04
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0FBH
OUT DX,AL
CALL DALLY
MOV AL,HOUR
AND AL,0FH
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0FDH
OUT DX,AL
CALL DALLY
MOV AL,HOUR
AND AL,0F0H
ror al,04
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0FEH
OUT DX,AL
CALL DALLY
POP SI
POP AX
POP DI
POP BX
RET
4.3.5调用闹钟
调用闹钟模块:BJ PROC,比较当前的时分秒与N_TIME中的设定的时间,若当前时间与所设定时间相同时,通过设置8254的控制字设置B8254的工作方式,给B8254设计数初值,通过调用音乐的音调表和时间表来让嗡鸣器响铃,判断音调表中的0来判断是否到曲末,到曲末时设B8254计数初值为0,返回主程序。
BJ PROC的代码及注释如下:
BJ PROC ;闹铃程序
MOV AL,HOUR
MOV CX,SEG N_TIME ;取N_TIME的段地址
MOV DS,CX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV BL,[SI+1]
ROL BL,04
MOV AL,0
MOV AL,[SI+2]
OR BL,AL
CMP AL,BL
JNZ LP
MOV CX,SEG N_TIME ;取N_TIME的段地址
MOV DS,CX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV BL,[SI+3]
ROL BL,04
MOV AL,0
MOV AL,[SI+4]
OR BL,AL
MOV AL,MIN
CMP AL,BL
JNZ LP
MOV CX,SEG N_TIME ;取N_TIME的段地址
MOV DS,CX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV BL,[SI+5]
ROL BL,04
MOV AL,0
MOV AL,[SI+6]
OR BL,AL
MOV AL,SEC
CMP AL,BL
JNZ LP
MOV DX, CON8254 ;8254
MOV AL, 76H ;计数器1,方式3
OUT DX, AL
BEGIN_M: MOV BX,OFFSET ST
MOV DI,OFFSET SL ;装入时间表起始地址
PLAY: MOV DX,0FH ;输入时钟为1MHz,1M = 0F4240H
MOV AX,4240H
DIV WORD PTR [BX] ;取出频率值计算计数初值,0F4240H / 输出频率
MOV DX,B8254
OUT DX,AL ;装入计数初值
MOV AL,AH
OUT DX,AL
MOV DL,[DI] ;取出演奏相对时间,调用延时子程序
CALL DALLY2
ADD BX,2
INC DI
CMP WORD PTR [BX],0 ;判断是否到曲末?
JE OUTPLAY
CALL DISP
JMP PLAY
OUTPLAY:MOV DX,B8254
MOV AX,00H
OUT DX,AL
MOV AL,AH
OUT DX,AL
RET
LP: RET
DALLY2 PROC ;延时子程序
H0: MOV CX,0010H
H1: MOV AX,0FF0H
H2: DEC AX
JNZ H2
LOOP H1
DEC DL
JNZ H0
RET
DALLY2 ENDP
BJ ENDP
4.3.6暂停或继续
通过按下小键盘上设定的某一按键,关闭中断,来使时间暂停,暂停后时间停留在当前的时间,接下来通过按其他按键开中断使得时间继续走动。这涉及到了对小键盘的扫描,这一块是参照实验指导书进一步进行设计的,代码和注释如下:
PAUSE PROC
CCSCAN_PAU: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK_PAU
JMP Z_PAU
INK_PAU: MOV CH,0FBH
MOV CL,00H
COLUM_PAU:MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,04H ;is L1?
JNZ Z_PAU
MOV AL,08H ;L3
MOV CL,0
KCODE2: ADD AL,CL
CLI
CALL DALLY_ANJIAN
CCSCAN3:
MOV DX,MY8255_A
OUT DX,AL
MOV AX,SEG TIMER ;取TIMER的段地址
MOV DS,AX
MOV SI,OFFSET TIMER ;取TIMER的地址偏移量
MOV AL,[SI+6]
MOV BL,[SI+5]
ROR BL,04
OR AL,BL
MOV SEC,AL
MOV AL,[SI+4]
MOV BL,[SI+3]
ROR BL,04
OR AL,BL
MOV MIN,AL
MOV AL,[SI+2]
MOV BL,[SI+1]
ROR BL,04
OR AL,BL
MOV HOUR,AL
MOV DX,MY8255_C
Z_PAU: RET
PAUSE ENDP
4.3.7初始化时间
原理和初始化时间相同,知识扫描到这一按键被按下时将TIMER中的时间清零重新计时
程序注释和代码如下:
QL PROC
CCSCAN4: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK6
JMP Z2
INK6: MOV CH,0F7H
MOV CL,00H
COLUM4: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,04H ;is L2?
JNZ Z2
MOV AL,08H ;L2
MOV CL,0
KCODE3:ADD AL,CL
CLI
CALL DALLY_ANJIAN
MOV DX,MY8255_A
OUT DX,AL
MOV AX,SEG TIMER ;取TIMER的段地址
MOV DS,AX
MOV SI,OFFSET TIMER ;取TIMER的地址偏移量
MOV AL,00H
MOV [SI+6],AL
MOV [SI+5],AL
MOV [SI+4],AL
MOV [SI+3],AL
MOV [SI+2],AL
MOV [SI+1],AL
MOV AL,[SI+6]
MOV BL,[SI+5]
ROR BL,04
OR AL,BL
MOV SEC,AL
MOV AL,[SI+4]
MOV BL,[SI+3]
ROR BL,04
OR AL,BL
MOV MIN,AL
MOV AL,[SI+2]
MOV BL,[SI+1]
ROR BL,04
OR AL,BL
MOV HOUR,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
STI
Z2: RET
QL ENDP
4.3.8播放音乐
原理原理和初始化时间相同,知识扫描到这一按键被按下时,调用这一按键对应的音乐来响铃。同时,当继续键被按下时,停止播放音乐,继续显示时间。
程序代码及注释如下(我们一共定了两首歌,这里只放一个音乐的代码,原理都相同):
DG1 PROC
CCSCAN11: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK7
JMP Z3
INK7: MOV CH,0FEH
MOV CL,00H
COLUM5: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,08H ;is L2?
JNZ Z3
MOV AL,0CH ;L2
MOV CL,3
KCODE4:ADD AL,CL
MOV DX,MY8255_A
OUT DX,AL
BEGIN_B: MOV BX,OFFSET ST
MOV DI,OFFSET SL ;装入时间表起始地址
PLAY1:
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ Z3
MOV DX,0FH ;输入时钟为1MHz,1M = 0F4240H
MOV AX,4240H
DIV WORD PTR [BX] ;取出频率值计算计数初值,0F4240H / 输出频率
MOV DX,B8254
OUT DX,AL ;装入计数初值
MOV AL,AH
OUT DX,AL
MOV DL,[DI] ;取出演奏相对时间,调用延时子程序
CALL DALLY2
ADD BX,2
INC DI
CMP WORD PTR [BX],0 ;判断是否到曲末?
JE Z3
CALL DISP
JMP PLAY1
Z3: RET
DG1 ENDP
4.3.9清空闹钟
原理原理和初始化时间相同,知识扫描到这一按键被按下时,清空N_TIME变量中的时间,使得闹钟被清空。
注释及代码如下:
CLCLOCK PROC
CCSCAN_CLCLOCK: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK_CLCLOCK
JMP Zz
INK_CLCLOCK:
MOV CH,0F7H
MOV CL,00H
COLUM_CLCLOCK:
MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,08H ;is L1?
JNZ Zz
MOV AL,0CH ;L3
MOV CL,2
KCODE_CLCLOCK: ADD AL,CL
CALL DALLY_ANJIAN
CLI
MOV AX,SEG N_TIME ;取TIMER的段地址
MOV DS,AX
MOV SI,OFFSET N_TIME ;取TIMER的地址偏移量
MOV AL,00H
MOV [SI+6],AL
MOV [SI+5],AL
MOV [SI+4],AL
MOV [SI+3],AL
MOV [SI+2],AL
MOV [SI+1],AL
STI
Zz: RET
CLCLOCK ENDP
最后粘一下最终的代码吧,在基础代码的基础上做了很多的修改,这里感谢阿硕带飞!!!以及小伙伴们共同合作!!!汇编课设真的是自闭,期末了还在自闭…但收获也很多!!刚好课设验收前一天平安夜是女朋友生日,把电子闹钟定在了12:24响铃,铃声是生日快乐歌~(唔…单身狗阿硕全程见证)
A8254 EQU 06C0H ;宏定义
B8254 EQU 06C2H
C8254 EQU 06C4H
CON8254 EQU 06C6H
MY8255_A EQU 0600H
MY8255_B EQU 0602H
MY8255_C EQU 0604H
MY8255_CON EQU 0606H
PUBLIC SEC,MIN,HOUR
DATA SEGMENT ;定义数据段
TAB DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H ;数码表
DB 7FH,6FH,77H,7CH,31H,5EH,79H,71H
FREQ_LIST DW 882,330,330,294,262,990,262,882,882
DW 990,262,294,262,294,262,330,882,441
DW 441,393,350,330,393,262,882,990,262,330
DW 294,262,990,262,882,330,330,294,262,990
DW 262,882,882,990,262,294,294,262,294,262
DW 330,330,882,441,441,393,350,330,393,262
DW 882,262,330,294,294,262,990,262,0
TIME_LIST DB 4,12,4,4,4,8,4,12,4 ;时间表
DB 4,4,8,4,8,4,8,4,12
DB 4,4,4,8,4,12,4,4,4,4
DB 4,4,8,4,12,12,4,4,4,8
DB 4,12,4,4,4,4,4,4,4,4
DB 4,8,4,12,4,4,4,8,4,8
DB 4,4,4,4,4,8,8,4,12
SONG_TONE DW 212,212,190,212,159,169,212,212,190,212,142,159,212,212,106,126,159,169,190,119,119,126,159,142,159,0
SONG_LONG DB 9,3,12,12,12,24,9,3,12,12,12,24,9,3,12,12,12,12,12,9,3,12,12,12,24,0
ST DW 392,392,440,392,523,494
DW 392,392,440,392,587,523
DW 392,392,784,659,523,494,440
DW 698,698,659,523,587,523,0
SL DB 6,3,6,6,4,5
DB 6,3,6,6,4,5
DB 6,3,6,6,4,5
DB 6,3,6,6,4,5
SEC DB 0 ;初始化
HOUR DB 0
MIN DB 0
N_TIME DB 20 DUP(0)
Z_TIME DB 20 DUP(0)
N_S DB 30
N_M DB 0
N_H DB 0
TIMER DB 10 DUP(0)
DUAN DB 0
BUF DB 3 DUP(0)
DATA ENDS
SSTACK SEGMENT STACK ;堆栈段
DW 256 DUP(?)
SSTACK ENDS
CODE SEGMENT ;代码段
ASSUME CS:CODE, SS:SSTACK,DS:DATA
START: ;8254初始化------>设置计数初值为10000
MOV DX, CON8254 ;8254
MOV AL, 36H ;计数器0,方式3
OUT DX, AL
;分频
MOV DX, A8254
MOV AX,10000
OUT DX, AL
MOV AL,AH
OUT DX, AL
;8255初始化------------->设置控制字
MOV AL,81H
MOV DX,MY8255_CON
OUT DX,AL
;MIR7中断---------取MIR7的段基址和偏移地址到003CH开始的空间
MOV AX, 0000H
MOV DS, AX
MOV AX, OFFSET MIR7 ;取中断入口地址
MOV SI, 003CH ;中断矢量地址
MOV [SI], AX ;填IRQ7的偏移矢量
MOV AX, SEG MIR7 ;段地址
MOV SI, 003EH
MOV [SI], AX ;填IRQ7的段地址矢量
;MIR6中断---------取MIR6的段基址和偏移地址到0038H开始的空间
MOV AX, OFFSET MIR6 ;取中断入口地址
MOV SI, 0038H ;中断矢量地址
MOV [SI], AX ;填IRQ6的偏移矢量
MOV AX, SEG MIR6 ;段地址
MOV SI, 003AH
MOV [SI], AX ;填IRQ6的段地址矢量
;SIR1中断---------取SIR1的段基址和偏移地址到0038H开始的空间
MOV AX, OFFSET SIR1 ;取中断入口地址
MOV SI, 00C4H ;中断矢量地址
MOV [SI], AX ;填SIR1的偏移矢量
MOV AX, SEG SIR1 ;段地址
MOV SI, 00C6H
MOV [SI], AX ;填SIR1的段地址矢量
;8259初始化
MOV AL, 11H
OUT 20H, AL ;ICW1
MOV AL, 08H
OUT 21H, AL ;ICW3
MOV AL,04H
OUT 21H,AL ;ICW2
MOV AL, 03H
OUT 21H, AL ;ICW4
;初始化从片8259
MOV AL, 11H
OUT 0A0H, AL ;ICW1
MOV AL, 30H
OUT 0A1H, AL ;ICW2
MOV AL, 02H
OUT 0A1H, AL ;ICW3
MOV AL, 01H
OUT 0A1H, AL ;ICW4
MOV AL, 0FDH
OUT 0A1H,AL ;OCW1 = 1111 1101
;??????????????
MOV AX,SEG N_TIME ;取N_TIME的段地址
MOV DS,AX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV [SI+1],1
STI ;可以响应可屏蔽中断请求
AA1:
CALL DISP ;调用显示子程序(disp)
CALL BJ ;调用闹钟(bj)
CALL ZDBS ;调用整点报时(ZDBS)
CALL CLP ;暂停和继续
CALL QL ;时间初始化(秒表)
CALL DG1 ;播放音乐1
CALL DG2
CALL DG3
CALL CLCLOCK ;清空闹钟
JMP AA1
MIR6 PROC
CLI
PUSH AX
PUSH SI
MOV AX,DATA
MOV DS,AX
MOV SI,3000H
MOV AL,00H
MOV [SI],AL ;清显示缓冲
MOV [SI+1],AL
MOV [SI+2],AL
MOV [SI+3],AL
MOV [SI+4],AL
MOV [SI+5],AL
MOV DI,3005H
MOV DX,MY8255_CON ;写8255控制字
MOV AL,81H
OUT DX,AL
BEGIN: CALL DIS ;调用显示子程序
CALL CLEAR ;清屏
CALL CCSCAN ;扫描
JNZ INK1
JMP BEGIN
INK1: CALL DIS
CALL KEYDALLY
CALL KEYDALLY
CALL CLEAR
CALL CCSCAN
MOV AX,SEG DUAN ;取DUAN的段地址
MOV DS,AX
MOV SI,OFFSET DUAN ;取DUAN的地址偏移量,用于技计数
MOV AL,[SI]
INC AL
MOV [SI],AL
CMP AL,7 ;AL与7相比较
JE B2
JNZ INK2 ;有键按下,转到INK2
JMP BEGIN
;========================================
;确定按下键的位置
;========================================
B2: MOV AL,0
MOV [SI],AL
POP AX
POP SI
IRET
INK2: MOV CH,0FEH
MOV CL,00H
COLUM: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
L1: TEST AL,01H ;is L1?
JNZ L2
MOV AL,00H ;L1
JMP KCODE
L2: TEST AL,02H ;is L2?
JNZ L3
MOV AL,04H ;L2
JMP KCODE
L3: TEST AL,04H ;is L3?
JNZ L4
MOV AL,08H ;L3
JMP KCODE
L4: TEST AL,08H ;is L4?
JNZ NEXT
MOV AL,0CH ;L4
KCODE: ADD AL,CL
CALL PUTBUF
PUSH AX
KON: CALL DIS
CALL CLEAR
CALL CCSCAN
JNZ KON
POP AX
NEXT: INC CL
MOV AL,CH
TEST AL,08H
JZ KERR
ROL AL,1
MOV CH,AL
JMP COLUM
KERR: JMP BEGIN
;========================================
;键盘扫描子程序
;========================================
CCSCAN: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
RET
;========================================
;清屏子程序
;========================================
CLEAR: MOV DX,MY8255_B
MOV AL,00H
OUT DX,AL
RET
;========================================
;显示子程序
;========================================
DIS: PUSH AX
MOV SI,3000H
MOV DL,0DFH
MOV AL,DL
AGAIN: PUSH DX
MOV DX,MY8255_A
OUT DX,AL
MOV AL,[SI]
MOV BX,OFFSET TAB
AND AX,00FFH
ADD BX,AX
MOV AL,[BX]
MOV DX,MY8255_B
OUT DX,AL
CALL KEYDALLY
INC SI
POP DX
MOV AL,DL
TEST AL,01H
JZ OUT1
ROR AL,1
MOV DL,AL
JMP AGAIN
OUT1: POP AX
RET
;====== 延时子程序 ======
KEYDALLY: PUSH CX
MOV CX,0006H
D1: MOV AX,009FH
D2: DEC AX
JNZ D2
LOOP D1
POP CX
RET
;========================================
;存键盘值到相应位的缓冲中
;========================================
PUTBUF: MOV SI,DI
MOV [SI],AL
MOV CX,SEG DUAN ;取DUAN的段地址
MOV DS,CX
MOV SI,OFFSET DUAN ;取DUAN的地址偏移量
MOV BX,[SI]
MOV CX,SEG N_TIME ;取N_TIME的段地址
MOV DS,CX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV [SI+BX],AL
MOV DX,[SI+BX]
DEC DI
CMP DI,2FFFH
JNZ GOBACK
MOV DI,3005H
GOBACK: RET
MIR6 ENDP
SIR1 PROC
CLI
PUSH AX
PUSH SI
MOV AX,DATA
MOV DS,AX
MOV SI,3000H
MOV AL,00H
MOV [SI],AL ;清显示缓冲
MOV [SI+1],AL
MOV [SI+2],AL
MOV [SI+3],AL
MOV [SI+4],AL
MOV [SI+5],AL
MOV DI,3005H
MOV DX,MY8255_CON ;写8255控制字
MOV AL,81H
OUT DX,AL
BEGIN_U:CALL DIS1 ;调用显示子程序
CALL CLEAR1 ;清屏
CALL CCSCAN1 ;扫描
JNZ INK3
JMP BEGIN_U
INK3: CALL DIS1
CALL U_DALLY
CALL U_DALLY
CALL CLEAR1
CALL CCSCAN1
MOV AX,SEG DUAN ;取DUAN的段地址
MOV DS,AX
MOV SI,OFFSET DUAN ;取DUAN的地址偏移量
MOV AL,[SI]
INC AL
MOV [SI],AL
CMP AL,7 ;AL与7相比较
JE B3
JNZ INK4 ;有键按下,转到INK4
JMP BEGIN_U
;========================================
;确定按下键的位置
;========================================
B3: MOV AL,0
MOV [SI],AL
POP AX
POP SI
IRET
INK4: MOV CH,0FEH
MOV CL,00H
COLUM2: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
U1: TEST AL,01H ;is L1?
JNZ U2
MOV AL,00H ;L1
JMP KCODE1
U2: TEST AL,02H ;is L2?
JNZ U3
MOV AL,04H ;L2
JMP KCODE1
U3: TEST AL,04H ;is L3?
JNZ U4
MOV AL,08H ;L3
JMP KCODE1
U4: TEST AL,08H ;is L4?
JNZ NEXT1
MOV AL,0CH ;L4
KCODE1: ADD AL,CL
CALL PUTBUF1
PUSH AX
KON1: CALL DIS1
CALL CLEAR1
CALL CCSCAN1
JNZ KON1
POP AX
NEXT1: INC CL
MOV AL,CH
TEST AL,08H
JZ KERR1
ROL AL,1
MOV CH,AL
JMP COLUM2
KERR1: JMP BEGIN_U
;========================================
;键盘扫描子程序
;========================================
CCSCAN1:MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
RET
;========================================
;清屏子程序
;========================================
CLEAR1: MOV DX,MY8255_B
MOV AL,00H
OUT DX,AL
RET
;========================================
;显示子程序
;========================================
DIS1: PUSH AX
MOV SI,3000H
MOV DL,0DFH
MOV AL,DL
AGAIN1: PUSH DX
MOV DX,MY8255_A
OUT DX,AL
MOV AL,[SI]
MOV BX,OFFSET TAB
AND AX,00FFH
ADD BX,AX
MOV AL,[BX]
MOV DX,MY8255_B
OUT DX,AL
CALL U_DALLY
INC SI
POP DX
MOV AL,DL
TEST AL,01H
JZ OUT2
ROR AL,1
MOV DL,AL
JMP AGAIN1
OUT2: POP AX
RET
;====== 延时子程序 ======
U_DALLY: PUSH CX
MOV CX,0006H
W1: MOV AX,009FH
W2: DEC AX
JNZ W2
LOOP W1
POP CX
RET
;========================================
;存键盘值到相应位的缓冲中
;========================================
PUTBUF1:MOV SI,DI
MOV [SI],AL
MOV CX,SEG DUAN ;取DUAN的段地址
MOV DS,CX
MOV SI,OFFSET DUAN ;取DUAN的地址偏移量
MOV BX,[SI]
MOV CX,SEG TIMER ;取TIMER的段地址
MOV DS,CX
MOV SI,OFFSET TIMER ;取TIMER的地址偏移量
MOV [SI+BX],AL
MOV DX,[SI+BX]
DEC DI
CMP DI,2FFFH
JNZ GOBACK1
MOV DI,3005H
GOBACK1:RET
SIR1 ENDP
MIR7 PROC
STI ;置中断标志位IF
PUSH AX ;压栈
PUSH SI
PUSH BX
MOV AX,SEG TIMER ;取TIMER的段地址
MOV DS,AX
MOV SI,OFFSET TIMER ;取TIMER的地址偏移量
MOV AL,[SI]
INC AL
MOV [SI],AL
CMP AL,100 ;AL与100相比较
JNE MID ;若不相等,则跳转
MOV AL,0 ;相等则向下执行
MOV [SI],AL
MOV AL,[SI+6]
ADD AL,1
DAA ;十进制调整,用于加法
MOV [SI+6],AL
CMP AL,10H
JNE TRNED
MOV AL,0
MOV [SI+6],AL
MOV AL,[SI+5]
ADD AL,1
DAA
MOV [SI+5],AL
CMP AL,6H
JNE TRNED
MOV AL,0
MOV [SI+5],AL
MOV AL,[SI+4]
ADD AL,1
DAA
MOV [SI+4],AL
CMP AL,10H
MID: JNE TRNED
MOV AL,0
MOV [SI+4],AL
MOV AL,[SI+3]
ADD AL,1
DAA
MOV [SI+3],AL
CMP AL,6H
JNE TRNED
MOV AL,0
MOV [SI+3],AL
MOV AL,[SI+2]
ADD AL,1
DAA
MOV [SI+2],AL
MOV AL,[SI+1]
CMP AL,2H
JNZ HOUR1
MOV AL,[SI+2]
CMP AL,4H
JNZ TRNED
MOV AL,0
MOV [SI+2],AL
MOV [SI+1],AL
JMP TRNED
HOUR1:
MOV AL,[SI+2]
CMP AL,10H
JNZ TRNED
MOV AL,0
MOV [SI+2],AL
MOV AL,[SI+1]
ADD AL,1
DAA
MOV [SI+1],AL
TRNED:
MOV AL,[SI+6]
MOV BL,[SI+5]
ROR BL,04
OR AL,BL
MOV SEC,AL
MOV AL,[SI+4]
MOV BL,[SI+3]
ROR BL,04
OR AL,BL
MOV MIN,AL
MOV AL,[SI+2]
MOV BL,[SI+1]
ROR BL,04
OR AL,BL
MOV HOUR,AL
POP BX
POP SI ;出栈
POP AX
STI ;置中断标志位IF
IRET ;中断返回
ENDP
DISP:
PUSH BX
PUSH DI
PUSH AX
PUSH SI
MOV DX,MY8255_B
MOV AX,SEG TAB
MOV DS,AX
MOV BX,OFFSET TAB
MOV AL,SEC
AND AL,0FH ;与低四位相与
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0DFH
OUT DX,AL
CALL DALLY
MOV AL,SEC
AND AL,0F0H
ror al,04
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0EFH
OUT DX,AL
CALL DALLY
MOV AL,MIN
AND AL,0FH
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0F7H
OUT DX,AL
CALL DALLY
MOV AL,MIN
AND AL,0F0H
ror al,04
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0FBH
OUT DX,AL
CALL DALLY
MOV AL,HOUR
AND AL,0FH
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0FDH
OUT DX,AL
CALL DALLY
MOV AL,HOUR
AND AL,0F0H
ror al,04
MOV AH,00H
MOV SI,AX
MOV AL,[BX+SI]
MOV DX,MY8255_B
OUT DX,AL
MOV DX,MY8255_A
MOV AL,0FEH
OUT DX,AL
CALL DALLY
POP SI
POP AX
POP DI
POP BX
RET
ZDBS PROC ;整点报时
MOV AL,MIN
CMP AL,00H
JNZ LP2
MOV AL,SEC
CMP AL,00H
JNZ LP2
MOV DX, CON8254 ;8254
MOV AL, 76H ;计数器1,方式3
OUT DX, AL
ZD1:
MOV DX, B8254
MOV AL, 00H
OUT DX, AL
MOV AL, 09H
OUT DX, AL
MOV AL,SEC
CMP AL,05H
JE OUTZD
CALL DISP
JMP ZD1
OUTZD:
MOV AX,00H
OUT DX,AL
MOV AL,AH
OUT DX,AL
RET
LP2: RET
ZDBS ENDP
BJ PROC ;闹铃程序
MOV AL,HOUR
MOV CX,SEG N_TIME ;取N_TIME的段地址
MOV DS,CX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV BL,[SI+1]
ROL BL,04
MOV AL,0
MOV AL,[SI+2]
OR BL,AL
CMP AL,BL
JNZ LP
MOV CX,SEG N_TIME ;取N_TIME的段地址
MOV DS,CX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV BL,[SI+3]
ROL BL,04
MOV AL,0
MOV AL,[SI+4]
OR BL,AL
MOV AL,MIN
CMP AL,BL
JNZ LP
MOV CX,SEG N_TIME ;取N_TIME的段地址
MOV DS,CX
MOV SI,OFFSET N_TIME ;取N_TIME的地址偏移量
MOV BL,[SI+5]
ROL BL,04
MOV AL,0
MOV AL,[SI+6]
OR BL,AL
MOV AL,SEC
CMP AL,BL
JNZ LP
MOV DX, CON8254 ;8254
MOV AL, 76H ;计数器1,方式3
OUT DX, AL
BEGIN_M: MOV BX,OFFSET ST
MOV DI,OFFSET SL ;装入时间表起始地址
PLAY: MOV DX,0FH ;输入时钟为1MHz,1M = 0F4240H
MOV AX,4240H
DIV WORD PTR [BX] ;取出频率值计算计数初值,0F4240H / 输出频率
MOV DX,B8254
OUT DX,AL ;装入计数初值
MOV AL,AH
OUT DX,AL
MOV DL,[DI] ;取出演奏相对时间,调用延时子程序
CALL DALLY2
ADD BX,2
INC DI
CMP WORD PTR [BX],0 ;判断是否到曲末?
JE OUTPLAY
CALL DISP
JMP PLAY
OUTPLAY:MOV DX,B8254
MOV AX,00H
OUT DX,AL
MOV AL,AH
OUT DX,AL
RET
LP: RET
DALLY2 PROC ;延时子程序
H0: MOV CX,0010H
H1: MOV AX,0FF0H
H2: DEC AX
JNZ H2
LOOP H1
DEC DL
JNZ H0
RET
DALLY2 ENDP
BJ ENDP
CLP PROC
CCSCAN2: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK5
JMP Z1
INK5: MOV CH,0FBH
MOV CL,00H
COLUM3: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,04H ;is L1?
JNZ Z1
MOV AL,08H ;L3
MOV CL,0
KCODE2: ADD AL,CL
CLI
CALL DALLY_ANJIAN
CCSCAN3:
MOV DX,MY8255_A
OUT DX,AL
MOV AX,SEG TIMER ;取TIMER的段地址
MOV DS,AX
MOV SI,OFFSET TIMER ;取TIMER的地址偏移量
MOV AL,[SI+6]
MOV BL,[SI+5]
ROR BL,04
OR AL,BL
MOV SEC,AL
MOV AL,[SI+4]
MOV BL,[SI+3]
ROR BL,04
OR AL,BL
MOV MIN,AL
MOV AL,[SI+2]
MOV BL,[SI+1]
ROR BL,04
OR AL,BL
MOV HOUR,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ Z0
JZ CCSCAN3
Z0: STI
Z1: RET
CLP ENDP
QL PROC
CCSCAN4: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK6
JMP Z2
INK6: MOV CH,0F7H
MOV CL,00H
COLUM4: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,04H ;is L2?
JNZ Z2
MOV AL,08H ;L2
MOV CL,0
KCODE3:ADD AL,CL
CLI
CALL DALLY_ANJIAN
MOV DX,MY8255_A
OUT DX,AL
MOV AX,SEG TIMER ;取TIMER的段地址
MOV DS,AX
MOV SI,OFFSET TIMER ;取TIMER的地址偏移量
MOV AL,00H
MOV [SI+6],AL
MOV [SI+5],AL
MOV [SI+4],AL
MOV [SI+3],AL
MOV [SI+2],AL
MOV [SI+1],AL
MOV AL,[SI+6]
MOV BL,[SI+5]
ROR BL,04
OR AL,BL
MOV SEC,AL
MOV AL,[SI+4]
MOV BL,[SI+3]
ROR BL,04
OR AL,BL
MOV MIN,AL
MOV AL,[SI+2]
MOV BL,[SI+1]
ROR BL,04
OR AL,BL
MOV HOUR,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
STI
Z2: RET
QL ENDP
DG1 PROC
CCSCAN11: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK7
JMP Z3
INK7: MOV CH,0FEH
MOV CL,00H
COLUM5: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,08H ;is L2?
JNZ Z3
MOV AL,0CH ;L2
MOV CL,3
KCODE4:ADD AL,CL
MOV DX,MY8255_A
OUT DX,AL
BEGIN_B: MOV BX,OFFSET ST
MOV DI,OFFSET SL ;装入时间表起始地址
PLAY1:
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ Z3
MOV DX,0FH ;输入时钟为1MHz,1M = 0F4240H
MOV AX,4240H
DIV WORD PTR [BX] ;取出频率值计算计数初值,0F4240H / 输出频率
MOV DX,B8254
OUT DX,AL ;装入计数初值
MOV AL,AH
OUT DX,AL
MOV DL,[DI] ;取出演奏相对时间,调用延时子程序
CALL DALLY2
ADD BX,2
INC DI
CMP WORD PTR [BX],0 ;判断是否到曲末?
JE Z3
CALL DISP
JMP PLAY1
Z3: RET
DG1 ENDP
CLCLOCK PROC
CCSCAN_CLCLOCK: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK_CLCLOCK
JMP Zz
INK_CLCLOCK: MOV CH,0F7H
MOV CL,00H
COLUM_CLCLOCK: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,08H ;is L1?
JNZ Zz
MOV AL,0CH ;L3
MOV CL,2
KCODE_CLCLOCK: ADD AL,CL
CALL DALLY_ANJIAN
CLI
MOV AX,SEG N_TIME ;取TIMER的段地址
MOV DS,AX
MOV SI,OFFSET N_TIME ;取TIMER的地址偏移量
MOV AL,00H
MOV [SI+6],AL
MOV [SI+5],AL
MOV [SI+4],AL
MOV [SI+3],AL
MOV [SI+2],AL
MOV [SI+1],AL
STI
Zz: RET
CLCLOCK ENDP
DG2 PROC
CCSCAN12: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK_DG
JMP Z_DG
INK_DG: MOV CH,0FDH
MOV CL,00H
COLUM_DG: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,08H ;is L2?
JNZ Z_DG
MOV AL,0CH ;L2
MOV CL,2
KCODE_DG:ADD AL,CL
MOV DX,MY8255_A
OUT DX,AL
BEGIN_C: MOV BX,OFFSET FREQ_LIST
MOV DI,OFFSET TIME_LIST ;装入时间表起始地址
PLAY2:
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ Z_DG
MOV DX,0FH ;输入时钟为1MHz,1M = 0F4240H
MOV AX,4240H
DIV WORD PTR [BX] ;取出频率值计算计数初值,0F4240H / 输出频率
MOV DX,B8254
OUT DX,AL ;装入计数初值
MOV AL,AH
OUT DX,AL
MOV DL,[DI] ;取出演奏相对时间,调用延时子程序
CALL DALLY2
ADD BX,2
INC DI
CMP WORD PTR [BX],0 ;判断是否到曲末?
JE Z_DG
CALL DISP
JMP PLAY2
Z_DG: RET
DG2 ENDP
DG3 PROC
CCSCAN13: MOV AL,00H
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ INK_DG3
JMP Z_DG3
INK_DG3: MOV CH,0FBH
MOV CL,00H
COLUM_DG3: MOV AL,CH
MOV DX,MY8255_A
OUT DX,AL
MOV DX,MY8255_C
IN AL,DX
TEST AL,08H ;is L2?
JNZ Z_DG3
MOV AL,0CH ;L2
MOV CL,1
KCODE_DG3:ADD AL,CL
MOV DX,MY8255_A
OUT DX,AL
BEGIN_D: MOV BX,OFFSET SONG_TONE
MOV DI,OFFSET SONG_LONG ;装入时间表起始地址
PLAY3:
MOV DX,MY8255_C
IN AL,DX
NOT AL
AND AL,0FH
JNZ Z_DG
MOV DX,0FH ;输入时钟为1MHz,1M = 0F4240H
MOV AX,4240H
DIV WORD PTR [BX] ;取出频率值计算计数初值,0F4240H / 输出频率
MOV DX,B8254
OUT DX,AL ;装入计数初值
MOV AL,AH
OUT DX,AL
MOV DL,[DI] ;取出演奏相对时间,调用延时子程序
CALL DALLY2
ADD BX,2
INC DI
CMP WORD PTR [BX],0 ;判断是否到曲末?
JE Z_DG3
CALL DISP
JMP PLAY3
Z_DG3: RET
DG3 ENDP
DALLY_ANJIAN: PUSH CX
MOV CX,00F6H
TTTT1: MOV AX,009FH
TTTT2: DEC AX
JNZ TTTT2
LOOP TTTT1
POP CX
RET
DALLY: PUSH CX
MOV CX,0006H
T1: MOV AX,009FH
T2: DEC AX
JNZ T2
LOOP T1
POP CX
RET
CODE ENDS
END START