前言
本文是对《微机原理与接口技术》课程作业的完整总结,包含两部分内容:
程序设计专题:10 道 8086 汇编语言编程题,涵盖字符串输出、BCD 码转换、分支结构、移位运算、四则运算、补码、分段函数、数组搜索、十六进制输出、键盘输入等核心知识点。
课程设计大作业:基于 8086 最小系统 + 8255A 可编程并行接口芯片的灯光控制器设计,支持 6 种灯光模式、数码管显示、一键复位等扩展功能,使用 Proteus 进行电路仿真。
所有程序均在 DOSBox + MASM 5.0 环境下编译运行通过,电路仿真使用 Proteus 8.17。
仓库地址12367257321/Proteus-8086-LED: 8086的微机原理灯光控制器设计 能利用8086进行LED小灯亮灭控制; 能用8个以下按键/开关控制8个小灯的亮灭; 能实现对小灯单独和整体(组合)的控制; 绘制电路图,编写相应的控制程序; 其他扩展功能。
一、开发环境搭建
1.1 DOSBox + MASM 5.0
DOSBox 是运行 16 位 DOS 程序的模拟器,MASM 5.0 是微软经典的 8086 宏汇编编译器。
安装步骤:
下载并安装 DOSBox 0.74
创建工作目录,例如 D:\DosBox\MASM,将 MASM 相关文件(MASM.EXE、LINK.EXE、DEBUG.EXE)放入该目录
修改 DOSBox 配置文件(通常在 C:\Users\用户名\AppData\Local\DOSBox\dosbox-0.74.conf),在末尾添加:
ini
1
2
mount c D:\DosBox\MASM
c:
可选:修改显示参数让窗口更大
ini
1
2
windowresolution=1280x960
output=opengl
1.2 编译运行流程
asm
1MASM XXX.ASM; ; 汇编,生成 .OBJ 文件
LINK XXX.OBJ; ; 链接,生成 .EXE 文件
XXX.EXE ; 运行程序
2
3
部分简单程序(如纯输出程序)可以跳过 LINK 步骤,直接用 DEBUG 调试。
1.3 Proteus 8.17
Proteus 用于硬件电路仿真,支持 8086 系列 CPU 和常用外设芯片。在 Proteus 中搭建电路后,将汇编程序编译生成的 HEX 文件加载到 ROM 芯片中即可运行仿真。
二、程序设计专题(10 道编程题)
2.1 题目总览
序号 文件 题目 核心知识点
1 A.asm 输出姓名拼音 字符串定义(DB)、INT 21H 的 09H 功能
2 B.asm 单位 BCD 码转 ASCII BCD 码拆分、ASCII 码转换
3 C.asm 小写字母转大写 CMP + JA/JB 分支结构
4 D.asm 多位 BCD 码移位输出 SHR 移位、AND 掩码、BCD 拆分
5 E.asm 多位加减乘除 MUL/DIV 指令、子程序调用、进制转换输出
6 F.asm 双字负数补码 NOT 取反 + ADC 进位传递
7 G.asm 分段函数求 Y 三级分支(X<0 / X<10 / X>=10)
8 H.asm 数组寻目标数据 LOOP 循环 + CMP + JE 线性搜索
9 I.asm 多位十六进制输出 ROL 循环左移 + AND 掩码 + 条件转换
10 J.asm 键盘缓冲输入 INT 21H 的 0AH 功能(缓冲输入)
2.2 各题详解
第 1 题:输出姓名拼音(A.asm)
功能:在屏幕上显示字符串 wangyilin。
核心代码思路:
asm
1
2
3
4
5
6
7
8
9
10
11
12
13
DATA SEGMENT
MSG DB 'wangyilin', 0DH, 0AH, '$' ; 定义字符串,$ 结尾
DATA ENDS
CODE SEGMENT
MOV AX, DATA
MOV DS, AX
MOV DX, OFFSET MSG ; DX 指向字符串首地址
MOV AH, 09H ; INT 21H 的 09H 功能:输出字符串
INT 21H
MOV AH, 4CH ; 退出程序
INT 21H
CODE ENDS
要点:DS 寄存器需要先指向数据段;字符串必须以 $ 结尾。
第 2 题:单位 BCD 码转 ASCII(B.asm)
功能:将压缩 BCD 码 05H 转换为 ASCII 码 35H 并显示。
核心思路:BCD 码的每一位(0~9)加上 30H 即为对应的 ASCII 码。
asm
1
2
3
4
5
MOV AL, 05H ; BCD 码 05
ADD AL, 30H ; 转为 ASCII:35H → 字符 '5'
MOV DL, AL
MOV AH, 02H ; INT 21H 的 02H 功能:输出单字符
INT 21H
第 3 题:小写字母转大写(C.asm)
功能:输入小写字母 a,输出大写 A。
核心思路:利用 CMP + 条件跳转实现分支结构。小写字母减 20H 即为大写。
asm
1
2
3
4
5
6
7
8
9
10
11
MOV AH, 01H ; 读键盘输入
INT 21H
CMP AL, 'a' ; 比较是否为小写
JB NOT_LOWER ; 低于 'a' 则跳转
CMP AL, 'z' ; 比较是否超出小写范围
JA NOT_LOWER ; 高于 'z' 则跳转
SUB AL, 20H ; 小写转大写
NOT_LOWER:
MOV DL, AL
MOV AH, 02H ; 输出字符
INT 21H
第 4 题:多位 BCD 码移位输出(D.asm)
功能:将 0506H 拆分为各个 BCD 位并以十进制形式显示。
核心思路:通过 SHR 右移 4 位取高半字节,AND 0FH 取低半字节,分别加 30H 转 ASCII。
asm
1
2
3
4
5
6
7
8
9
10
11
12
MOV AX, 0506H
MOV BL, AH ; 取高字节 05H
MOV CL, 4
SHR BL, CL ; 右移 4 位 → 0
AND BL, 0FH ; 掩码取低 4 位
ADD BL, 30H ; 转 ASCII
MOV BH, AL ; 取低字节 06H
MOV CL, 4
SHR BH, CL ; 右移 4 位 → 0
AND BH, 0FH
ADD BH, 30H
踩坑记录:8086 中 SHR AL, 4 是非法指令(移位次数 > 1 时必须用 CL 寄存器),需要先 MOV CL, 4 再 SHR AL, CL。
第 5 题:多位加减乘除(E.asm)
功能:实现多位数的四则运算并输出结果。
核心思路:使用 ADD/SUB/MUL/DIV 指令进行运算,编写 PRINT_HEX 子程序将结果以十六进制或十进制形式输出。
asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
; 加法示例
MOV AX, 1234H
MOV BX, 5678H
ADD AX, BX ; AX = 68ACH
; 乘法示例(无符号)
MOV AL, 12 ; 被乘数
MOV BL, 5 ; 乘数
MUL BL ; AX = AL × BL = 60
; 除法示例(无符号)
MOV AX, 100 ; 被除数
MOV BL, 7 ; 除数
DIV BL ; AL = 商 = 14, AH = 余数 = 2
第 6 题:双字负数补码(F.asm)
功能:对 32 位双字数据求补码。
核心思路:补码 = 取反 + 1。对于双字数据,低 16 位取反加 1,高 16 位取反后加进位(ADC)。
asm
1
2
3
4
5
; 假设双字数据在 DX:AX 中(DX 高位,AX 低位)
NOT AX ; 低 16 位取反
NOT DX ; 高 16 位取反
ADD AX, 1 ; 低 16 位加 1
ADC DX, 0 ; 高 16 位加进位
要点:ADC(带进位加法)是关键,它把 ADD 产生的进位传递到高位。
第 7 题:分段函数求 Y(G.asm)
功能:根据 X 的值计算分段函数:
Plain Text
1
2
3
{ -1 X < 0
Y = { 2X+1 0 ≤ X < 10
{ X² X ≥ 10
核心思路:三级分支判断,使用 CMP + JL/JGE 实现。
asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CMP X, 0
JL NEGATIVE ; X < 0
CMP X, 10
JL MIDDLE ; 0 ≤ X < 10
; X ≥ 10 的情况
MOV AX, X
MUL AX ; AX = X²
JMP DONE
NEGATIVE:
MOV AX, -1
JMP DONE
MIDDLE:
MOV AX, X
MOV BL, 2
MUL BL ; AX = 2X
ADD AX, 1 ; AX = 2X + 1
DONE:
MOV Y, AX
第 8 题:数组寻目标数据(H.asm)
功能:在数组中查找指定数据,找到则显示其位置。
核心思路:LOOP 循环 + CMP 比较 + JE 相等跳转,实现线性搜索。
asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MOV SI, OFFSET ARRAY ; SI 指向数组首地址
MOV CX, COUNT ; CX = 数组长度
MOV AL, TARGET ; AL = 目标值
SEARCH:
CMP [SI], AL ; 比较当前元素
JE FOUND ; 相等则找到
INC SI ; 指向下一个元素
LOOP SEARCH ; CX-1,不为 0 则继续
; 未找到的处理
JMP NOT_FOUND
FOUND:
; SI 当前指向目标元素,计算偏移即位置
第 9 题:多位十六进制输出(I.asm)
功能:将 32 位数据以十六进制形式逐位输出。
核心思路:ROL 循环左移 4 位,每次取最低 4 位,判断是 0~9 还是 A~F,转为 ASCII 后输出。
asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MOV CX, 8 ; 32 位 = 8 个十六进制位
MOV BX, DATA32
PRINT_LOOP:
ROL BX, 4 ; 循环左移 4 位
MOV AL, BL
AND AL, 0FH ; 取最低 4 位
CMP AL, 10
JB IS_DIGIT ; 0~9
ADD AL, 'A' - 10 ; A~F
JMP OUTPUT
IS_DIGIT:
ADD AL, '0' ; 0~9
OUTPUT:
MOV DL, AL
MOV AH, 02H
INT 21H
LOOP PRINT_LOOP
第 10 题:键盘缓冲输入(J.asm)
功能:使用 INT 21H 的 0AH 功能接收键盘输入并回显。
核心思路:定义输入缓冲区(首字节为最大长度,次字节为实际长度,之后为字符存储区)。
asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
BUFFER DB 20 ; 最大输入长度
DB ? ; 实际输入长度(由 DOS 填充)
DB 20 DUP(?) ; 字符存储区
; 缓冲输入
MOV DX, OFFSET BUFFER
MOV AH, 0AH
INT 21H
; 回显
MOV CL, BUFFER+1 ; 取实际输入长度
MOV CH, 0
MOV SI, OFFSET BUFFER+2
DISP:
MOV DL, [SI]
MOV AH, 02H
INT 21H
INC SI
LOOP DISP
三、灯光控制器课程设计
3.1 设计目标
基于 8086 最小系统和 8255A 可编程并行接口芯片,设计一个多模式灯光控制器:
8 个按键控制 8 个 LED 灯
支持 6 种灯光模式
数码管实时显示当前模式编号
支持一键复位
3.2 硬件电路设计
8086 最小系统
芯片 作用
8086 CPU 主处理器(最小模式)
8284A 时钟发生器,提供 8MHz 主频
74LS373 地址锁存器,锁存低 16 位地址
74LS138 3-8 译码器,产生片选信号
74LS245 数据总线缓冲器
2764 8KB EPROM,存储程序
8255A 接口配置
端口 地址 方向 连接
PA 口 2000H 输出 8 个 LED(经 220Ω 限流电阻)
PB 口 2002H 输入 8 个按键(上拉电阻 + 接地)
PC 口 2004H 输出 共阴数码管 a~g 段
控制口 2006H — 写入方式控制字
方式控制字:82H = 1000 0010B
D7=1:方式选择有效
D6D5=00:PA 口方式 0
D4=0:PA 口输出
D3=0:PC 高 4 位输出
D2=0:PB 口方式 0
D1=0:PB 口输入
D0=0:PC 低 4 位输出
3.3 软件设计
主程序流程
Plain Text
1
2
3
4
5
6
7
8
9
10
11
12
13
初始化 8255A(写入控制字 82H)
↓
循环读取 PB 口按键状态
↓
检测按键变化(边沿检测消抖)
↓
根据按键编号切换到对应模式
↓
执行对应模式的处理程序
↓
更新数码管显示
↓
返回继续检测
6 种灯光模式
模式 按键 实现方式
0 - 正常模式 PB0 按键与 LED 一一对应,按哪个亮哪个
1 - 全亮模式 PB1 PA 口输出 00H(低电平点亮)
2 - 全灭模式 PB2 PA 口输出 FFH
3 - 流水灯 PB3 循环左移,每次延时切换一位
4 - 交替闪烁 PB4 奇偶位交替翻转,55H / AAH 切换
5 - 呼吸灯 PB5 软件 PWM:逐渐改变亮灭时间比
数码管显示
PC0~PC6 连接共阴数码管的 a~g 段,通过查表法获取段码:
asm
1
2
SEG_TABLE DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H ; 0~7
DB 7FH, 6FH, 77H, 7CH, 39H, 5EH, 79H, 71H ; 8~F
显示时从表中取出对应模式编号的段码,输出到 PC 口即可。
一键复位
PB6 + PB7 同时按下时触发复位,系统回到模式 0,LED 全部熄灭,数码管显示 0。
asm
1
2
3
4
5
6
; 检测组合键
IN AL, 2002H ; 读 PB 口
AND AL, 0C0H ; 取 PB6、PB7
CMP AL, 00H ; 两个都按下(低电平有效)
JNE NOT_RESET
CALL RESET_ALL ; 调用复位子程序
3.4 仿真结果
在 Proteus 中完成电路搭建后,加载程序进行仿真:
正常模式:按下按键,对应 LED 亮灭切换,数码管显示 0
全亮/全灭:一键控制所有 LED
流水灯:LED 依次循环点亮,效果流畅
交替闪烁:奇偶位 LED 交替亮灭
呼吸灯:通过软件 PWM 模拟亮度渐变
数码管:始终显示当前模式编号
一键复位:同时按 PB6+PB7,系统恢复初始状态
四、踩坑记录
4.1 SHR AL, 4 报错
8086 指令集中,移位指令的移位次数如果大于 1,不能直接写立即数,必须通过 CL 寄存器:
asm
1
2
3
4
5
6
; ❌ 错误写法(8086 不支持)
SHR AL, 4
; ✅ 正确写法
MOV CL, 4
SHR AL, CL
4.2 DS 寄存器未初始化
很多初学者(包括我)会忘记将数据段地址装入 DS,导致程序运行异常:
asm
1
2
MOV AX, DATA_SEG
MOV DS, AX ; 这一步不能省!
4.3 DOSBox 窗口太小
修改配置文件中的 windowresolution 和 output 参数:
ini
1
2
windowresolution=1280x960
output=opengl
4.4 Proteus 中 8086 不运行
常见原因:
ALE 信号未正确连接(8284A → 74LS373)
READY 引脚未接高电平(CPU 会一直等待)
ROM 的 EA 引脚未接高电平(不会从外部 ROM 取指)
中断向量表未正确配置
五、总结
通过本次课程作业,我系统掌握了以下内容:
8086 汇编语言编程:从最简单的字符串输出到复杂的多分支、循环、子程序调用,逐步建立了对汇编语言的理解。
DOS 中断机制:INT 21H 是 DOS 环境下最常用的中断,01H/02H/09H/0AH/4CH 这几个功能号需要牢记。
数据表示与转换:BCD 码、ASCII 码、补码之间的转换是汇编编程的基本功。
8255A 可编程接口芯片:掌握了方式 0 下的输入输出配置,理解了端口地址译码的原理。
Proteus 电路仿真:学会了搭建 8086 最小系统、连接外设芯片、加载程序进行仿真调试。
软硬件协同设计:灯光控制器项目让我体会到软件程序和硬件电路的配合关系——端口地址、数据流向、时序配合都需要精确设计。
附录:完整代码
所有源代码已上传至 GitHub 仓库,欢迎 Star 和 Fork。
如有问题欢迎在评论区交流,觉得有用的话点个赞吧!