简介:《TDX-PITE-80X86微机接口应用技术实验教程》面向学习80X86微机原理与接口技术的高校学生及实验指导教师,可作为课程实验、硬件联调与接口芯片应用的实践参考。资源包共1个PDF文件,约909KB,内容围绕西安唐都科教仪器实验平台展开,先说明FPGA板的50MHz全局时钟、JTAG下载口及扩展插座引脚分配,再覆盖键盘扫描及显示、电子发声、点阵LED显示、双机通讯、步进电机、温度闭环控制和直流电机闭环调速等实验项目。文中结合8259、8255、8254、8251、8237等接口单元,给出实验目的、硬件连接与调试思路,便于读者理解微机与外部设备的交互过程,并可按实验模块查漏补缺。目前已有667人学习,适合需要对照实验平台完成课程实践和接口技术训练的学习者。
1. 从一块引脚表开始:这套 80X86 微机接口实验方案要解决什么
课设选题报上去的时候,很多人以为 80X86 微机接口这门课的实验就是照接线图插线、把例程编译一遍看现象。真正卡住进度的是另外一些现象:实验箱上电后数码管只亮第一位、串口发出去十个字节对方只收到九个、点阵滚屏时上半屏亮下半屏黑。这套 80X86 微机接口应用技术实验教程的价值不在八个实验的名字,而在于它把 FPGA 单元、五块接口芯片和外围电路之间的引脚与地址关系摆到同一张表上,让第一次做微机接口课设或毕设前期验证的人有据可查。下文按硬件底座、人机交互、外设驱动与联机、避坑排查、验收答辩的顺序,把这套课程资源拆成一份能照着落地的方案。
2. 硬件底座与地址映射:FPGA 单元资源和五块接口芯片怎么接
动手之前先把板子上的“谁连谁”弄清楚,比急着敲代码省事得多。这套实验平台把 8255、8254、8251、8259、8237 五块接口芯片的逻辑烧进了一片 FPGA,物理上只剩一块板子加一堆排针。这种设计对课设很友好:接线错一根,现象立刻不对,不用怀疑是分立器件坏了。但代价是引脚关系被压进了一张表里,不先读懂它,后面每个实验都得靠试。
2.1 50MHz 时钟、JTAG 口与公用总线
FPGA 板上有一个 50MHz 有源晶振,接在芯片的 PIN_25 脚,也就是 CLK3,作为全局时钟信号使用。这个时钟和 8254 的计数时钟不是一回事:前者喂给 FPGA 内部逻辑,后者由实验平台单独提供,做发声实验时通常取 1MHz 或由外部时钟分频得到。混淆这两个时钟是新手第一个翻车点,算出来的计数初值会莫名其妙差几十倍。
“JTAG 下载”口位于 8251 单元和 8237 单元之间,用来调试下载。做课设的阶段一般不需要重新烧写 FPGA 逻辑,出厂时配好的接口芯片逻辑已经够用;但如果实验室要改片选地址分配,就得从这个口进去改。
板上的 A15~A0 地址线、D7~D0 数据线、IOR#、IOW#、RST# 是所有接口芯片公用的。也就是说,五块芯片挂在同一组总线上,靠片选信号区分谁在响应。理解这一点,后面查“为什么读出来是 0xFF”就有方向了:要么片选没选中,要么选错了芯片。
2.2 引脚分配表怎么读
原始教程给了一张很长的对应关系表,实际做实验只需要会读三类行:数据线、地址线、片选线。数据线 D7~D0 依次对应 PIN_119、121、125、127、129、133、136、138;地址线 A15~A0 对应 PIN_83、85、87、141、143、99、101、105、111、113、115、120、124、126、128、132。这些编号不用背,用到哪根查哪根。
| 功能类别 | 信号 | FPGA 引脚 | 说明 |
|---|---|---|---|
| 数据总线 | D7~D0 | 119、121、125、127、129、133、136、138 | 五块芯片公用 |
| 地址总线 | A15~A8 | 83、85、87、141、143、99、101、105 | 高位参与片选译码 |
| 地址总线 | A7~A0 | 111、113、115、120、124、126、128、132 | 低位进芯片内部寄存器 |
| 片选 | 8255_cs | 23 | 低电平有效 |
| 片选 | 8254_cs | 30 | 低电平有效 |
| 片选 | 8251_cs | 24 | 低电平有效 |
| 片选 | 8259_cs | 28 | 低电平有效 |
| 片选 | 8237_cs | 86 | 低电平有效 |
| 总线控制 | IOW# / IOR# | 73 / 71 | 读写选通 |
| 复位与时钟 | RST# / sys_clk | 84 / 25 | 系统复位、50MHz 输入 |
表格只列了做课设最常查的几组,8255 的 PA/PB/PC 三口分散在 PIN_1 到 PIN_52 之间,接线时按单元面板丝印对号即可。读这张表的正确姿势是:先确定你要用哪个芯片的哪个口,再反查引脚号,别反过来。反过来查很容易在密集排针上数错一格,接完线现象全乱。
2.3 片选与端口地址:五块芯片不打架的前提
五块芯片共用数据总线和地址总线,谁被选中完全取决于片选信号。实验平台上每个单元都有一个片选输入端,接不同的 IOY 输出就得到不同的基址。以 8255 为例,它内部有 A、B、C 三个数据口加一个控制口,正好占四个连续端口地址,用 A1、A0 两根线区分。
/* 端口基址取决于片选接到哪个 IOY 输出,下面的 0x60 只是示例 * 改接线后必须同步改这四个宏,否则读写全落在别的芯片上 */ #define P8255_A 0x60 /* A 口:键盘列扫描输出 */ #define P8255_B 0x61 /* B 口:数码管段码输出 */ #define P8255_C 0x62 /* C 口:低 4 位读行,高 4 位备用 */ #define P8255_CTL 0x63 /* 控制口:写方式字 */ /* 控制字 0x81:A 组方式 0、PA 输出、PC 高 4 位输出; * B 组方式 0、PB 输出、PC 低 4 位输入 */ outportb(P8255_CTL, 0x81);控制字 0x81 拆开看是 1000 0001:D7 为 1 表示方式设置标志,D6D5 选 A 组方式 0,D4 置 0 让 PA 输出,D3 置 0 让 PC 高四位输出,D2 选 B 组方式 0,D1 置 0 让 PB 输出,D0 置 1 让 PC 低四位输入。这个方向配置正好对应键盘扫描:PA 往外打列扫描信号,PC 低四位往里读行状态,PB 往外送段码。
提示:写代码前先用调试工具对每个基址做一次读操作,读回 0xFF 通常说明片选没接上或者地址算错;读回稳定值才说明芯片真的挂上总线了。
2.4 上电自检的三步顺序
我一般让学生按固定顺序自检,别一上来就跑完整程序。第一步量时钟,用示波器看 PIN_25 有没有 50MHz 方波,没有就查晶振供电。第二步测复位,按一下复位键看 RST# 引脚有没有低电平脉冲,没有就查按键和上拉。第三步读片选,对每个芯片基址读一次,把结果记下来当基线。
这三步花不了五分钟,但能把“程序写错”和“硬件没通”两类问题分开。少了这一步,后面调键盘扫描时你会在代码里找半天,最后发现是排线插反了。
3. 人机交互链路:8255 键盘扫描、数码管动态刷新与 8254 方波发声
键盘、数码管、蜂鸣器这三样东西凑在一起,是微机接口课设里最典型的输入输出闭环。教程把它们拆成两个实验:键盘扫描及显示设计、电子发声设计。实际做的时候建议连着做,因为它们共用 8255 和 8254 两个单元,接线一次到位,能省一轮插拔。
3.1 4×4 键盘的行列扫描与键值编码
键盘是 4 行 4 列的矩阵结构,16 个按键编成 0~F 十六个键值。扫描逻辑很朴素:PA 口依次输出一列低电平,其余列为高,然后读 PC 口低四位的行状态;哪一行为低,就说明那一行这一列的交叉点被按下。
去抖不能省。机械按键按下瞬间会有几毫秒的抖动,直接采信会读到连续多个键值。通常的做法是读到有效行后延时 10~20ms 再读一次,两次一致才认。教程例程里用的是软件延时循环,代码简单但占用 CPU;如果想让主循环还能干别的,可以改成定时器节拍采样。
键值编码用查表最省事:把 4×4 的键值写成二维数组,行号乘 4 加列号就是键值 0~F。这样改键位定义只动数组,不动扫描逻辑。
3.2 数码管段码与四位循环显示
实验要求是:按下某个键,键值显示在一个数码管上;再按下一个键,新键值显示到下一个数码管;四个数码管滚动显示最近四次按键。这是一个典型的先进先出缓冲,用长度为 4 的数组加一个写指针就能实现。
段码表按共阴数码管给,a 段对应 bit0,dp 对应 bit7:
/* 共阴段码 0~F,若实验箱用共阳数码管,整体按位取反即可 */ static const unsigned char SEG[16] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 };动态刷新的关键是“消隐”和“节拍”。四个数码管共用一组段码线,靠位选线轮流点亮。切换位选之前先把段码清零,否则上一位的残影会串到下一位上,看起来就是“数码管有鬼影”。每位点亮时间给 1ms 左右,四位轮一遍 4ms,刷新率 250Hz,肉眼完全看不出闪烁。
3.3 8254 方式 3:计数初值与音符时间表
发声实验的原理一句话能说清:把一个音符对应频率的方波送到扬声器上,就发出这个音;把一串音符的方波按顺序送出去,就是一段曲子。8254 的方式 3 是方波发生器,往计数器里写一个初值,OUT 端就输出对应频率的方波。
计数初值等于输入时钟除以输出频率。输入取 1MHz、要 800Hz,初值就是 1000000÷800=1250,也就是 0x04E2。音符频率表教程里给了完整的一张,A4 是 440Hz,C4 是 262Hz,按同一公式换算即可。
; 8254 计数器 0,方式 3,输入 1MHz,输出 800Hz ; 控制字 36H = 计数器0 + 先低后高 + 方式3 + 二进制计数 MOV AL, 36H OUT 43H, AL ; 43H 为 8254 控制口(按实际片选调整) MOV AX, 04E2H ; 1250 = 1000000 / 800 OUT 40H, AL ; 先写低字节 MOV AL, AH OUT 40H, AL ; 再写高字节方式字 0x36 的拆法:D7D6 为 00 选中计数器 0,D5D4 为 11 表示先读/写低字节再高字节,D3D2D1 为 011 选中方式 3,D0 为 0 表示二进制计数。这里最容易错的是读写顺序,方式字写了“先低后高”却先送高字节,输出频率会差 256 倍,听起来像蚊子叫或者根本听不见。
音符时长靠软件延时控制。教程给了一个单位延时的子程序,主程序把“这个音符要奏几个单位时间”送进 DL 再调用它。CPU 主频不同,单位延时长度会漂,同一份时间表在不同机器上节奏会变,所以调试时先听一小节,节奏明显偏快就把单位延时循环次数加大。这是玄学部分,只能靠耳朵校准。
3.4 参考实现:一次扫描同时完成读键与刷新
把读键和显示放进同一个主循环,是最省事也最稳的写法。下面这段是骨架,端口宏沿用第 2 章的定义:
unsigned char fifo[4] = {0x10, 0x10, 0x10, 0x10}; /* 0x10 表示该位空 */ unsigned char wp = 0; void refresh_once(void) { unsigned char i; for (i = 0; i < 4; i++) { outportb(P8255_B, 0x00); /* 先消隐 */ outportb(P8255_C, ~(1 << (i + 4))); /* 位选,高 4 位输出 */ outportb(P8255_B, fifo[i] == 0x10 ? 0x00 : SEG[fifo[i]]); delay_ms(1); /* 每位点亮 1ms */ } } void main(void) { unsigned char k; outportb(P8255_CTL, 0x81); /* 初始化方向 */ while (1) { k = key_scan(); /* 返回 0~15,无键返回 0xFF */ if (k != 0xFF) { fifo[wp] = k; /* 写指针环形前进 */ wp = (wp + 1) & 0x03; } refresh_once(); /* 每轮都刷新,保证不闪 */ } }这段代码有两个设计取舍值得说明。一是刷新放在主循环里而不是中断里,因为课设规模小,扫描一次几十微秒,完全来得及;二是用 0x10 当“空位”标记,避免空位显示成 0 和真实键值 0 混淆。如果实验箱的位选是低电平有效,~(1 << (i + 4))这句要改成高四位单独置位,别直接照抄。
key_scan()里注意释放检测:按键松开前不要重复入队,否则按一次会写进去四五个相同的键值。简单做法是记录上一次的键值,相同就跳过。
4. 外设驱动与联机:点阵 LED、8251 双机通讯、步进电机与闭环调速
这一组实验的共同点是“驱动 + 时序”,代码写对不难,难在时序参数和接线方向。点阵看扫描节拍,串口看波特率因子,电机看脉冲间隔,闭环看采样周期。任何一个参数错一个数量级,现象都是“完全不动”而不是“差一点”,所以调试时要养成先量波形再看代码的习惯。
4.1 16×16 点阵的行列驱动与字模提取
实验平台的 16×16 点阵由四块 8×8 点阵拼成,行信号由带 3-8 译码的行驱动芯片控制,列信号由带移位寄存器和锁存功能的恒流驱动芯片控制。点亮的条件是行给“1”、列给“0”,也就是行选通、列拉低。
扫描流程固定:取一行字模的两个字节,串行移入列驱动芯片,锁存输出,打开对应行,延时一小段,关行,换下一行。16 行轮一遍的周期要控制在 16ms 以内,否则肉眼能看到滚动条纹。单行点亮时间给 0.5~1ms 比较合适,太短亮度不够,太长会有拖影。
字模提取是最容易被忽略的一步。教程给的取模规则是横向取模:每 8 个连续点构成一个字节,最左边的点是最低位 bit0,最右边是 bit7;16×16 汉字每行 2 字节、共 16 行、合计 32 字节;四块点阵的取字顺序是左上、右上、左下、右下。这个顺序和显示时的行列扫描顺序必须严格对应,错了就会出现“字是正的但左右镜像”或者“上下颠倒”。
用取模软件生成字模时,输出格式选 C 语言数组或汇编数据段都行,关键是设置里的取模方式和字节位序要和程序里的移位顺序对上。生成完先在纸上画一遍第一行两个字节的 16 个 bit,和想要的第一行像素逐位核对,比在板子上试快得多。
4.2 8251 双机通讯:初始化顺序与收发握手
双机通讯实验需要两台实验装置,一台作发送机,一台作接收机。发送机把内存 3000H~3009H 十个单元的数据发出去,接收机收到后直接送屏幕显示。硬件上 8251 的时钟由 8254 提供,1.8432MHz 晶振分频后得到。
8251 的初始化有严格顺序,写错一步后面全废:先往控制口连写三个 00H 做软件复位,再写方式字,最后写命令字。
; 8251 异步方式:9600bps、8 数据位、无校验、1 停止位 ; 8254 输出 153600Hz 作为 8251 的 CLK,初值 = 1843200/153600 = 12 MOV DX, 8251_CTL XOR AL, AL OUT DX, AL ; 第 1 个 00H CALL SHORT_DELAY OUT DX, AL ; 第 2 个 00H CALL SHORT_DELAY OUT DX, AL ; 第 3 个 00H,完成软件复位 MOV AL, 4EH ; 方式字:波特率因子 16 + 8 位数据 + 无校验 + 1 停止位 OUT DX, AL MOV AL, 37H ; 命令字:允许收发 + 清错误标志 + DTR/RTS 有效 OUT DX, AL方式字 0x4E 拆开是 0100 1110:D1D0 为 10 表示波特率因子 16,D3D2 为 11 表示 8 位数据,D4 为 0 禁止校验,D5 为 0 表示偶校验(校验关掉后无效),D7D6 为 01 表示 1 个停止位。命令字 0x37 是 0011 0111:D0 允许发送、D1 置 DTR、D2 允许接收、D4 清错误标志、D5 置 RTS。
收发握手靠状态字。读状态口,D0 为 1 表示发送缓冲空,可以写数据;D1 为 1 表示收到一个字节,可以读数据。发送端不能连着往数据口写,必须等 D0 置位;接收端不能盲读,必须等 D1 置位。这两条是串口实验里最常见的丢字节原因。
两台机器的 TXD 和 RXD 要交叉接,GND 必须共地。少了共地这一根线,两边电平没有共同参考,收到的全是乱码,很多人会误以为是波特率算错,在代码里折腾半天。
4.3 步进电机脉冲分配
步进电机的控制本质是按顺序给四相绕组通电。单四拍的通电顺序是 0x01、0x02、0x04、0x08 循环,双四拍是 0x03、0x06、0x0C、0x09 循环,双四拍力矩更大、运行更平稳。
/* 双四拍脉冲分配表,输出到 8255 的某一口驱动电机 */ static const unsigned char STEP[4] = {0x03, 0x06, 0x0C, 0x09}; void step_run(int steps, int dir) { static unsigned char idx = 0; int i; for (i = 0; i < steps; i++) { idx = (idx + (dir > 0 ? 1 : 3)) & 0x03; /* 模 4 前进或后退 */ outportb(P8255_A, STEP[idx]); delay_ms(2); /* 脉冲间隔决定转速 */ } }脉冲间隔不能太小,太小电机来不及响应会丢步,现象是“转着转着位置偏了”;也不能太大,太大就是慢动作。整步模式下常见步距角是 1.8 度,转一圈 200 步,按 2ms 间隔算一圈 0.4 秒,比较接近实验室常用值。改间隔前先算一遍所需脉冲数,别让电机撞到限位。
4.4 温度与转速闭环的控制骨架
温度闭环和直流电机调速这两个实验属于同一类:采集一个物理量,和设定值比较,用偏差去调整执行机构。温度用的是加热元件加温度传感器,电机用的是 PWM 或调压加转速反馈。
控制骨架通常是增量式 PI:每个采样周期算一次偏差,输出量在上一次的基础上加上 Kp 乘以偏差变化量、加上 Ki 乘以当前偏差。比例项管响应快慢,积分项管稳态误差。整定的顺序是先只加 P,让系统有明显响应但允许有静差;再加 I,把静差压下去;如果超调太大再考虑加 D。
采样周期比参数更重要。周期太短,噪声被放大,输出抖;周期太长,控制滞后,容易振荡。温度这类热惯性大的对象,采样周期给 200ms~1s 都正常;电机转速采样可以快一些,10~50ms。这个值和硬件无关,取决于被控对象的响应速度,照抄别人的参数大概率不稳。
5. 避坑排查:五个最容易在验收现场翻车的点
带过几轮课设之后,出问题的地方高度集中。下面五条按“现象—原因—解决”写,基本覆盖验收现场八成的翻车情况。
现象一:数码管只亮第一位,或者亮度明显不均。原因通常是刷新节拍太慢或者没做消隐。位选切过去之后段码还留着上一位的值,残影串位;或者每位点亮时间给到 5ms 以上,四位轮一遍超过 20ms,肉眼能看出闪。 解决办法是把每位点亮时间压到 1ms,切换位选前先往段码口写 0x00 消隐,刷新函数放在主循环里每轮都调用,不要只在按键时才刷。
现象二:键盘读出来永远是 0x0F 或者全是 0x00。先查控制字。PC 口低四位如果被写成输出,读回来的是你写出去的值,不是按键状态。再查行列方向,PA 打列、PC 读行,接反了扫描不出任何键。最后查上拉,行线没有上拉电阻时悬空电平不稳,读出来随机。 解决办法是先用万用表量按下按键时行线电平有没有被拉低,能拉低说明硬件没问题,问题在控制字;再把控制字 0x81 的 D0 位确认一遍,这一位是 PC 低四位方向,置 1 才是输入。
现象三:8254 接上扬声器只有“咔”一声,没有持续音。三种可能:计数初值算错数量级、方式字写错、GATE 没接高电平。初值算错最常见的是把 1MHz 当成 50MHz 用,算出来的初值大 50 倍,超出 16 位范围被截断。 解决办法是先按 1MHz 输入重算一遍,确认初值落在 1~65535 之间;再检查方式字是不是 0x36,读写顺序是不是先低后高;最后确认 GATE 引脚接的是高电平,方式 3 下 GATE 为低会停止计数。
现象四:8251 收不到数据,或者收到的是乱码。未做软件复位是头号原因。8251 上电后状态不确定,必须先连写三个 00H 再写方式字,跳过这一步后面怎么写都不生效。其次是波特率因子不匹配,两边一个用 16 一个用 64,收出来就是乱码。第三是 TXD/RXD 没交叉、GND 没共地。 解决办法是按“复位—方式字—命令字”的顺序逐条核对,用示波器量 TXD 引脚有没有波形,有波形再查接收端波特率。共地这根线单独用一根短线接,别指望通过电源地间接连通。
现象五:点阵显示花屏、拖影,或者字是镜像的。拖影多半是行扫描时间太长或者锁存时序不对,一行的余晖还没消下一行就来了。镜像或上下颠倒则是取模顺序和扫描顺序没对上,取模按左上→右上→左下→右下,程序里也得按这个顺序送四块点阵的数据。 解决办法是先把单行扫描时间压到 1ms 以内,在换行前把列数据全部清零;再用一个只有一横的测试字模验证方向,横线显示在正确的行上,说明行列映射是对的,剩下的就是字模数据本身的问题。
6. 验收与答辩:把八个实验串成一条可演示的主线
验收现场最忌讳的是“一个实验一个程序、现场挨个编译”。评审老师时间有限,看到你在那儿等编译,印象分先掉一截。我的建议是提前准备一条演示主线:上电自检 → 键盘按键 → 数码管回显 → 蜂鸣器响应 → 点阵滚屏 → 双机通讯 → 电机转动。这条线把八个实验串成一个有反馈的系统,讲的时候不用切程序,一气呵成。
演示脚本按下面的判据准备,每项都要能当场复现:
| 演示环节 | 通过判据 | 大概率被追问的点 |
|---|---|---|
| 上电自检 | 时钟、复位、片选三项读数正常 | 片选译码用了哪几根地址线 |
| 键盘与显示 | 连按四个不同键,四位依次滚动更新 | 去抖怎么做的,为什么不用中断 |
| 电子发声 | 播放一段完整旋律,音高无明显偏差 | 计数初值公式,时钟源是多少 |
| 点阵显示 | 字符串完整滚过一遍,无拖影无镜像 | 取模顺序,单行点亮时间 |
| 双机通讯 | 十个字节全部到达且内容一致 | 8251 初始化顺序,波特率怎么算 |
| 步进电机 | 正反转各转若干步,位置可复现 | 脉冲分配方式,脉冲间隔取值依据 |
| 闭环调速 | 设定值改变后输出跟随且稳定 | 采样周期,P 和 I 的作用 |
答辩陈述控制在五分钟内,顺序按“需求—方案—关键实现—验证结果”走。先说这套系统要解决什么(键盘输入如何被采集并显示、两台机器如何交换数据),再说硬件上怎么搭(FPGA 单元资源、片选分配),然后挑一个最有把握的模块讲实现细节,最后给验证数据。别贪多,把一个模块讲透,比八个模块各说一句强。
被问到不会的地方,直接说“这个参数是试出来的,具体机理我还没验证”,比硬编一个理由安全。老师更在意你知不知道自己的方案边界在哪。
有个教训我记了很久:第一次带课设验收,学生演示到点阵那一项,滚屏滚到一半卡住了,现场重启又正常,下来查了半天发现是主循环里刷新函数被一个长延时阻塞了。从那以后我每次让学生交方案,都强制走一遍“连续演示三遍”的流程,第三遍还能稳定跑完,才算过关。硬件实验的稳定性不是调出来的,是重复出来的。希望这套拆解能帮到你,把你手上那份实验教程真正跑成一份能交得出去的方案。
本文还有配套的精品资源,点击获取