当前位置: 首页 > news >正文

8088 单板机 汇编 NMI 中断程序示例 (脱离 DOS 环境)

; =================================================================
; nmi_demo.asm - 8088 单板机 NMI 中断演示程序
; 脱离 DOS 环境,直接运行在裸机上
; =================================================================; 硬件配置假设:
; - 8088 CPU @ 4.77MHz
; - 8259 PIC (可编程中断控制器)
; - 8255 PPI (可编程外设接口) 连接 LED
; - 7 段数码管显示
; - NMI 按钮连接到 NMI 引脚PORT_PPI_A     EQU 60h    ; 8255 PPI 端口 A (LED 控制)
PORT_PPI_B     EQU 61h    ; 8255 PPI 端口 B (7 段数码管数据)
PORT_PPI_C     EQU 62h    ; 8255 PPI 端口 C (数码管位选)
PORT_PPI_CTRL  EQU 63h    ; 8255 PPI 控制端口PORT_PIC_CMD   EQU 20h    ; 8259 PIC 命令端口
PORT_PIC_DATA  EQU 21h    ; 8259 PIC 数据端口; 7 段数码管编码 (共阴极)
;       0     1     2     3     4     5     6     7     8     9
SEG7 db 3Fh, 06h, 5Bh, 4Fh, 66h, 6Dh, 7Dh, 07h, 7Fh, 6Fhorg 0FFF0h                ; 8088 复位向量地址
reset:jmp 0F000h:start      ; 跳转到实际起始地址org 0F000h                ; BIOS 区域起始地址 (典型); === 主程序入口 ===
start:; 设置段寄存器cli                   ; 禁用中断mov ax, csmov ds, ax            ; DS = CSmov ss, ax            ; SS = CSmov sp, 0FFFEh        ; 栈指针在 64KB 顶部; 初始化硬件call init_ppi         ; 初始化 8255 PPIcall init_pic         ; 初始化 8259 PICcall init_nmi         ; 初始化 NMI 处理; 显示启动信息call clear_displaymov si, msg_welcomecall display_string; 主循环 - 等待 NMIsti                   ; 启用中断
main_loop:hlt                   ; 暂停 CPU 等待中断jmp main_loop; === 初始化 8255 PPI ===
init_ppi:; 设置 8255 控制字: 端口A输出, 端口B输出, 端口C输出, 模式0mov al, 10000000b     ; 控制字: 1 (I/O模式) 00 (A组模式0) 0 (A输出) 1 (C上输出) 0 (B组模式0) 0 (B输出) 0 (C下输出)out PORT_PPI_CTRL, al; 初始状态: 关闭所有 LED 和数码管xor al, alout PORT_PPI_A, al    ; 关闭 LEDout PORT_PPI_B, al    ; 关闭数码管段out PORT_PPI_C, al    ; 关闭数码管位选ret; === 初始化 8259 PIC ===
init_pic:; ICW1: 边沿触发, 级联, 需要 ICW4mov al, 00010011b     ; ICW1: 1 (需要ICW4) 0 (级联) 0 (边沿触发) 1 (需要ICW4) 1 (主PIC)out PORT_PIC_CMD, al; ICW2: 中断向量基地址mov al, 08h           ; 中断向量号从 08h 开始out PORT_PIC_DATA, al; ICW3: 主片 IR2 连接从片 (本示例不使用从片)mov al, 00000100b     ; IR2 连接从片 (00000100b)out PORT_PIC_DATA, al; ICW4: 8086/88 模式mov al, 00000001b     ; ICW4: 0 (非特殊全嵌套) 0 (非缓冲) 0 (主片) 1 (8086模式)out PORT_PIC_DATA, al; OCW1: 屏蔽所有中断 (NMI 不受影响)mov al, 11111111b     ; 屏蔽所有 IRQout PORT_PIC_DATA, alret; === 初始化 NMI 处理 ===
init_nmi:; 保存原始 NMI 向量xor ax, axmov es, ax            ; ES = 0000h (中断向量表段)mov di, 2*4           ; NMI 向量位置 (中断号 2 * 4 字节)mov ax, [es:di]       ; 获取偏移mov [old_nmi_offset], axmov ax, [es:di+2]     ; 获取段地址mov [old_nmi_segment], ax; 设置新的 NMI 处理程序climov word [es:di], nmi_handler    ; 设置新偏移mov [es:di+2], cs                ; 设置段地址 (当前代码段)sti; 启用 NMI (清除 CMOS 寄存器第7位)in al, 70hand al, 01111111b     ; 清除第7位 (NMI 启用)out 70h, alret; === NMI 中断处理程序 ===
nmi_handler:; 保存寄存器push axpush bxpush cxpush dxpush sipush ds; 设置数据段mov ax, csmov ds, ax; 增加 NMI 计数器inc byte [nmi_count]; 在 LED 上显示 NMI 发生mov al, 0FFh          ; 点亮所有 LEDout PORT_PPI_A, al; 在数码管上显示计数call update_display; 延迟一段时间 (视觉反馈)mov cx, 0FFFFh
delay_loop:noploop delay_loop; 关闭 LEDxor al, alout PORT_PPI_A, al; 发送中断结束信号 (EOI)mov al, 20h           ; 非特定 EOIout PORT_PIC_CMD, al; 恢复寄存器pop dspop sipop dxpop cxpop bxpop axiret                  ; 中断返回; === 更新数码管显示 ===
update_display:; 显示 NMI 计数mov al, [nmi_count]and al, 0Fh           ; 只显示低4位; 获取数码管编码mov bx, SEG7xlat                  ; AL = DS:[BX + AL]; 输出到数码管out PORT_PPI_B, al    ; 段数据; 启用第一个数码管mov al, 00000001b     ; 位选: 启用第一个数码管out PORT_PPI_C, alret; === 清除数码管显示 ===
clear_display:xor al, alout PORT_PPI_B, al    ; 关闭所有段out PORT_PPI_C, al    ; 关闭所有位选ret; === 显示字符串 (SI = 字符串地址) ===
display_string:push axpush bxpush cxpush dxpush simov cx, 0             ; 字符计数器
next_char:lodsb                 ; 加载下一个字符test al, al           ; 检查是否结束jz display_done; 查找字符的7段编码mov bx, SEG7xlat                  ; AL = 7段编码; 输出到数码管out PORT_PPI_B, al    ; 段数据; 设置位选mov al, clinc alout PORT_PPI_C, al    ; 位选; 延迟push cxmov cx, 1000h
delay_char:loop delay_charpop cxinc cx                ; 下一个数码管cmp cx, 4             ; 最多4个数码管jb next_chardisplay_done:pop sipop dxpop cxpop bxpop axret; === 数据区 ===
msg_welcome db 'NMI', 0   ; 欢迎消息 (以0结尾); NMI 计数器
nmi_count db 0; 原始 NMI 向量保存位置
old_nmi_offset  dw 0
old_nmi_segment dw 0; === 填充到 64KB ROM 结束 ===
times 0FFFFh - $ + 1 db 0FFh

相关文章:

  • 爬虫入门:从基础到实战全攻略
  • 深入浅出MQTT协议:从物联网基础到实战应用全解析
  • nt!MiDispatchFault函数里面的nt!IoPageRead函数分析和nt!MiWaitForInPageComplete函数分析
  • ArcPy错误处理与调试技巧(3)
  • SRE 基础知识:在站点可靠性工程中可以期待什么
  • Mac电脑上本地安装 MySQL并配置开启自启完整流程
  • 数字创新智慧园区建设及运维方案
  • go环境配置
  • MATLAB中properties函数用法
  • 【Linux命令】scp远程拷贝
  • 考研系列—操作系统:第五章、输入输出(I/O)管理
  • 【笔记】在 MSYS2(MINGW64)中安装 python-maturin 的记录
  • 【python深度学习】Day 42 Grad-CAM与Hook函数
  • 关于langchain使用API加载model的方式
  • C++基础算法————广度优先搜索(BFS)
  • Spring AI调用Ollama+DeepSeek
  • 微调大模型:什么时候该做,什么时候不该做?
  • NodeJS全栈开发面试题讲解——P2Express / Nest 后端开发
  • 【2025最新】Java图书借阅管理系统:从课程作业到实战应用的完整解决方案
  • java CountDownLatch‌
  • 怎样做网站/深圳网络推广哪家好
  • 重庆网站怎么设置/拼多多代运营收费标准
  • 树莓派做的网站/seo营销推广
  • 网站做的文字乱码/长沙seo
  • 网站建设专员工作职责/seo收费
  • 备案信息 网站名/留手机号广告