8088 单板机 NMI 中断程序示例 (脱离 DOS 环境)
求组DeepSeek给的将要进行的8088单板机NMI中断编程示例。
·
求组DeepSeek给的将要进行的8088单板机NMI中断编程示例。
/* nmidemo.c - 8088 单板机 NMI 中断演示程序 */
/* 脱离 DOS 环境,直接运行在裸机上 */
/* 使用 Digital Mars C 编译器,TINY 模式编译 */
/* 硬件配置假设:
- 8088 CPU @ 4.77MHz
- 8255 PPI (可编程外设接口) 连接 LED
- NMI 按钮连接到 NMI 引脚
- 系统 ROM 从 0xF0000 开始 */
/* 端口定义 */
#define PORT_PPI_A 0x60 // 8255 PPI 端口 A (LED 控制)
#define PORT_PPI_B 0x61 // 8255 PPI 端口 B
#define PORT_PPI_C 0x62 // 8255 PPI 端口 C
#define PORT_PPI_CTRL 0x63 // 8255 PPI 控制端口
/* 函数声明 */
void nmi_handler(void);
void set_nmi_handler(void);
void init_ppi(void);
void delay(unsigned int count);
void outportb(unsigned short port, unsigned char value);
unsigned char inportb(unsigned short port);
/* NMI 计数器 */
volatile unsigned char nmi_count = 0;
/* 主函数 */
int main() {
// 设置栈指针 (在 64KB RAM 顶部)
asm {
mov ax, cs
mov ss, ax
mov sp, 0xFFFE
}
// 初始化硬件
init_ppi();
set_nmi_handler();
// 初始状态: 点亮 LED 0
outportb(PORT_PPI_A, 0x01);
// 主循环 - 等待 NMI
while (1) {
// 循环点亮 LED
for (int i = 0; i < 8; i++) {
outportb(PORT_PPI_A, 1 << i);
delay(0xFFFF);
}
}
return 0;
}
/* 设置 NMI 处理程序 */
void set_nmi_handler() {
// 保存原始 NMI 向量 (中断号 2)
unsigned int nmi_vector = 2 * 4; // 每个中断向量占 4 字节
// 获取原始 NMI 处理程序地址
unsigned int orig_offset, orig_segment;
asm {
push ds
xor ax, ax
mov ds, ax
mov si, [nmi_vector]
mov [orig_offset], si
mov si, [nmi_vector+2]
mov [orig_segment], si
pop ds
}
// 设置新的 NMI 处理程序
asm {
push ds
xor ax, ax
mov ds, ax
mov si, [nmi_vector]
mov word ptr [si], offset nmi_handler
mov si, [nmi_vector+2]
mov [si], cs ; 段地址 = CS
pop ds
}
// 启用 NMI (清除 CMOS 寄存器第 7 位)
outportb(0x70, inportb(0x70) & 0x7F);
}
/* NMI 中断处理程序 */
void nmi_handler() {
// 保存寄存器
asm {
push ax
push bx
push cx
push dx
push ds
}
// 设置数据段
asm {
mov ax, cs
mov ds, ax
}
// 增加 NMI 计数器
nmi_count++;
// 在 LED 上显示 NMI 发生 (二进制计数)
outportb(PORT_PPI_A, nmi_count);
// 延迟一段时间 (视觉反馈)
delay(0xFFFF);
// 恢复寄存器
asm {
pop ds
pop dx
pop cx
pop bx
pop ax
}
// 中断返回
asm iret;
}
/* 初始化 8255 PPI */
void init_ppi() {
// 设置 8255 控制字: 端口 A 输出, 模式 0
outportb(PORT_PPI_CTRL, 0x80); // 10000000b: 端口 A 输出, 端口 B 输出, 端口 C 输出
// 初始状态: 关闭所有 LED
outportb(PORT_PPI_A, 0x00);
}
/* 端口输出函数 */
void outportb(unsigned short port, unsigned char value) {
asm {
mov dx, port
mov al, value
out dx, al
}
}
/* 端口输入函数 */
unsigned char inportb(unsigned short port) {
unsigned char value;
asm {
mov dx, port
in al, dx
mov value, al
}
return value;
}
/* 简单延迟函数 */
void delay(unsigned int count) {
asm {
mov cx, count
delay_loop:
nop
loop delay_loop
}
}

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)