---
tags:
- 接口与通讯技术
- 8259A
- 中断控制器
- 可编程芯片
create time: 2026-06-26 23:05
---
# 8259A 中断控制器
## 概述
8259A 是 Intel 公司生产的可编程中断控制器(Programmable Interrupt Controller, PIC),**在全部 4 套试卷中均有出现**。它负责管理和控制 8086 系统中的外部中断请求,支持 8 级优先级中断,可通过级联扩展至最多 64 级。本芯片的知识点主要集中在 **初始化命令字(ICW)编写**、**中断响应过程** 和 **优先级管理** 三个方面。
> [!tip] 考试要点
> - **ICW 写入顺序**:ICW1 → ICW2 → ICW3(可选)→ ICW4(可选)
> - **ICW2 与中断类型码**的计算:高 5 位由程序员设定,低 3 位自动对应 IR0~IR7
> - **中断响应时序**:两个 INTA 脉冲期间 8259A 分别执行什么操作
> - **OCW2 EOI 命令**的发送方式和端口
> - **全嵌套方式**的优先级规则和适用场景
> - **级联系统**的中断级数和 ICW3 设置
## 正文
### 1. 8259A 的核心功能
```mermaid
graph TB
A["IR0~IR7 中断请求输入"] --> B["8259A"]
B -- "INT 输出" --> C["CPU"]
C -- "INTA 响应" --> B
B -- "中断类型码" --> C
D["优先级判别器 PR"] <--> B
E["中断屏蔽寄存器 IMR"] <--> B
F["中断服务寄存器 ISR"] <--> B
G["中断请求寄存器 IRR"] <--> B
```
| 寄存器 | 缩写 | 位数 | 功能说明 |
|--------|------|:----:|------|
| 中断请求寄存器 | **IRR** | 8 位 | 记录哪些 IR 引脚有pending的中断请求,某位 = 1 表示对应 IRi 有未响应的请求 |
| 中断屏蔽寄存器 | **IMR** | 8 位 | 某位 = 1 则屏蔽对应 IR 的中断请求(通过 OCW1 设置),= 0 则允许 |
| 中断服务寄存器 | **ISR** | 8 位 | 记录当前正在被 CPU 服务的中断源,用于嵌套管理;中断服务完成后需清除 |
| 优先级判别器 | **PR** | — | 从 IRR 中未被 IMR 屏蔽的请求里选出最高优先级的中断 |
> [!question] IRR、IMR、ISR 三者如何协作完成一次中断响应?
> 1. 外设在 IRi 引脚产生中断请求 → **IRR** 对应位置 1
> 2. 8259A 将 IRR 与 **IMR** 做按位与运算:某位 = IMR 该位的值 → 该请求被屏蔽,不可响应
> 3. 未被屏蔽的请求送入 **PR** 进行优先级判别,选出的最高优先级候选与 **ISR** 比较
> 4. 若候选优先级高于 ISR 中所有正在服务的中断,则 8259A 向 CPU 发出 **INT** 信号
> 5. CPU 响应后给出两个 **INTA** 脉冲 → 第一个 INTA 将 ISR 对应位置 1、IRR 对应位清 0;第二个 INTA 将中断类型码送上数据总线
### 2. 端口地址
8259A 有两个端口地址,取决于总线地址线 **A0** 的值:
| A0 | 端口用途 | 最小系统中地址 |
|----|----------|:--------------:|
| 0 | **偶地址端口** — 写 ICW1、OCW2、OCW3;读 ISR / IRR | **20H** |
| 1 | **奇地址端口** — 写 ICW2、ICW3、ICW4、OCW1 | **21H** |
> [!info] 端口地址记忆法
> - A0 = 0 → 偶地址 → 20H("偶"和"零"都联想为偶数)
> - A0 = 1 → 奇地址 → 21H(比 20H 大 1,刚好对应 A0=1)
> - 最小系统中 8259A 的端口就是 20H/21H,考试默认使用此地址
### 3. 初始化命令字(ICW)
8259A 上电后必须通过 ICW 完成初始化,**必须按顺序写入**,每个命令字占一个 I/O 写周期:
```mermaid
graph LR
A["ICW1\n(偶地址端口 A0=0)"] --> B{"ICW1 的 D1 SNGL"}
B -- "0: 级联模式" --> C["ICW2\n(奇地址端口)"]
B -- "1: 单片模式" --> C
C --> D["ICW3\n(仅级联时写)"]
D --> E["ICW4\n(按需)"]
E --> F["初始化完成"]
```
#### ICW1(偶地址端口,A0=0)
```
D7 D6 D5 D4 D3 D2 D1 D0
[ Don't Care ] 1 LTIM: 0=边沿触发 1=电平触发 SNGL: 0=级联 1=单片 IC4: 0=不需ICW4 1=需ICW4
```
| 位 | 符号 | 含义 | 说明 |
|---|------|------|------|
| D4 | — | **固定为 1** | 这是识别 ICW1 的标志位,若 D4=0 则视为 OCW 而非 ICW |
| D3 | LTIM | 触发方式 | 0 = 边沿触发(IR 上升沿有效);1 = 电平触发(IR 高电平有效) |
| D2 | SNGL | 级联标志 | 0 = 多片级联(后续需要写 ICW3);1 = 单片系统(不写 ICW3) |
| D0 | IC4 | ICW4 标志 | 0 = 不需要 ICW4(默认工作在 8080/8085 模式);1 = 需要 ICW4(8086 模式下必须写) |
> [!example] ICW1 计算示例
> **要求**:边沿触发、级联方式、需要 ICW4
>
> - D4 固定 = 1
> - LTIM = 0(边沿触发)
> - SNGL = 0(级联)
> - IC4 = 1(需要 ICW4)
> - D7~D5 可填 0
>
> ICW1 = `0001 0001B` = **11H**
#### ICW2(奇地址端口,A0=1)
ICW2 提供 **中断类型码的高 5 位**(T7~T3),低 3 位(T2~T0)由 8259A **根据请求来源自动填入**。
```
D7 D6 D5 D4 D3 D2 D1 D0
T7 T6 T5 T4 T3 固定为 0 (IR 编码会自动填充)
```
中断类型码的计算公式:
$$
\text{类型码} = \text{ICW2}_{[7:3]} \times 2^3 + \text{IR编号}
$$
即:ICW2 高 5 位左移 3 位,再加上 IR 引脚号(0~7)。
> [!example] ICW2 计算示例
>
> **例 1**:IR0~IR7 对应中断类型码 80H~87H
> - 80H = `1000 0000B`,高 5 位 = `10000`
> - ICW2 = **80H**
> - 验证:IR0 → 80H, IR1 → 81H, ..., IR7 → 87H ✓
>
> **例 2**:IR0~IR7 对应中断类型码 20H~27H
> - 20H = `0010 0000B`,高 5 位 = `00100`
> - ICW2 = **20H**
>
> **例 3**:IR0~IR7 对应中断类型码 48H~4FH
> - 48H = `0100 1000B`,高 5 位 = `01001`
> - ICW2 = **90H** (注意:取高 5 位而不是取原字节!48H 的高 5 位是 `01001` = 9H,所以 ICW2 = 90H)
> [!warning] 易错点
> ICW2 的值不等于第一个中断类型码!ICW2 只保留高 5 位,低 3 位填 0。例如要分配 48H~4FH,ICW2 = 90H(不是 48H)。这是因为低 3 位由 IR 编号自动填入。
#### ICW3(奇地址端口,仅级联时需要)
ICW3 在主片和从片中有不同含义:
- **主片 ICW3**:每位对应一个 IR 引脚,某位 = 1 表示该 IR 引脚连接了从片的 INT 输出
- 例如 IR2 和 IR5 各接一个从片 → 主片 ICW3 = `0010 0100B` = **24H**
- **从片 ICW3**:低 3 位表示从片的 INT 接到主片的哪个 IR 引脚(即从片的 ID 编号)
- 例如从片接到主片 IR2 → 从片 ICW3 = `0000 0010B` = **02H**
> [!example] 一主二从级联的 ICW3 设置
>
> - 主片 IR2 接从片 1,IR5 接从片 2
> - 主片 ICW3 = IR2 + IR5 = `0010 0100B` = **24H**
> - 从片 1 ICW3 = 2(接到主片 IR2)= **02H**
> - 从片 2 ICW3 = 5(接到主片 IR5)= **05H**
#### ICW4(奇地址端口,按需)
```
D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 SFNM: BUF: M/S: uPM: (保留=0)
0=普通 0=非缓冲 0=从片 0=8080/8085
1=特殊全嵌套 1=缓冲 1=主片 1=8086/8088
```
| 位 | 符号 | 含义 |
|---|------|------|
| D4 | SFNM | **Special Fully Nested Mode**,特殊全嵌套方式。当系统中有多片 8259A 级联且其中一片本身也有子级联时使用,该片的 ISR 允许同级中断嵌套 |
| D3 | BUF | **Buffer Flag**,缓冲模式标志。= 1 表示系统使用缓冲区(通常配合 82283 收发器),此时需结合 M/S 位决定选择器;= 0 为非缓冲直接连接 |
| D2 | M/S | Master/Slave,仅当 BUF=1 时有效。= 1 为主片(选择器输出使能);= 0 为从片 |
| D0 | uPM | **Unified Protected Mode**,CPU 模式。= 1 表示 8086/8088 模式(自动 EOI 禁用);= 0 表示 8080/8085 模式 |
> [!warning] 8086 系统中 ICW4 必须写
> 8086/8088 系统下,ICW4 的 D0 = uPM = 1 是必须的。考试中常见最小初始化序列为:**ICW1 → ICW2 → ICW4**(跳过 ICW3)。
> [!example] ICW4 计算示例
> **要求**:8086 模式,非缓冲方式
> - D7~D5 = 000
> - SFNM = 0(普通模式)
> - BUF = 0(非缓冲)
> - M/S = 0(不考虑,BUF=0 时无效)
> - uPM = 1(8086 模式)
> - D0 = 0(保留位)
>
> ICW4 = `0000 0010B` = **02H**
>
> **要求**:8086 模式,缓冲方式,主片
> - BUF = 1, M/S = 1, uPM = 1
> - ICW4 = `0000 1110B` = **0EH**
### 4. 操作命令字(OCW)
OCW 在初始化完成后、系统运行过程中根据需要写入,可随时修改:
| OCW | 端口 | 可读写 | 功能 |
|-----|------|:------:|------|
| **OCW1** | 奇地址 (A0=1) | 仅写 | 设置中断屏蔽字,直接写入 IMR。某位 = 1 屏蔽对应中断 |
| **OCW2** | 偶地址 (A0=0) | 仅写 | 控制中断结束方式和优先级轮换策略 |
| **OCW3** | 偶地址 (A0=0) | 读写 | 查询 RR/RIS 状态、设置特殊屏蔽方式 |
#### OCW2 — EOI 命令
```
D7 D6 D5 D4 D3 D2 D1 D0
0 0 R SL EOI (reserved)
```
三种常用操作:
| 操作 | D1 D0 | D2 | 说明 | 示例值 |
|------|:-----:|:--:|------|:------:|
| **普通 EOI** | xx | 0 | 置 EOI=1, R=SL=0 → 清除 ISR 中优先级最高的位 | **20H** |
| **特殊 EOI** | 0x | 1 | 置 EOI=1, R=0, SL=1 → 指定清除 ISR 中 IRk 对应的位(k 由 D4~D2 指定) | **C0H**(清除 IR0)|
| **优先级自动循环** | 10 | 0 | 设 R=1, SL=0, EOI=0 → 服务完后最高优先级降为最低,次高变为最高 | **A0H** |
> [!info] EOI 命令怎么发?
> OCW2 写入**偶地址端口**(最小系统 = 20H)。在中断服务程序末尾发送 EOI 以通知 8259A 该中断处理完毕:
> ```asm
> MOV AL, 20H ; 普通 EOI
> OUT 20H, AL ; 发送到偶地址端口
> ```
> [!question] 为什么要发送 EOI?
> 发送 EOI 后,8259A 会将 ISR 中对应中断源的位清 0。不清 0 的话,8259A 认为该中断仍在服务,不会响应相同或更低优先级的中断。只有在自动 EOI 模式(某些特定配置下)才不需要手动发送 EOI。
#### OCW3 — 特殊屏蔽方式和读命令
OCW3 的功能较多样:
- **设置特殊屏蔽方式(ESMM = 1)**:某位 = 1 时进入特殊屏蔽方式,此时 IMR 的该位 = 1 允许同级别中断嵌套(只屏蔽比当前低的)
- **设置 RR/RIS 读取命令**:RR=1 时,下一个 INTA 脉冲读出 ISR(RR=1, RIS=1)或 IRR(RR=1, RIS=0)的内容
- **查询 polled 命令**:用于轮询方式查找最高优先级挂起中断
### 5. 中断响应过程
```mermaid
sequenceDiagram
participant P as "外设"
participant I as "8259A"
participant C as "CPU"
P->>I: "IRi 引脚产生中断请求"
Note over I: "IRR[i] = 1"
Note over I: "PR 判别优先级"
I->>C: "INT = 1 (向 CPU 发中断请求)"
C->>I: "第一个 INTA 脉冲"
Note over I: "ISR[i] = 1
IRR[i] = 0
8259A 锁存当前优先级"
C->>I: "第二个 INTA 脉冲"
I->>C: "中断类型码 N 送上数据总线"
Note over C: "CPU 读类型码 N"
Note over C: "向量地址 = N × 4"
C->>C: "从向量表读取 CS:IP
转去执行中断服务程序"
```
> [!warning] 两个 INTA 脉冲的作用截然不同
> - **第一个 INTA**:8259A 内部操作 —— 将被响应当前中断置入 ISR、从 IRR 中清除对应位,并锁定当前优先级以防止同级中断干扰。此时 CPU 尚未获取类型码。
> - **第二个 INTA**:8259A 将锁存的中断类型码(已拼接好的完整 8 位类型码)放到数据总线上供 CPU 读取。
### 6. 中断向量表
8086 的中断向量表位于内存最低地址 **00000H ~ 003FFH**(共 1KB),可存放 256 个中断向量(每个向量 4 字节)。
中断向量地址计算公式:
$$
\text{向量地址} = \text{中断类型号} \times 4
$$
每个向量占 4 字节,布局为:**低 2 字节 = IP(偏移地址),高 2 字节 = CS(段地址)**。
| 向量地址 | 存储内容 | 说明 |
|---------|----------|------|
| N×4 | IP 低字节 | 跳转目标偏移 |
| N×4+1 | IP 高字节 | |
| N×4+2 | CS 低字节 | 跳转目标段 |
| N×4+3 | CS 高字节 | |
> [!example] 中断向量表地址计算
>
> **例**:中断类型码为 80H,其向量存放在哪里?
> - 向量地址 = 80H × 4 = `10000000₂` × 4 = **200H**
> - 向量存放在 **00000H + 200H = 00200H ~ 00203H** 四个字节
> - 00200H = IP 低字节, 00201H = IP 高字节, 00202H = CS 低字节, 00203H = CS 高字节
### 7. 优先级管理方式
| 方式 | 特点 | 优先级变化 | 配置方法 |
|------|------|-----------|---------|
| **固定优先级**(默认,全嵌套) | IR0 最高 → IR7 最低,永远不变 | 无变化 | 默认工作模式 |
| **自动优先级轮换** | 服务完的中断降为最低,原来的最低升到最高 | 循环移动 | OCW2 = A0H(编程旋转) |
| **特殊全嵌套** | 允许**同级**中断嵌套,用于级联系统中主片 | 无变化 | ICW4 的 SFNM=1 |
| **特殊屏蔽方式** | 临时屏蔽当前优先级,只允许更低优先级中断 | 按需切换 | OCW3 设置 ESMM + SIM |
> [!question] 全嵌套方式下,IRQ5 正在服务,哪些中断可以打断它?
> 答:只有优先级更高的 **IRQ0 ~ IRQ4** 可以打断 IRQ5。IRQ6 和 IRQ7 优先级低于 IRQ5,必须等待 IRQ5 服务完成(发送 EOI 清除 ISR[5])后,才能被调度。**即使 IRQ6/IRQ7 没有被 IMR 屏蔽,也不会响应**。
> [!info] 全嵌套 vs 特殊全嵌套
> - **全嵌套**(固定优先级):不同优先级之间可以嵌套,但**同级不能嵌套**
> - **特殊全嵌套**(SFNM=1):同全嵌套一样默认不同级可嵌套,但通过 OCW3 可将某个中断设为特殊屏蔽,允许**同级**中断抢占——这在级联系统的从片中很重要(从片内部可能还需要处理多个同级子中断)
### 8. 级联扩展
| 配置 | 中断级数 | IR 端口占用 | 说明 |
|------|:--------:|------------|------|
| 单片 8259A | **8 级** | 8 | IR0~IR7 均直接使用 |
| 一主一从级联 | **15 级** | 8 + 7 = 15 | 从片占用主片 1 个 IR(8+8-1=15) |
| 一主二从级联 | **22 级** | 8 + 7 + 7 = 22 | 两个从片各占用主片 1 个 IR |
| 四片级联(1主3从) | **29 级** | 8 + 7×3 = 29 | 最多扩展到 64 级(4 片 8259A) |
> [!info] 为什么是 8n-1 而不是 8n?
> 每增加一片从片,需要占用主片(或上级从片)的一个 IR 端口来传递从中继而来的中断请求,因此实际可用的中断级数 = 8×N - (N-1) = 7N + 1,其中 N 为 8259A 片数。第一片贡献 8 级,之后每加一片净增 7 级。
### 9. 典型初始化程序
以下是一个完整的初始化示例(最小系统,8086 模式):
```asm
; ============================================================
; 8259A 初始化程序(最小系统)
; 端口地址:20H(偶地址,A0=0),21H(奇地址,A0=1)
; 条件:边沿触发、单片、中断类型码 80H~87H、8086 模式
; ============================================================
MOV AL, 11H ; ICW1: 边沿触发(LTIM=0), 单片(SNGL=1), 需ICW4(IC4=1)
; 0001 0001B = 11H
OUT 20H, AL ; 写入偶地址端口
MOV AL, 80H ; ICW2: 中断类型码基址 = 80H(高5位=10000)
OUT 21H, AL ; 写入奇地址端口
; IR0→80H, IR1→81H, ..., IR7→87H
MOV AL, 02H ; ICW4: 8086模式(uPM=1), 非缓冲
; 0000 0010B = 02H
OUT 21H, AL ; 写入奇地址端口
; ---- 初始化完成 ----
; 此时 IMR = 00H(复位默认值),所有中断开放
```
#### 中断服务程序模板
```asm
INT_ISR PROC FAR
PUSH AX ; 保护现场
PUSH BX
PUSH CX
PUSH DX
PUSH DS
; ---- 中断处理逻辑 ----
; ... 具体处理代码 ...
MOV AL, 20H ; 普通 EOI 命令
OUT 20H, AL ; 发送到 8259A(偶地址端口)
POP DS ; 恢复现场
POP DX
POP CX
POP BX
POP AX
IRET ; 中断返回(从栈中恢复 CS:IP 和 FLAGS)
INT_ISR ENDP
```
> [!info] IRET vs RET 的区别
> - **RET**:普通子程序返回,只弹出 IP
> - **IRET**:中断返回,依次弹出 IP → CS → FLAGS,恢复中断前的完整上下文
### 10. 考试综合例题
> [!example] 【真题型】设计 8259A 初始化程序
>
> **题目**:某 8086 系统中使用单片 8259A,端口地址 20H/21H,要求:
> - 边沿触发
> - 中断类型码起始于 70H
> - 工作在 8086 模式
> - 初始化后允许所有中断
>
> **解答**:
> ```asm
> MOV AL, 70H ; ICW2: 中断类型码基址 = 70H(高 5 位 = 01110)
> ; IR0→70H, IR1→71H, ..., IR7→77H
> OUT 21H, AL
>
> MOV AL, 02H ; ICW4: 8086 模式 (uPM=1), 非缓冲
> OUT 21H, AL
>
> MOV AL, 00H ; OCW1: 不屏蔽任何中断(所有中断开放)
> OUT 21H, AL
> ```
> [!tip] ICW2 取值要点
> ICW2 的值就是 **IR0 对应的中断类型码**。例如题目要求中断类型码从 70H 开始,ICW2 直接设为 70H 即可。这是因为 ICW2 的高 5 位构成类型码的高 5 位,低 3 位自动为 0,恰好对应 IR0(编号为 0)。
---
> [!question] 【综合题】多片级联系统初始化
>
> **题目**:某 8086 系统采用一主两从级联方式,端口地址 20H/21H,要求:
> - 边沿触发
> - 主片 IR2 接从片 1,IR5 接从片 2
> - 所有芯片中断类型码分别起始于 40H、50H、60H
> - 工作在 8086 模式、缓冲方式
>
> **解答**:
>
> **主片初始化**:
> ```asm
> MOV AL, 13H ; ICW1: 边沿(0), 级联(0), 需ICW4(1) → 0001_0011B = 13H
> OUT 20H, AL
> MOV AL, 40H ; ICW2: 主片类型码基址 = 40H
> OUT 21H, AL
> MOV AL, 24H ; ICW3: IR2+IR5 = 0010_0100B = 24H
> OUT 21H, AL
> MOV AL, 0EH ; ICW4: 8086模式(uPM=1), 缓冲(BUF=1), 主片(M/S=1) = 0000_1110B = 0EH
> OUT 21H, AL
> ```
>
> **从片 1 初始化**:
> ```asm
> MOV AL, 11H ; ICW1: 边沿(0), 单片(1), 需ICW4(1) = 0001_0001B = 11H
> OUT 20H, AL
> MOV AL, 50H ; ICW2: 从片1类型码基址 = 50H
> OUT 21H, AL
> MOV AL, 02H ; ICW3: 接主片IR2 → ID=2 = 00H
> OUT 21H, AL
> MOV AL, 0AH ; ICW4: 8086模式, 缓冲, 从片(M/S=0) = 0000_1010B = 0AH
> OUT 21H, AL
> ```
>
> **从片 2 初始化**:
> ```asm
> MOV AL, 11H ; ICW1: 同从片1
> OUT 20H, AL
> MOV AL, 60H ; ICW2: 从片2类型码基址 = 60H
> OUT 21H, AL
> MOV AL, 05H ; ICW3: 接主片IR5 → ID=5 = 05H
> OUT 21H, AL
> MOV AL, 0AH ; ICW4: 8086模式, 缓冲, 从片(M/S=0) = 0AH
> OUT 21H, AL
> ```
>
> > [!info] 解题思路
> > 1. 先确认级联方式 → SNGL=0 → 需要 ICW3
> > 2. 确定 ICW2 = 各芯片中断类型码的起始值(IR0 对应的类型码)
> > 3. 主片 ICW3 = 连接从片的 IR 引脚编号之和
> > 4. 从片 ICW3 = 连接到主片的 IR 引脚编号(即自身 ID)
> > 5. 缓冲模式下,ICW4 中 BUF=1,M/S 区分主从片
> [!question] 【选择题风格】8259A 在最小系统中的端口地址是多少?
> A) 20H/21H B) 22H/23H C) 28H/29H D) 30H/31H
>
> 答:**A) 20H/21H**。这是标准答案,考试默认使用该地址。
## 附录:快速复习卡
> [!summary] 核心口诀
> - **ICW 顺序记心中**:ICW1 → ICW2 → ICW3(级联) → ICW4(8086必写)
> - **奇偶分清单又明**:偶地址(20H)写 ICW1/OCW2/OCW3,奇地址(21H)写 ICW2/3/4 和 OCW1
> - **ICW2 高位我设定**:高 5 位自己填,低 3 位自动对应 IR 号
> - **EOI 必须手动发**:OCW2=20H 送 20H,别忘写在 ISR 末尾
> - **全嵌套高低分明**:IR0 永远最高,IR7 永远最低
## 关联笔记
- [[8255A可编程并行接口]]
- [[8254定时计数器]]
- [[8251A串行通信接口]]
- [[接口与通讯技术/试题册/index|试题册索引]]