⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jjztl.asm

📁 IO程序 - 交通灯演示程序,采用中断驱动模式。① 南北路口的绿灯
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;**********************************************************
;* 文 件 名: JJZTL.asm                                    *
;* 说    明: IO程序 - 交通灯演示程序                      *
;* 作    者: 蒋露 计超 张业                               *
;* 创建日期: 2006.4.11                                    *
;* 编译工具: MASM 5.0/6.0                                 *
;* 备    注:                                              *
;*                                                        *
;* 0. 主程序结构: 本程序由主循环和定时器中断处理函数组成, *
;*    程序首先初始化IRQ7号中断的处理函数为NewIRQ7,再初始  *
;*    化8255的PA,PC口为方式0输出,再初始化8253为IRQ7中断源 *
;*    ,中断频率为10次/秒,然后进入主循环.主循环负责显示由  *
;*    全局变量CurTime保存的十位和个位当前倒计时数还有由全 *
;*    局变量CurMode保存的当前LED灯显示状态(还包括S1和S0). *
;*    当定时器中断发生时会调用NewIRQ7中断处理函数,该函数  *
;*    进行计秒处理(由SecTick记录),当到达一秒时调用DecTime *
;*    函数进行对CurTime的递减操作.NewIRQ7还进行显示模式的 *
;*    判断,ModeInt记录了14个模式各自要经过中断的次数(模式 *
;*    0的数据为300就是说明模式0要经过300个中断即30秒才跳  *
;*    转到下一个模式).TimeInc记录了模式转换时在CurTime上  *
;*    的增量.这是一个小小的技巧,用来避免大量的跳转指令,但 *
;*    愿这不会使我的代码看起来更加困难. ^_^.              *
;*                                                        *
;*                                                        *
;* 1. 退出按键检测问题: 这大概是本程序中最令人困扰的了,有 *
;*    一个小函数KeyTest用来测试是否该退出,当它用AL返回1时 *
;*    代表可以退出.但关键是这个代码怎么写.KeyTest必须是无 *
;*    等待的,它不可以打断主显示循环的不断执行.DOS中断06H  *
;*    和BIOS的16号中断都可以不暂停的执行按键检测任务.但是 *
;*    测试结果是他们总会造成莫名其妙的程序异常.问题肯定出 *
;*    在中断嵌套上,他们内部肯定会使用STI指令打开中断的,这 *
;*    时如果IRQ7中断到来,就会有问题.而且为了定时器的准确  *
;*    最好不要随便屏蔽IRQ7.暂时的解决方案是使用外部开关K0 *
;*    连线方法详见实验报告的实验一图2(74LS244).           *
;*                                                        *
;* 2. 优化和改进: 多个计数变量的合并,代码设计时很随意,没  *
;*    有仔细考虑变量的共同点,比如CurTime和ModeTick就可以  *
;*    合并.中断粒度的减小,当前中断间隔为0.1秒,其实由于模  *
;*    间的最小间隔是0.5秒,所以可以将中断间隔延长到0.5秒.  *
;*    退出机制的改进,当前采用了利用74LS244的K0开关控制程  *
;*    序,应该还可以直接读键盘缓冲的方式判断按键.(已改)    *
;*                                                        *
;* 七段数码管连线示意图:                                  *
;*  a - PA0      S0 - PC0                                 *
;*  b - PA1      S1 - PC1                   a             *
;*  c - PA2                                 ━            *
;*  d - PA3      dp - 地                 f┃g ┃b         *
;*  e - PA4                                 ━            *
;*  f - PA5                              e┃  ┃c         *
;*  g - PA6                                 ━            *
;*                                          d             *
;*                                                        *
;*                                                        *
;* LED灯连线示意图:      ○  ○  ○  ○  ○  ○  ○  ○   *
;*                      1红 1黄 1绿  无  无 2红 2黄 2绿   *
;*                      PC7 PC6 PC5  地  地 PC4 PC3 PC2   *
;*                                                        *
;* 8255端口A设置:       PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0   *
;*                      空   g   f   e   d   c   b   a    *
;*                                                        *
;* 8255端口C设置:       PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0   *
;*                      1红 1黄 1绿 2红 2黄 2绿 S1  S0    *
;*                      1 - 南北方向                      *
;*                      2 - 东西方向                      *
;*                                                        *
;* 中断部分连线参考实验报告实验2                          *
;**********************************************************

; 需要使用到286指令 PUSHA/POPA,可以用多个PUSH/POP替换
.286
;----------------------------------------------------------
; 常量定义
E8255_PA        EQU 288H
E8255_PC        EQU 28AH
E8255_CTL       EQU 28BH

E8253_CLK0      EQU 280H
E8253_CLK1      EQU 281H
E8253_CTL       EQU 283H

E8259_CTL0      EQU 20H
E8259_CTL1      EQU 21H

; 键盘端口
KEYBOARD_PORT   EQU 60H

; IRQ7的中断号
IRQ7_NR         EQU 0FH
IRQ7_OPEN_MASK  EQU 7FH
IRQ7_CLOSE_MASK EQU 80H    

; 一秒中断数
SEC_SETUP       EQU 10  
;----------------------------------------------------------
; 数据段
DATA_SEG SEGMENT
  ; LED灯的显示模式,PC口输出
  LedMode   DB 00110000B   ; 南北绿灯亮,东西红灯亮 0
            DB 01010000B   ; 南北黄灯亮,东西红灯亮 1
            DB 00010000B   ;            东西红灯亮 2
            DB 01010000B   ; 南北黄灯亮,东西红灯亮 3
            DB 00010000B   ;            东西红灯亮 4
            DB 01010000B   ; 南北黄灯亮,东西红灯亮 5
            DB 00010000B   ;            东西红灯亮 6 
            DB 10000100B   ; 南北红灯亮,东西绿灯亮 7
            DB 10001000B   ; 南北红灯亮,东西黄灯亮 8
            DB 10000000B   ; 南北红灯亮            9
            DB 10001000B   ; 南北红灯亮,东西黄灯亮 10
            DB 10000000B   ; 南北红灯亮            11
            DB 10001000B   ; 南北红灯亮,东西黄灯亮 12
            DB 10000000B   ; 南北红灯亮            13

  ; 七段数码管段码表
  SegTab    DB 00111111B   ; 3fh - 0
            DB 00000110B   ; 6h  - 1
            DB 01011011B   ; 5bh - 2
            DB 01001111B   ; 4fh - 3
            DB 01100110B   ; 66h - 4
            DB 01101101B   ; 6dh - 5
            DB 01111101B   ; 7dh - 6
            DB 00000111B   ; 7h  - 7
            DB 01111111B   ; 7fh - 8
            DB 01101111B   ; 6fh - 9

  ; 当前LED模式
  CurMode   DB 0

  ; 当前倒计数时间(十位和个位分开)
  CurTime   DB 1, 0

  ; 模式的Tick间隔
  ModeInt   DW 100, 5, 5, 5, 5, 5, 5
            DW 100, 5, 5, 5, 5, 5, 5

  ; 模式的时间递增量
  TimeInc   DB 1, 0
            DB 0, 3
            DB 0, 0
            DB 0, 0
            DB 0, 0
            DB 0, 0
            DB 0, 0
            DB 1, 0
            DB 0, 3
            DB 0, 0
            DB 0, 0
            DB 0, 0
            DB 0, 0
            DB 0, 0

  ; 模式计数(倒计数,用来记录当前模式剩余中断次数)
  ModeTick  DW 0

  ; 秒计数(用来计秒数)
  SecTick   DB SEC_SETUP
  
  WelMsg    DB 'Press ESC to quit.', 13, 10, '$'
  
  ; 保存的旧中断向量
  OldIrq    DW ?, ?    

DATA_SEG ENDS
;----------------------------------------------------------
; 堆栈段
STACK_SEG SEGMENT STACK
             DW 128 DUP(?)
STACK_SEG ENDS
;----------------------------------------------------------
; 代码段
CODE_SEG SEGMENT
            ASSUME DS:DATA_SEG, SS:STACK_SEG, CS:CODE_SEG
;----------------------------------------------------------
; 主程序
;┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
;┃MAIN 主程序                                           ┃
;┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
MAIN PROC FAR
  START:
            MOV     AX, DATA_SEG
            MOV     DS, AX

            MOV     AX, STACK_SEG
            MOV     SS, AX

            ; 显示欢迎字符串
            LEA     DX, WelMsg
            MOV     AH, 9H
            INT     21H

            ; 设置新的中断向量
            CALL    SetIRQ

            ; 初始化8255
            CALL    Init8255

            ; 初始化8253
            CALL    Init8253

            ; 主程序循环
  M_LOOP:
            MOV     BH, [CurTime]
            MOV     BL, [CurTime+1]

            ; 显示十位
            MOV     AH, 2H
            MOV     AL, BH
            CALL    Display
            CALL    Delay

            ; 显示个位
            MOV     AH, 1H
            MOV     AL, BL
            CALL    Display
            CALL    Delay   
               
            ; 判断按键
            CALL    KeyTest
            CMP     AL, 1
            JNE     M_LOOP

            ; 恢复旧中断向量
            CALL    RestoreIRQ
                        
            ; 返回DOS
            MOV     AH, 4CH
            MOV     AL, 0H
            INT     21H
MAIN ENDP
;----------------------------------------------------------
;┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
;┃Init8253 初始化 8253                                  ┃
;┣━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
;┃参    数 : 无                                         ┃
;┃返 回 值 : 无                                         ┃
;┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Init8253 PROC NEAR
            PUSHA

            ;向8253写控制字
            MOV     DX, E8253_CTL
            ;控制字:计数器0,方式3,16位操作,二进制模式
            MOV     AL, 00110110B
            OUT     DX, AL

            ;写入计数器0初值1000
            MOV     AX, 1000
            ;先写入低字节
            MOV     DX, E8253_CLK0
            OUT     DX, AL
            ;后写入高字节
            MOV     AL, AH
            OUT     DX, AL

            ;向8253写控制字
            MOV     DX, E8253_CTL
            ;控制字:计数器1,方式2,16位操作,二进制模式
            MOV     AL, 76H
            OUT     DX, AL

            ;写入计数器1初值100
            MOV     AX, 100
            ;先写低字节
            MOV     DX, E8253_CLK1
            OUT     DX, AL
            ;后写高字节
            MOV     AL, AH
            OUT     DX, AL

            POPA
            RET
Init8253 ENDP
;----------------------------------------------------------
;┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
;┃Init8255 初始化 8255                                  ┃
;┣━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
;┃参    数 : 无                                         ┃
;┃返 回 值 : 无                                         ┃
;┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Init8255 PROC NEAR
            PUSHA

            ;使8255的PA,PC口为方式0输出
            MOV     DX, E8255_CTL
            MOV     AL, 10000000B
            OUT     DX, AL

            POPA
            RET

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -