简介:这份《微型计算机接口技术及应用习题及答案》以PDF形式整理,面向学习微机原理与接口技术的高校学生、专升本及考研复习人群,可用于课后自测、期末复习与考点梳理。内容以问答形式展开,涵盖接口在微机应用中的作用与基本任务,I/O设备接口应具备的命令执行、状态返回、数据缓冲、设备寻址、信号转换及数据格式转换等功能,并延伸至总线组成与性能评价指标、ISA总线特点、多层次总线结构、端口与端口共用技术、统一编址与独立编址的优缺点、I/O端口地址译码电路设计的灵活性,以及内部定时与外部定时、软件定时与硬件定时、82C54A六种工作方式等章节重点。资源包内含1个PDF文件,约68KB,体积轻巧,便于打印或离线查阅。目前已有215人学习下载。答案按题号逐条对照,表述完整,适合作为章节复习提纲与问答题答题参考。
1. 从“习题及答案.pdf”说起:接口技术真正在考什么
有人把这份 PDF 存进平板,通勤时翻两页,觉得控制字无非是背张表格。真到拿 8255 点亮一块数码管时才卡住:题干里那句“PC7 作状态输入”决定了整个初始化顺序,背下来的 80H 写进去,板子毫无反应。微型计算机接口技术的习题看着像文科题,本质却是寄存器位域、总线时序、地址空间三件事的组合体操。8255、8253/8254、8259A、ADC0809、DAC0832 这些芯片的题目,几乎都能拆成四步:定端口地址、写控制字、算初值或时序、落一段最小汇编。这份“习题及答案”最合适的用法不是背,而是当作一份可复现的检查清单——每道题都能在仿真里或实验箱上跑一遍,跑不通就说明某个位理解错了。下面按这四步展开。
2. 接口技术习题的四类主考题型与判定依据
把整本习题翻完会发现,题目换汤不换药,基本落在四类上:端口地址译码、控制字与命令字、计数初值与时序、中断向量与程序流程。每一类都有固定判据,抓住判据,答案就是自己推出来的,而不是从答案页抄来的。下面按判据逐类拆,顺带把常错的那一位标出来。
2.1 端口地址译码题:先定边界,再谈片选
这类题通常在题干给一张 74LS138 或若干与非门的连线图,问“写出各芯片的端口地址范围”“有无地址重叠”。稳妥做法是先别急着算十六进制,把三件事确认清楚:哪些地址线参与了译码、片选信号是高有效还是低有效、芯片的 A0/A1 接到了哪两根地址线。第一件事决定地址范围里有多少“空洞”,第二件事决定条件写成等号还是取反,第三件事只决定端口偏移。
| 芯片 | 端口选择线 | 偏移 0 | 偏移 1 | 偏移 2 | 偏移 3 |
|---|---|---|---|---|---|
| 8255A | A1 A0 | A 口 | B 口 | C 口 | 控制口 |
| 8253/8254 | A1 A0 | 计数器 0 | 计数器 1 | 计数器 2 | 控制口 |
| 8259A | A0 | 偶地址:ICW1、OCW2、OCW3 | 奇地址:ICW2~ICW4、OCW1 | — | — |
| ADC0809 | A B C | IN0~IN7,占 8 个连续地址 |
全译码和部分译码的差别,用一段脚本比手算更容易看明白。把“参与译码的地址线及其要求电平”写成字典,未参与译码的位可以取 0 也可以取 1,重叠就出在这里。
# 由“参与译码的地址线及其要求电平”反推端口地址范围 # key = 地址线编号(A0 记 0),value = 片选有效时该线必须为的电平 decoded = {15: 0, 14: 0, 13: 0, 12: 0, 11: 0, 10: 0, 9: 1, 8: 1} lo = 0 for bit, val in decoded.items(): lo |= val << bit # 固定位按题目要求置位,其余位先取 0 free_mask = 0xFFFF for bit in decoded: free_mask &= ~(1 << bit) # 未参与译码的地址线可 0 可 1 hi = lo | free_mask base = lo & ~0x3 # 芯片用 A1A0 选端口,低两位不能当基址 print("地址范围:", hex(lo), "~", hex(hi), " 基址:", hex(base)) print("端口:", [hex(base + i) for i in range(4)])decoded里的键是地址线编号,值是片选有效时必须出现的电平,A15~A8 全为 0、A9 和 A8 为 1,算出来lo是 0x0300,free_mask是 0x00FF。也就是说,A7~A2 这六根线都没参与译码,芯片会被 0x300、0x304、0x308……共 64 个不同地址命中,这就是部分译码的地址重叠。base = lo & ~0x3这一步对应“A1A0 接芯片、A0 不接或接固定电平”的常见接法,得到的基址是 0x300,四个端口依次是 0x300~0x303。
最容易丢分的是把未参与译码的高位地址线当成 0 处理。题目里如果写“A15~A4 接译码器,A3~A0 接芯片”,那范围就只有 16 个地址,没有重叠;一旦图上出现悬空的高位线,答案里必须补一句“存在地址重叠”,只写一个地址范围会被判错。
2.2 控制字题:8255、8253、8259 的位域逐位拆开
控制字题分值高、判分机械,错一位整题归零。可靠的做法是先在草稿上画 8 个格子,从 D7 往下填,填完再合成十六进制,不要一边读题一边心算。三张最常考的控制字格式如下。
8255A 方式控制字(D7 必须为 1):
| 位 | D7 | D6 D5 | D4 | D3 | D2 | D1 | D0 |
|---|---|---|---|---|---|---|---|
| 含义 | 标志位=1 | A 组方式:00/01/1x | A 口:1 入 0 出 | C 口高 4 位:1 入 0 出 | B 组方式:0 方式 0,1 方式 1 | B 口:1 入 0 出 | C 口低 4 位:1 入 0 出 |
8253/8254 控制字:
| 位 | D7 D6 | D5 D4 | D3 D2 D1 | D0 |
|---|---|---|---|---|
| 含义 | 选计数器:00=T0,01=T1,10=T2 | 01 只低 8 位,10 只高 8 位,11 先低后高,00 锁存 | 方式 0~5 | 0 二进制,1 BCD |
8259A 的 ICW1:
| 位 | D7 | D6 D5 | D4 | D3 | D2 | D1 | D0 |
|---|---|---|---|---|---|---|---|
| 含义 | 固定为 1 | 8086 系统取 00 | 固定为 1,表示正在写 ICW1 | 1 电平触发,0 边沿触发 | 8086 系统取 0 | 1 单片,0 级联 | 1 需要 ICW4 |
把三张表写成函数,可以顺手验证答案:
def pack(bits: dict, width=8) -> int: """bits: {位号: 0 或 1},合成控制字""" v = 0 for i, b in bits.items(): assert b in (0, 1) and 0 <= i < width v |= b << i return v # 8255:A 组方式 0 且 A 口输出、PC7~PC4 输出;B 组方式 0 且 B 口输入、PC3~PC0 输入 ctrl8255 = pack({7: 1, 6: 0, 5: 0, 4: 0, 3: 0, 2: 0, 1: 1, 0: 1}) # 8253:计数器 1、先低后高、方式 3、二进制计数 ctrl8253 = pack({7: 0, 6: 1, 5: 1, 4: 1, 3: 0, 2: 1, 1: 1, 0: 0}) # 8259A ICW1:边沿触发、单片、需要 ICW4 icw1 = pack({7: 1, 6: 0, 5: 0, 4: 1, 3: 0, 2: 0, 1: 1, 0: 1}) print(hex(ctrl8255), hex(ctrl8253), hex(icw1)) # 0x83 0x76 0x93核对 8255 那一项:D7=1 表示方式控制字,D6D5=00 是 A 组方式 0,D4=0 表示 A 口输出,D3=0 表示 C 口高 4 位输出,D2=0 是 B 组方式 0,D1=1 表示 B 口输入,D0=1 表示 C 口低 4 位输入,合成 1000 0011B 即 0x83。8253 的 0x76 拆开是 D7D6=01 选 T1、D5D4=11 先低后高、D3D2D1=011 方式 3、D0=0 二进制。ICW1 的 0x93 拆开是 D7=1、D4=1、D3=0 边沿触发、D1=1 单片、D0=1 需要 ICW4。
对照答案页时先查两个硬性位:8255 的 D7 和 8259 的 D7、D4 必须为 1,这几个位错了后面全错。有些教材对 D6、D5 这两个“任意位”取法不同,写出来的十六进制会差一位,只要 D7、D4 以及触发方式、单片级联这几项和题目条件对得上,就不必纠结。
2.3 计数初值题:从时钟频率倒推,越界就级联
计数初值题的公式只有一条:分频类方式(方式 2、方式 3)下,计数初值等于输入时钟频率除以期望输出频率。16 位二进制计数的上限是 65536,写 0 就代表 65536;BCD 计数上限是 10000,写 0 代表 10000。只要算出来的初值超过这个上限,就说明要级联两个计数器。
举个典型题:2MHz 时钟要得到 1Hz 方波,分频比是 2,000,000,远超 65536。常见拆法是 T0 取初值 2000,把 2MHz 分成 1kHz,再用 T1 取初值 1000,把 1kHz 分成 1Hz,两级串联总的分频比正好是 2,000,000。拆法不唯一,写程序前可以先算一遍:
def nearest_pair(total, max_n=65536): """把分频比拆成两个都不超过 max_n 的计数器初值,优先整除且两值接近""" best = None for n1 in range(2, min(max_n, total) + 1): if total % n1: # 不能整除会产生频率误差,先跳过 continue n2 = total // n1 if n2 > max_n: continue if best is None or abs(n1 - n2) < abs(best[0] - best[1]): best = (n1, n2) return best print(nearest_pair(2_000_000)) # (2000, 1000) print(2_000_000 / 65536) # 30.5,说明单级绝对不够max_n这一项要按计数方式改:二进制方式填 65536,BCD 方式填 10000,题目里若出现“按 BCD 计数”,两级初值都得能写成十进制并且不超过 10000。total % n1的判断是为了控制频率误差,不能整除时误差等于“实际输出频率 = 时钟 / 取整后的初值”,题干一般会给出允许误差范围,把取整后的实际值算出来写进答案更稳妥。
写完初值还要写写入顺序。控制字里 D5D4=11 表示“先低后高”,程序里就必须先OUT低字节再OUT高字节,顺序反了计数器会按错误初值计数。若误设成 01(只写低 8 位),2000 会被截成 2000 & 0xFF = 208,输出频率差了近十倍——这是“答案对、结果不对”里最常见的一种。
2.4 中断向量题:类型号乘 4 之后看什么
8086 的中断向量表固定从物理地址 0 开始,每个中断占 4 个字节,前两字节是服务程序的偏移地址 IP,后两字节是段基址 CS。所以“中断类型号 n 对应的向量表首地址 = n × 4”这句话必须记牢,剩下的就是填哪个字节。
| 中断类型号 | 向量表首地址 | 存放内容 |
|---|---|---|
| 09H | 24H | 24H~25H 存 IP,26H~27H 存 CS |
| 20H | 80H | 80H~81H 存 IP,82H~83H 存 CS |
| 60H | 180H | 180H~181H 存 IP,182H~183H 存 CS |
8259A 的题目常问“IR3 对应的中断类型号是多少”。答案取决于 ICW2:ICW2 的高 5 位是类型号基址,低 3 位由芯片自动填入 IR 号。若 ICW2 = 40H,那 IR0 是 40H,IR3 就是 43H;写 ICW2 时把低 3 位写成 1 也不会报错,但读回来的类型号会偏移。程序流程类的题则盯住四件事:进入服务程序先保存现场、需要嵌套时再开中断、处理完向偶地址写 EOI、最后用 IRET 返回。写RET会让栈里的标志寄存器、CS、IP 错位,程序直接跑飞。
3. 用汇编与仿真把习题答案跑一遍
题目只要求“写出程序段”时,靠纸笔推判断即可;一旦题目要求波形图、时序图或“验证结果”,就必须让代码真的跑起来。跑之前先想清楚一件事:仿真的价值不在于复现硬件,而在于验证你对位域和顺序的理解是否自洽。顺序错了、地址错了,仿真里立刻就能看出来,比在实验箱上拔插线快得多。
3.1 环境选择:emu8086 与 MASM + DOSBox 各适合哪类题
| 环境 | 适合的题型 | 不方便的地方 |
|---|---|---|
| emu8086 | 端口读写、单步看寄存器、简单中断流程 | 外设靠虚拟端口模拟,看不到真实波形 |
| MASM/TASM + DOSBox | 完整汇编程序、循环与字符串、DEBUG 跟踪 | 端口访问受宿主系统限制,需要额外调试手段 |
| 电路仿真工具 | 8255/8253/ADC0809 的连线与时序、波形图题 | 要自己画图,元件参数得和题干对上 |
| 真实实验箱或开发板 | 数码管、矩阵键盘、ADC 采样的最终验证 | 排线跳线错一次,排查时间很长 |
选环境的标准很简单:题目里出现“画出波形”就上电路仿真,出现“写出程序段并说明执行结果”就用 emu8086 单步走一遍。真正做课设时,先用仿真把地址和控制字定下来,再搬到硬件上,能省掉大量试错。
3.2 8255 端口读写的最小可运行代码
假设题目给出的 8255 基址是 300H,A 口为 300H、B 口为 301H、C 口为 302H、控制口为 303H。要求 A 口方式 0 输出、B 口方式 0 输入,最小程序如下。
; 8255 基址 300H:A 口方式 0 输出,B 口方式 0 输入 CODE SEGMENT ASSUME CS:CODE START: MOV DX, 303H ; 控制口;端口号超过 FFH 必须用 DX 间接寻址 MOV AL, 83H ; D7=1 方式控制字,A 口输出、B 口输入、C 口高出低入 OUT DX, AL ; 写控制字,完成初始化 MOV DX, 300H ; A 口地址 MOV AL, 0FFH OUT DX, AL ; A 口 8 位全输出高电平 MOV DX, 301H ; B 口地址 IN AL, DX ; 读回 B 口状态 MOV BL, AL ; 暂存到 BL,便于单步观察 MOV AH, 4CH INT 21H CODE ENDS END START三个细节决定这段代码能不能跑通。第一,端口地址超过 255 时不能用IN AL, 300H这种直接寻址,必须先把地址送 DX,再用IN/OUT的 DX 寻址形式。第二,控制字只写一次就够,重复写会清掉芯片内部状态,程序里若在循环中反复写 83H,C 口的位操作效果会被覆盖。第三,初始化必须放在数据读写之前,先OUT数据再写控制字,输出锁存器里的值对不上。单步运行时重点看两个点:写控制字后立刻读一下控制口,能读回 83H 说明写成功了;读 B 口时若返回值恒为 0,先确认外部有没有给上拉或输入信号。
3.3 8253 计数初值的验证:先低后高不能乱
继续用 3.2 的地址风格,把 8253 基址定在 304H,则 T0 是 304H、T1 是 305H、T2 是 306H、控制口是 307H。题目要求 T0 工作在方式 3、二进制、初值 2000,程序如下。
; 8253 基址 304H:T0 方式 3,先低后高,二进制,初值 2000 MOV DX, 307H ; 控制口 MOV AL, 00110110B ; D7D6=00 选 T0;D5D4=11 先低后高;D3D2D1=011 方式 3;D0=0 二进制 OUT DX, AL MOV DX, 304H ; T0 数据口 MOV AX, 2000 ; 初值 = 2MHz / 1kHz OUT DX, AL ; 先写低 8 位 MOV AL, AH OUT DX, AL ; 再写高 8 位控制字 00110110B 就是十六进制的 36H,拆开逐段核对:D7D6=00 选中计数器 0,D5D4=11 表示读写的是一次完整 16 位值且先低后高,D3D2D1=011 对应方式 3(方波输出),D0=0 表示按二进制计数而不是 BCD。两个OUT的顺序不能交换,芯片内部有一个“高低字节选择触发器”,第一个字节被当作低 8 位,第二个字节被当作高 8 位,写反了初值会变成 2000 的高低位互换结果。
验证方法有两种。软的办法是在仿真里读回计数器当前值,看它是否在 2000 附近递减;硬的办法是把 T0 的输出接到示波器或逻辑分析仪,量周期是否等于 1ms。如果量出来是 9.6kHz 左右的频率,基本可以断定初值被截断成了 208,回头检查控制字的 D5D4 是不是误写成 01。
3.4 中断服务程序的骨架:EOI 忘写会怎样
假设 8259A 的偶地址是 20H、奇地址是 21H,且已按题目要求完成 ICW 初始化,中断服务程序的骨架大致如下。
ISR PROC FAR PUSH AX ; 现场保护:用到的寄存器都要压栈 PUSH DX STI ; 需要嵌套时开中断,不需要嵌套可省略 MOV DX, 20H MOV AL, 20H ; OCW2:普通 EOI,通知 8259A 本次中断结束 OUT DX, AL IN AL, 60H ; 读走外设数据,清掉中断请求源 POP DX ; 与 PUSH 顺序相反地恢复现场 POP AX IRET ; 中断返回必须用 IRET ISR ENDP20H 这个命令字是 OCW2 的普通 EOI,写向偶地址;如果写成 21H(奇地址),实际改的是中断屏蔽字 OCW1,结果是屏蔽掉某一路而不是结束中断。最典型的两个故障是:漏写 EOI 导致同级中断只响应一次,看起来像“中断死了”;用RET代替IRET导致返回后标志寄存器、CS、IP 的弹出顺序错位,程序跑飞。PUSH和POP必须严格配对,只PUSH AX不POP AX,返回时栈顶就不是正确的返回地址了。
4. 从习题到实物:地址译码、时序参数与五类典型故障排查
纸面答案能对上,不等于板子上能跑。习题里的地址是题目给死的,实物上要自己选;习题里的时序是理想化的,实物上受芯片参数约束。这一章说的是从“算对”到“跑通”之间那段最容易返工的路。
4.1 地址译码落地:三根线决定端口号,四根线决定重叠
在实验箱或自制板卡上给新芯片分配地址,要同时满足三个约束。第一是避开系统已占用的区间,常见端口不能碰:8259A 用 20H 和 21H,8253/8254 用 40H~43H,键盘控制器用 60H 和 64H,并口常用 378H,串口常用 3F8H。第二是落在译码器还能腾出来的地址区间里,74LS138 只有 8 个输出,用掉几个要提前算清楚。第三是把低两位留给芯片自己的 A1A0,基址要选 4 的整数倍。
选完基址还要判断会不会重叠。判断标准和 2.1 节一样:看有多少根地址线没接进译码器。接了 A15~A4 就是全译码,一个芯片只占 16 个连续地址;只接到 A9 就有一大片重复区间,别的芯片落进来时会同时响应,表现为“访问谁都能触发”。实物调试时的验证手段很土但有效:写一段循环,把候选地址逐个读一遍,看哪些地址返回同样的值,重复出现的间隔就是重叠周期。
4.2 时序参数:ADC0809 的转换时间决定了采样节拍
ADC0809 的时钟一般由 8253 的分频输出提供,这正好把 3.3 节的初值计算和采样率连了起来。常用时钟是 500kHz 左右,此时单次转换时间在 128μs 上下,启动转换、等 EOC、读数还有额外的软件开销。
f_clk = 500_000 # ADC0809 时钟频率,由 8253 分频得到 t_conv = 128e-6 # 单次转换时间,秒 t_overhead = 20e-6 # 启动、等 EOC、取数的软件开销估计 t_sample = t_conv + t_overhead print(f"单通道最高采样率约 {1 / t_sample:.0f} Hz") # 反过来:要求 10kHz 采样,节拍预算是多少 print(f"10kHz 的节拍预算 {1 / 10_000 * 1e6:.0f} us")f_clk是设计输入,题目里通常反着给——要求某个采样率,让你倒推 8253 的初值。t_conv取决于时钟频率,时钟取 640kHz 时转换时间约 100μs,采样率上限约 8.3kHz;t_overhead是工程估计值,包含启动转换、查询 EOC、读走结果的指令开销,不算进去会得到偏乐观的结论。算出来 10kHz 的节拍预算是 100μs,而单次转换就要 128μs,说明这个指标单靠一片 ADC0809 达不到,答案里应当写清“需降低采样率或改用转换更快的器件”,而不是硬凑一个初值。
4.3 电平与驱动:数码管段码表别手抄
数码管、发光二极管这类题错得最多的不是原理,是段码抄错或者位序对不上。把段码表写成脚本生成,比从答案页誊一遍可靠。
SEGS = "abcdefg" # 位序:a 占 bit0,g 占 bit6,dp 留 bit7 def seg_code(digit: str, common_cathode=True) -> int: table = { '0': 'abcdef', '1': 'bc', '2': 'abdeg', '3': 'abcdg', '4': 'bcfg', '5': 'acdfg', '6': 'acdefg', '7': 'abc', '8': 'abcdefg', '9': 'abcdfg', } v = 0 for ch in table.get(digit, ''): v |= 1 << SEGS.index(ch) return v if common_cathode else (~v) & 0x7F # 共阳低电平点亮,取反后保留 7 位 for d in "0123456789": print(d, hex(seg_code(d)), hex(seg_code(d, common_cathode=False)))SEGS定义了位序,也就是硬件把 a~g 各段接到数据口的哪一位,这一项必须按实际接线改,抄表之前先确认。common_cathode=True时输出高电平点亮,0 对应 0x3F、1 对应 0x06;共阳时取反,0 对应 0x40。& 0x7F是为了只保留七段,把 dp 位留空,若题目要求带小数点,再单独把小点位置 1 即可。驱动能力也要算:一段 LED 的工作电流乘以同时点亮的段数,超过端口输出能力就得加驱动芯片,直接把数码管挂在 8255 上是不稳妥的接法。
4.4 五类典型故障的对照排查表
| 现象 | 最可能的原因 | 验证方法 | 修正 |
|---|---|---|---|
| 写控制字后外设毫无反应 | 控制字写到数据口,或 D7=0 被当成 C 口位操作命令 | 读回控制口看是否为写入值 | 确认控制口地址 = 基址 + 3 |
| 输出频率是预期值的若干倍 | 8253 的 RL 位设成只写低 8 位,初值被截断 | 量周期反推初值 | 控制字 D5D4 改成 11,先低后高 |
| 中断只响应一次 | 服务程序漏写 EOI | 在 ISR 里下断点看是否再次进入 | 向偶地址写 20H |
| 中断返回后程序跑飞 | 用 RET 代替 IRET,或 PUSH/POP 不配对 | 单步观察栈指针与返回地址 | 改成 IRET,核对现场保护 |
| 访问某芯片时别的芯片也响应 | 部分译码,高位地址线未参与 | 穷举地址空间看命中间隔 | 增加译码线,或改用全译码 |
排查顺序建议固定下来:先看地址、再看控制字、最后看时序。地址错了后面全错,先排地址能省掉大量返工。表里的“验证方法”一列是关键,每一行都给出一个能在仿真或调试器里立刻执行的动作,避免靠猜。
5. 把习题 PDF 变成可复用的接口技术检查清单
题目刷完就忘,是因为答案存在 PDF 里,判断标准没留在脑子里。换个用法:把每道题抽成“题型标签 + 判据”,存在一份自己维护的清单里,下次遇到同类题直接调判据,不用重推。
5.1 按四类题型给题目打标签
拿到 PDF 先花一小时做分类,标签就用四类:地址译码、控制字、计数初值、中断向量。每道题旁边写一行判据,比如地址译码题写“参与译码的线 + 片选极性 + A1A0 接法”,控制字题写“D7 标志位 + 方式位 + 输入输出方向”。分类完成后会发现,重复题型很多,真正需要重新推的只有十几道。跨章节的题单独标出来,比如“用 8253 给 ADC0809 提供时钟”这类题同时考初值和时序,属于最容易在考试和调试里出问题的一类。
5.2 四个常数覆盖大半计算题
整本习题里反复用到的常数其实只有四个:16 位计数器最大值 65536,BCD 计数最大值 10000,中断向量表每项 4 字节,8259A 的 EOI 命令字 20H。把这些写在清单第一页,配合“8255 控制口 = 基址 + 3、8253 控制口 = 基址 + 3、8259A 偶地址写命令奇地址写屏蔽字”这三条地址偏移,绝大多数计算题就有了起点。
5.3 自测方式:先画位表格,再合成十六进制
自测时把答案页遮住,只读题干,在草稿纸上画 8 个格子填位,填完再合成十六进制,最后才翻答案。对不上时不改答案,回去查位定义——差异出现在 D7 还是 D5D4,直接指向你对哪一条判据理解偏了。每道题控制在三分钟内完成,超过就说明判据没背熟。把每次错的位号记在清单末尾,考前和上板前各看一遍,比重新翻一遍 PDF 快得多。画格子的习惯要保留到实物调试阶段:改控制字之前先在纸上填一遍位,再动手改代码,返工次数会明显下降。
本文还有配套的精品资源,点击获取