带中断计数器的UART接收中断程序 (8259@400H/402H)

1.程序功能

  在中断服务程序中增加了中断计数器,并在主循环中通过串口输出中断次数。

2.验证

2.1手动触发8259的IR1,高电平有效

2.2串口接收

3.测试程序


; You may customize this and other start-up templates; 
; The location of this template is c:\emu8086\inc\0_com_template.txt; =============================================
; PC16550 UART接收中断程序 + LED闪烁 + 中断计数器
; 硬件配置:
;   - UART基地址: 100H
;   - LED端口: 800H
;   - 8259 PIC端口: 400H(命令), 402H(数据)
;   - 中断请求线: IRQ1 (8259 IR1)
;   - 中断向量号: 21H
;   - 时钟频率: 18.432MHz
;   - 波特率: 9600 bps (除数78H)
; =============================================ORG 100H
JMP INITIALIZATION      ; 跳过数据区到初始化代码; 数据段定义
BUFFER_SIZE EQU 256     ; 接收缓冲区大小
recv_buffer DB BUFFER_SIZE DUP(0)  ; 接收缓冲区
buffer_head DW 0        ; 缓冲区头指针
buffer_tail DW 0        ; 缓冲区尾指针
buffer_count DW 0       ; 缓冲区中字符计数; LED控制变量
led_state DB 0FFH       ; LED状态: FFH=亮, 00H=灭
flash_counter DW 0      ; 闪烁计数器
FLASH_INTERVAL EQU 50  ; 闪烁间隔(约0.5秒); 中断计数器
interrupt_counter DW 0  ; 中断次数计数器
last_report DW 0        ; 上次报告时间
REPORT_INTERVAL EQU 1000 ; 报告间隔(主循环次数); 16550寄存器偏移
UART_BASE EQU 100H
RBR_THR EQU UART_BASE + 0  ; 接收缓冲/发送保持寄存器
IER     EQU UART_BASE + 1  ; 中断使能寄存器
IIR_FCR EQU UART_BASE + 2  ; 中断标识/FIFO控制寄存器
LCR     EQU UART_BASE + 3  ; 线路控制寄存器
MCR     EQU UART_BASE + 4  ; 调制解调器控制寄存器
LSR     EQU UART_BASE + 5  ; 线路状态寄存器
DLL     EQU UART_BASE + 0  ; 除数锁存低字节 (DLAB=1)
DLM     EQU UART_BASE + 1  ; 除数锁存高字节 (DLAB=1); 8259 PIC端口 (修改为400H/402H)
PIC_CMD  EQU 400H
PIC_DATA EQU 402H; 中断向量号
UART_IRQ EQU 21H        ; IRQ1对应中断21H; =============================================
; UART初始化子程序
; =============================================
INIT_UART:; 设置波特率除数 (9600 @ 18.432MHz)MOV DX, LCRMOV AL, 80H         ; 设置DLAB=1OUT DX, ALMOV DX, DLL         ; 除数锁存低字节MOV AL, 78H         ; 120 = 78H (18.432MHz / (16 * 9600))OUT DX, ALMOV DX, DLM         ; 除数锁存高字节MOV AL, 00HOUT DX, AL; 设置线路参数: 8位数据, 1停止位, 无校验MOV DX, LCRMOV AL, 03H         ; 8N1, DLAB=0OUT DX, AL; 启用并复位FIFOMOV DX, IIR_FCRMOV AL, 0C7H        ; 启用FIFO, 14字节触发点, 清除接收FIFOOUT DX, AL; 设置调制解调器控制MOV DX, MCRMOV AL, 0BH         ; 启用OUT2(中断使能), RTS和DTROUT DX, AL; 启用接收数据中断MOV DX, IER; MOV AL, 01H         ; 仅启用接收数据中断MOV AL, 00H         ; 仅启用接收数据中断OUT DX, ALRET; =============================================
; 8259 PIC初始化 (适配400H/402H端口)
; =============================================
INIT_PIC:; 保存原始中断屏蔽字MOV DX, PIC_DATAIN AL, DXMOV [original_mask], AL; 初始化8259MOV DX, PIC_CMDMOV AL, 17H         ; ICW1: 边沿触发, 级联, 需要ICW4OUT DX, ALMOV DX, PIC_DATAMOV AL, UART_IRQ-1   ; ICW2: 中断向量基值OUT DX, ALMOV AL, 01H         ; ICW4: 8086模式, 非缓冲, 正常EOIOUT DX, AL; 允许IRQ1中断IN AL, DXAND AL, 0FDH        ; 清除IRQ1屏蔽位(11111101)OUT DX, ALRET; =============================================
; 设置中断向量
; =============================================
SET_INTERRUPT_VECTOR:CLI                 ; 关中断XOR AX, AXMOV ES, AX          ; ES = 0 (中断向量表段地址); 计算中断向量位置 (中断号 * 4)MOV AX, UART_IRQSHL AX, 2           ; 乘以4; 设置中断向量MOV DI, AXMOV AX, OFFSET UART_ISRCLDSTOSW               ; 存储偏移地址MOV AX, CSSTOSW               ; 存储段地址STI                 ; 开中断RET; =============================================
; UART中断服务程序 (IRQ1) - 增加中断计数器
; =============================================
UART_ISR PROC FARPUSH AXPUSH BXPUSH DXPUSH DS; 设置DS为当前数据段MOV AX, CSMOV DS, AX; 增加中断计数器INC [interrupt_counter]ISR_LOOP:; 检查中断源MOV DX, IIR_FCRIN AL, DXTEST AL, 01H        ; 检查是否有待处理中断 (bit0=1表示无中断)JNZ ISR_EXIT        ; 无中断则退出; 检查是否为接收数据中断TEST AL, 04H        ; 检查中断类型位 (bit1-2)JNZ CHECK_OTHER     ; 不是接收中断则检查其他; 处理接收数据中断MOV DX, RBR_THRIN AL, DX           ; 读取接收到的字符; 将字符存入缓冲区CALL BUFFER_STORE; 继续检查其他中断JMP ISR_LOOPCHECK_OTHER:; 处理其他中断类型 (可选); 这里可以添加发送中断或错误中断的处理; ...ISR_EXIT:; 发送EOI到8259 (使用新端口)MOV AL, 20HMOV DX, PIC_CMD     ; PIC_CMD = 400HOUT DX, ALPOP DSPOP DXPOP BXPOP AXIRET
UART_ISR ENDP; =============================================
; 串口发送字符子程序
; 输入: AL = 要发送的字符
; =============================================
SEND_CHAR:PUSH AXPUSH DX; 保存字符MOV AH, ALSEND_WAIT:; 检查发送保持寄存器是否为空MOV DX, LSRIN AL, DXTEST AL, 20H        ; 检查THRE位(bit5)JZ SEND_WAIT        ; 不为空则等待; 发送字符MOV DX, RBR_THRMOV AL, AHOUT DX, ALPOP DXPOP AXRET; =============================================
; LED控制子程序
; =============================================
UPDATE_LED:PUSH AXPUSH DX; 更新闪烁计数器INC [flash_counter]CMP [flash_counter], FLASH_INTERVALJB LED_DONE         ; 未达到间隔; 重置计数器MOV [flash_counter], 0; 切换LED状态XOR [led_state], 0FFH; 输出到LED端口MOV DX, 800HMOV AL, [led_state]OUT DX, ALLED_DONE:POP DXPOP AXRET; =============================================
; 将字符存入缓冲区
; =============================================
BUFFER_STORE:PUSH BX; 检查缓冲区是否已满MOV BX, buffer_countCMP BX, BUFFER_SIZEJAE BUFFER_FULL     ; 缓冲区已满,丢弃字符; 存储字符MOV BX, buffer_tailMOV [recv_buffer + BX], AL; 更新尾指针INC BXCMP BX, BUFFER_SIZEJB NO_WRAP_TAILXOR BX, BX          ; 回绕到缓冲区开头NO_WRAP_TAIL:MOV buffer_tail, BX; 更新字符计数INC buffer_countBUFFER_FULL:POP BXRET; =============================================
; 从缓冲区读取字符
; =============================================
BUFFER_READ:PUSH BX; 检查缓冲区是否为空CMP buffer_count, 0JE BUFFER_EMPTY; 读取字符MOV BX, buffer_headMOV AL, [recv_buffer + BX]; 更新头指针INC BXCMP BX, BUFFER_SIZEJB NO_WRAP_HEADXOR BX, BX          ; 回绕到缓冲区开头NO_WRAP_HEAD:MOV buffer_head, BX; 更新字符计数DEC buffer_count; 设置成功标志STCJMP READ_DONEBUFFER_EMPTY:XOR AL, AL          ; 返回0CLC                 ; 清除进位标志 (失败)READ_DONE:POP BXRET; =============================================
; 串口发送字符串
; 输入: SI = 字符串偏移地址
; =============================================
SEND_STRING:PUSH AXPUSH SISEND_STR_LOOP:LODSB               ; 加载字符到ALOR AL, AL           ; 检查是否结束(0)JZ SEND_STR_DONE    ; 是则结束CALL SEND_CHAR      ; 发送字符JMP SEND_STR_LOOP   ; 继续发送SEND_STR_DONE:POP SIPOP AXRET; =============================================
; 将数字转换为字符串并发送
; 输入: AX = 要发送的数字
; =============================================
SEND_NUMBER:PUSH AXPUSH BXPUSH CXPUSH DXPUSH DI; 准备数字转换MOV CX, 0           ; 数字位数计数器MOV BX, 10          ; 除数; 处理0特殊情况TEST AX, AXJNZ CONVERT_LOOPMOV AL, '0'CALL SEND_CHARJMP SEND_NUM_DONECONVERT_LOOP:XOR DX, DX          ; 清零DXDIV BX              ; AX = AX/10, DX = 余数ADD DL, '0'         ; 转换为ASCIIPUSH DX             ; 保存数字字符INC CX              ; 增加位数计数TEST AX, AX         ; 检查商是否为0JNZ CONVERT_LOOP    ; 不为0则继续SEND_LOOP:POP AX              ; 获取数字字符CALL SEND_CHAR      ; 发送字符LOOP SEND_LOOP      ; 循环发送所有数字SEND_NUM_DONE:POP DIPOP DXPOP CXPOP BXPOP AXRET; =============================================
; 报告中断计数器状态
; =============================================
REPORT_COUNTER:PUSH AXPUSH SI; 发送前缀消息MOV SI, OFFSET counter_msgCALL SEND_STRING; 发送中断计数MOV AX, [interrupt_counter]CALL SEND_NUMBER; 发送后缀消息MOV SI, OFFSET counter_endCALL SEND_STRINGPOP SIPOP AXRET; =============================================
; 初始化系统
; =============================================
INIT_SYSTEM:; 初始化缓冲区MOV buffer_head, 0MOV buffer_tail, 0MOV buffer_count, 0; 初始化LED状态MOV [led_state], 0FFH  ; 初始状态: 亮MOV [flash_counter], 0; 初始化LED端口MOV DX, 800HMOV AL, [led_state]OUT DX, AL; 初始化计数器MOV [interrupt_counter], 0MOV [last_report], 0RET; =============================================
; 主初始化程序
; =============================================
INITIALIZATION:; 初始化系统CALL INIT_SYSTEM; 初始化UARTCALL INIT_UART; 初始化8259 PICCALL INIT_PIC; 设置中断向量CALL SET_INTERRUPT_VECTOR; 通过串口发送启动消息MOV SI, OFFSET startup_msgCALL SEND_STRING; =============================================
; 主程序循环
; =============================================
MAIN_LOOP:; 更新LED状态CALL UPDATE_LED; 更新报告计数器INC [last_report]CMP [last_report], REPORT_INTERVALJB SKIP_REPORT; 重置报告计数器MOV [last_report], 0; 报告中断计数CALL REPORT_COUNTERSKIP_REPORT:; 检查是否有接收到的字符CALL BUFFER_READJNC NO_DATA         ; 无数据则继续等待; 通过串口回显接收到的字符CALL SEND_CHAR; 检查是否为退出命令;CMP AL, 1BH         ; ESC键;JE EXIT_PROGRAMNO_DATA:; 短延时以控制闪烁频率MOV CX, 3000        ; 延时参数
DELAY_SHORT:LOOP DELAY_SHORTJMP MAIN_LOOP; =============================================
; 退出程序
; =============================================
EXIT_PROGRAM:; 发送最终中断计数报告CALL REPORT_COUNTER; 恢复原始中断屏蔽字MOV DX, PIC_DATAMOV AL, [original_mask]OUT DX, AL; 禁用UART中断MOV DX, IERMOV AL, 00HOUT DX, AL; 关闭LEDMOV DX, 800HMOV AL, 00HOUT DX, AL; 通过串口发送退出消息MOV SI, OFFSET exit_msgCALL SEND_STRING; 返回DOSMOV AH, 4CHINT 21H; =============================================
; 数据区
; =============================================
original_mask DB 0     ; 原始8259中断屏蔽字
startup_msg DB 0Dh, 0Ah, 'UART Interrupt Counter Program Started', 0Dh, 0AhDB 'Press ESC to exit...', 0Dh, 0Ah, 0
exit_msg    DB 0Dh, 0Ah, 'Program terminated.', 0Dh, 0Ah, 0
counter_msg DB 0Dh, 0Ah, 'Interrupt count: ', 0
counter_end DB ' times', 0Dh, 0Ah, 0  end_flag    DB  55h,55h,55h,55h,55hEND INITIALIZATION

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/909554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Postgresql中跟踪SQL语句

文章说明 本文主要说明如何在Postgresql中跟踪实际执行的SQL语句。 本文内容有如下应用场景: 在系统中执行了一系列的操作,需要将这些操作转化成SQL在正式环境上一次性执行,省下重新执行一遍的操作时间。最近系统数据被人或被程序修改导致…

【信创-k8s】重磅-鲲鹏arm+麒麟V10离线部署k8s1.30+kubesphere4.1.3

随着信创产业的推进,鲲鹏arm64架构得以快速发展。而由于信创领域的主要客户通常部署在内网环境中,这使得离线部署成为该架构方案实施过程中不可或缺的关键环节。 **环境涉及软件版本信息** 服务器芯片: **鲲鹏920/飞腾2000(arm64)** 操作系统&#xff…

第11章:Neo4j实际应用案例

理论知识和技术细节固然重要,但真正理解Neo4j的价值在于了解它如何解决实际业务问题。本章将探讨Neo4j在各个领域的实际应用案例,包括社交网络分析、推荐系统、知识图谱以及欺诈检测与安全分析。通过这些案例,读者可以了解如何将前面章节学到…

数字图像处理与OpenCV初探

什么是数字图像处理? 当今时代,数字图像无处不在。手机拍照、安防监控、医疗检查、地图导航、工业质检……我们每天都在接收、分析和处理大量图像信息。对于计算机而言,图像并不是一张“看得懂”的照片,而是由数值组成的矩阵。如何…

ubuntu网络连接失败 + mobaxterm拖拽文件出错等问题解决方法

网络连接问题&#xff0c;表现在不能通过源下载以及更新 终端问题显示【通过 ip a 命令获得】 kejiubuntu:~/Desktop$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00…

C# CS_Prj01 串口通信控制台程序

一直以来&#xff0c;玩8088单板机&#xff0c;上位机都是使用的绿色现成的串口软件。 今天&#xff0c;感觉8088单板机的各部分测试都基本完成了。 本着玩的精神&#xff0c;自己写一个上位机的简单串口程序&#xff0c;与自己的8088单板机通讯。 功能&#xff1a;一个完整…

40套精品大气黑金系列行业PPT模版分享

黑金系列PPT模版&#xff0c;优秀员工颁奖典礼PPT模版&#xff0c;消费订货会PPT模版&#xff0c;共赢未来PPT模版&#xff0c;投资类PPT模版&#xff0c;双12年终盛典PPT模版&#xff0c;商业计划书PPT模版&#xff0c;高端通用企业文化PPT模版&#xff0c;公司喜报企业捷报PP…

SAP学习笔记 - 开发31 - 前端Fiori开发 Device Adaptation(设备自适应)

上一章讲了Fiori开发中的 Responsiveness&#xff08;响应式设计&#xff09;。 SAP学习笔记 - 开发30 - 前端Fiori开发 Responsiveness&#xff08;响应式设计&#xff09;-CSDN博客 本章继续学习Fiori 开发中的知识。 目录 1&#xff0c;Device Adaptation&#xff08;设备…

网络的那些事——初级——OSPF(2)

前面说了OSPF的状态机和一起简单的OSPF配合&#xff0c;接下这章继续写OSPFV2 IP frr和OSPFV3. 什么是OSPF IP FRR? OSPF IP FRR&#xff08;Fast Reroute&#xff09;利用全网链路状态数据库&#xff0c;预先计算出备份路径保存在转发表中&#xff0c;以备在故障时提供流量保…

C++(初阶)(二十一)——unordered_set和unordered_map

二十二&#xff0c;unordered_set和unordered_map的使用 1.unordered_set 1.1介绍 c11 template<class Key,class Hash std::hash<Key>,class KeyEqual std::equal_to<Key>,class Allocator std::allocator<Key> > class unordered_set;c17 na…

Java面试题:分布式ID时钟回拨怎么处理?序列号耗尽了怎么办?

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录 引言1 分布式ID2 问题2.1 时钟回拨2.1.1 毫秒级时…

影视剧学经典系列-梁祝-陶渊明《感士不遇赋并序》

1、背景 《感士不遇赋并序》是东晋诗人陶渊明创作的一篇抒发怀才不遇之慨的辞赋作品。受董仲舒《士不遇赋》和司马迁《悲士不遇赋》启发&#xff0c;陶渊明借古喻今&#xff0c;批判“真风告逝&#xff0c;大伪斯兴”的乱世。社会批判‌以“密网裁而鱼骇&#xff0c;宏罗制而鸟…

Spring Cloud Gateway 全面学习指南

Spring Cloud Gateway 全面学习指南 学习目录 第一部分&#xff1a;基础概念与核心架构 API网关概述与Spring Cloud Gateway简介Spring Cloud Gateway核心架构与工作原理Spring Cloud Gateway与Zuul的对比分析Spring Cloud Gateway核心组件详解 第二部分&#xff1a;基础配…

蛋白分析工具和数据库

UniProt&#xff08;Universal Protein Resource&#xff09;是一个综合性的蛋白质数据库&#xff0c;提供了全球范围内已知的蛋白质序列和功能信息。其中&#xff0c;UniProtKB&#xff08;UniProt Knowledgebase&#xff09;是最核心的组成部分&#xff0c;包含了经过注释和分…

Docker -- 快速入门

镜像与容器 当我们使用Docker安装应用时&#xff0c;Docker会自动搜索并下载应用镜像&#xff08;image&#xff09;。镜像不仅包含应用本身&#xff0c;还包含应用运行所需要的环境&#xff0c;配置、系统函数库。Docker会在运行镜像时创建一个隔离环境&#xff0c;称为容器&…

输入数量未知如何设置输入

在 C 的算法题中&#xff0c;如果你不知道输入数据有多少组&#xff08;即测试用例的数量未知&#xff09;&#xff0c;通常的处理方式是使用 循环读取输入直到文件结束 &#xff08;EOF&#xff09;。这类题目常见于在线评测系统&#xff08;如 LeetCode、牛客网、POJ 等&…

如何在Windows上使用qemu安装ubuntu24.04服务器?

2025年6月15日&#xff0c;周日晚上 在Windows上使用QEMU安装Ubuntu 24.04需要完成环境配置、镜像准备、虚拟机创建及系统安装等步骤。以下是综合多个搜索结果后的详细指南&#xff1a; 1. 安装QEMU环境 下载QEMU Windows版 从QEMU官网下载64位安装包&#xff08;如qemu-w64-s…

前端开发面试题总结-vue2框架篇(二)

Vue2高频问答 一、为什么 Vue 的 data 属性必须声明为返回一个初始数据的函数? 回答重点&#xff1a; Vue 的 data 属性声明成一个返回初始数据的函数&#xff0c;是为了确保每个组件实例都有独立的状态。通过这种方式&#xff0c;避免了组件使用相同的数据对象导致的状态共…

Web第二次方向考核复盘

一、简答题 1. &#xff08;1&#xff09;为什么要清除浮动&#xff1f; 答&#xff1a;当子元素浮动时会脱离文档流&#xff0c;父元素无法正确计算子元素高度导致高度、边框异常显示。同时会影响后续文档流布局。 <style>.box1 {border: solid 2px #000;}.child1 {fl…

Linux入门(十八)read函数

read 读取控制台输入 基本语法 read 选项 参数 选项 -p 指定读取值时的提示符 -t 指定读取值时等待的时间&#xff08;秒&#xff09;&#xff0c;如果没有在指定的时间内输入&#xff0c;就不再等待了 参数 变量&#xff1a;指定读取值的变量名 实例&#xff1a; 1、读取控制…