8254+8255车辆测速实验:定时计数、并行接口与数码管显示

简介:这份微机原理与接口技术实验报告面向电子信息、通信与物联网相关专业学生,以智慧交通中的车辆测速为题,把课堂上的CPU、内存与I/O接口原理落到一个可运行的小系统上。文档完整梳理实验目的、设备环境、设计指标、硬件电路图、程序流程图、方案讨论、结果分析与分工记录,核心思路是在固定距离下把测速转化为测时,借助8254定时/计数与8255显示接口完成数据采集、速度计算,并在DOS屏幕与实验箱LED数码管上同步显示,读者可据此理解传感器选型、中断与定时器配置、抗干扰设计和误差分析等环节。资源包共1个docx文件,约769KB,为排版完整的实验报告正文,含目录与章节结构,便于直接参照撰写或复现实验。该资源已有646人学习下载,适合课程实验参考、报告模板借鉴与接口技术复习使用。

1. 项目定位:一套用 8254 和 8255 拼出来的车辆测速实验

把微机原理与接口技术课上的智慧交通车辆测速实验拆开看,它并不是一份只用来交作业的实验报告:8254 把 1MHz 时钟分频成 1Hz 计时脉冲,8255 把时间送到两位数码管,DOS 调用再把同一份读数打到屏幕上。放到物联网 IoT 的语境里,这是一条最朴素的感知—计时—显示链路,适合刚学完定时/计数和并行接口、想找一个能上电跑通的小系统的开发者。它不依赖复杂框架,难点全在接线、控制字和读数时序上,拿来练“软硬对账”很合适。

2. 系统架构与硬件链路:从 1MHz 时钟到 1Hz 计时脉冲怎么落

2.1 实验报告里的三层结构:信号链、控制链、显示链

这份实验报告的组织方式很典型:前面写实验目的、设备与环境、设计指标和硬件电路图,中间放程序流程图与方案比较,后面用实验效果和结果分析收口。真正要复现时,别按报告章节顺序从头读到尾,先把系统拆成信号链、控制链、显示链三层,排查会快很多。信号链负责把实验箱上的 1MHz 时钟逐级分频成 1Hz 计时脉冲;控制链负责用拨码开关控制 GATE2,决定什么时候开始计数、什么时候停止;显示链负责把计数器里的时间值同时送到两位数码管和 DOS 屏幕。三层里任何一层断了,现象都不一样,先定位层,再定位线。

报告正文里用拨码开关模拟车辆到位信号,摘要里提到的车辆模型和传感器属于课程场景描述。复现时先按拨码开关把链路跑通,再考虑换光电或磁感应传感器,顺序反过来容易翻车。因为传感器输出电平、抖动和触发脉宽都要额外处理,而拨码开关至少能让你先确认 8254 的分频和 8255 的显示是通的。定距离测速的核心思路没变:距离固定,测到车辆通过的时间,再用距离除以时间换速度。实验报告把重点放在“测时间”,速度换算是二次开发要补的那一步。

层次主要器件/接口职责先验证什么
信号链8254 通道 0、1、21MHz→1kHz→1Hz,通道 2 计时间OUT1 是否有 1Hz
控制链拨码开关、GATE2、8255 PC0/PC7控制计数启停、读开关状态GATE2 电平是否随开关变化
显示链8255 PA/PB、两位数码管、DOS段选、位选、屏幕打印一位数码管能否固定亮一个数字

这张表建议你抄到实验记录本上。调的时候每完成一行就在后面打勾,比在代码里乱加打印语句有效。尤其是 8254 的 OUT1,它是整条链路的分水岭:OUT1 没有 1Hz,后面读计数、拆位、显示全是空谈;OUT1 对了,再查 8255 和数码管,问题范围会小很多。

2.2 端口地址和接线表:先把 280H/288H 这组地址钉死

实验报告里的端口地址是这组:8254 的计数器 0/1/2 分别是 280H、281H、282H,控制寄存器是 283H;8255 的 A/B/C 口分别是 288H、289H、28AH,控制寄存器是 28BH。这个地址不是随便写的,它来自实验箱的片选译码,Y0 选 8254、Y1 选 8255。你换一块板子,地址可能整体平移,但“先确认片选、再确认端口”的顺序不变。血泪经验是:代码里地址写错时,OUT 指令不会报错,只是写到了别的地方,现象看起来像芯片坏了,其实只是 CS 接错或译码没使能。

芯片/端口地址用途备注
8254 计数器 0280H1MHz 分频到 1kHz方式 3,初值 1000
8254 计数器 1281H1kHz 分频到 1Hz方式 3,初值 1000
8254 计数器 2282H对 1Hz 脉冲计数方式 2,GATE2 控制
8254 控制寄存器283H写控制字、发锁存命令36H/76H/B4H/80H
8255 A 口288H数码管段选输出段码
8255 B 口289H数码管位选输出位选
8255 C 口28AH读拨码开关方案一读 PC0,方案二读 PC7
8255 控制寄存器28BH写方式字81H 或 89H

接线按报告里的硬件图落:Y0 接 8254 的 CS,Y1 接 8255 的 CS;8254 的 CLK0 接 1MHz,OUT0 接 CLK1,OUT1 接 CLK2;GATE0、GATE1 接高电平,GATE2 接拨码开关;8255 的 PC0 也接拨码开关,PA 接七段数码管段选,PB 接位选。这里最容易忽略的是 GATE0 和 GATE1,它们不接高,通道 0 和通道 1 不输出,OUT1 自然没有 1Hz。另一个容易接错的是 GATE2 和 PC0 的关系:GATE2 是 8254 的计数门控,PC0 是 8255 读开关状态,两者可以并到同一个拨码开关上,但不要只接其中一个。

注意:GATE0、GATE1 必须为高电平,通道才持续输出;GATE2 由拨码开关控制,高电平允许计数,低电平停止计数。

2.3 主循环:轮询式结构比中断更适合先跑通

这份实验报告的主程序是轮询式:主循环里依次调显示、DOS 打印、按键扫描、时间更新四个子程序,没有走中断。对课程实验来说,这个选择很务实。中断方式要配中断向量、写中断服务程序、保护现场,还要处理 8259 的屏蔽字,任何一步没对,现象都是“程序跑飞”或“计数不动”,排查成本高。轮询式虽然占 CPU,但逻辑线性,拿示波器看 OUT1、拿万用表量 GATE2、在子程序之间加断点都方便。先把轮询跑通,再考虑用中断做按键或定时采样,是更稳的路线。

; 主循环框架:四个子程序轮流跑 START_MAIN: CALL SHOW_2 ; 两位数码管动态扫描 CALL SHOW_DOS ; DOS 屏打印当前秒数 CALL KEY_SCAN ; 读 PC0 拨码开关,置 FLAG CALL TIME_DATAUP ; 锁存并读 8254 通道2,更新 TIME JMP START_MAIN

逻辑说明:SHOW_2负责把TIME拆成十位和个位并动态扫描;SHOW_DOS用 DOS 的 2 号功能输出字符,BUF用来去重,避免同一秒反复刷屏;KEY_SCAN读 8255 C 口的开关位,把FLAG置 0 或 1;TIME_DATAUP只在FLAG=1时锁存并读取 8254 通道 2。四个子程序顺序不唯一,但TIME_DATAUP最好放在显示之后,这样屏幕和数码管看到的是同一轮采样值。参数上,TIME是 0 到 99 的秒数,FLAG是启停标志,BUF保存上一次打印值,NUM保存锁存到的计数值。

调试顺序建议反过来用:先注释掉SHOW_DOS和KEY_SCAN,只让SHOW_2显示一个固定数字,确认数码管段选和位选没问题;再打开KEY_SCAN,把FLAG送到数码管或 DOS 打印,确认拨码开关能读到;最后打开TIME_DATAUP,看TIME是否随拨码开关变化。每打开一个子程序就验证一个现象,比一次性全开再猜问题快得多。主循环里DELAY1的延时会影响扫描频率和按键响应,延时太长数码管闪,延时太短 CPU 空转,先按报告里的0FFFH跑,再按实际亮度微调。

3. 初始化拆解:8254 分频链和 8255 显示口的控制字

3.1 8254 控制字:36H、76H、B4H 分别改了什么

8254 的三个通道不是一起初始化的,每个通道先往控制寄存器 283H 写一个控制字,再往对应计数器端口写初值。报告里通道 0 用 36H,通道 1 用 76H,通道 2 用 B4H。36H 展开是 00110110B:SC1SC0=00 选计数器 0,RW1RW0=11 表示先写低字节再写高字节,M2M1M0=011 是方式 3 方波,BCD=0 是二进制计数。76H 是 01110110B,只把计数器选择改成 01,也就是通道 1,其余位不变。B4H 是 10110100B:计数器 2,先低后高,方式 2 分频脉冲,二进制计数。控制字写错一位,现象可能是没有输出、输出频率不对,或者读回值顺序反了。

; 8254 初始化:1MHz -> 1kHz -> 1Hz MOV DX, 283H MOV AL, 36H ; 计数器0:先低后高,方式3,二进制 OUT DX, AL MOV DX, 280H MOV AX, 1000 ; 1MHz / 1000 = 1kHz OUT DX, AL MOV AL, AH OUT DX, AL MOV DX, 283H MOV AL, 76H ; 计数器1:先低后高,方式3,二进制 OUT DX, AL MOV DX, 281H MOV AX, 1000 ; 1kHz / 1000 = 1Hz OUT DX, AL MOV AL, AH OUT DX, AL MOV DX, 283H MOV AL, 0B4H ; 计数器2:先低后高,方式2,二进制 OUT DX, AL MOV DX, 282H MOV AX, 0 ; 方式2下0表示65536个脉冲 OUT DX, AL MOV AL, AH OUT DX, AL

逻辑说明:通道 0 把 1MHz 除以 1000,得到 1kHz;通道 1 再把 1kHz 除以 1000,得到 1Hz;通道 2 对 1Hz 脉冲计数,计数值就是经过的秒数。参数说明:初值 1000 的十进制是 03E8H,低字节 E8H 先写,高字节 03H 后写;如果写成先高后低,读回值会错位。通道 2 初值写 0,在方式 2 下不是“零个脉冲”,而是 65536 个脉冲,报告里用SUB BX,AX做差,方案二用0FFFFH-AX,都是围绕这个初值做文章。方式 3 输出方波,适合做分频链;方式 2 输出分频脉冲,适合计数,别把两者混用。

注意:计数初值写入顺序必须和控制字里的“先低后高”一致,否则读回值会错位,现象像“计数器乱跳”。

3.2 8255 控制字:81H 和 89H 的 C 口方向差异

8255 的控制字决定 A、B、C 口的方向。方案一用 81H,方案二用 89H,这两个值只差一位,但 C 口方向完全不同。81H 是 10000001B:A 口方式 0 输出,B 口方式 0 输出,C 口高 4 位输出,C 口低 4 位输入,所以 PC0 可以读拨码开关。89H 是 10001001B:A 口输出,B 口输出,C 口高 4 位和低 4 位都输入,所以方案二读 PC7。报告里方案二的注释写“PC7 输入”,代码里读 28AH 后AND AL,80H,和控制字是对应的;方案一读 PC0,代码里AND AL,00000001B,和 81H 对应。把方案一的KEY_SCAN贴到方案二的初始化后面,读 PC0 永远是 0,这不是开关坏了,是 C 口方向没配对。

; 方案一:81H,A/B 方式0输出,C高4位输出,C低4位输入 MOV DX, 28BH MOV AL, 81H OUT DX, AL ; 方案二:89H,A/B 方式0输出,C口高4位和低4位都输入 MOV DX, 28BH MOV AL, 89H OUT DX, AL

逻辑说明:方式 0 是基本输入输出,不需要握手信号,适合拨码开关和数码管这种慢速外设。参数说明:81H 里 D4=0 表示 A 口输出,D3=1 表示 C 口高 4 位输入?这里别死记位,直接按“A 输出、B 输出、C 低输入”记方案一;按“A 输出、B 输出、C 全输入”记方案二。实际写代码时,先确定你读的是 PC0 还是 PC7,再选控制字:读 PC0 用 81H,读 PC7 用 89H。8255 控制寄存器地址是 28BH,A/B/C 口地址是 288H/289H/28AH,地址错一位就会写到别的端口。

3.3 初始化顺序和上电默认值:先清显示再开计数

初始化顺序没有强制规定,8255 和 8254 谁先谁后都能跑,但显示清零要放在主循环之前。上电时 8255 的输出口状态不确定,数码管可能随机亮段,看起来像“程序已经跑了”,其实只是端口默认电平。稳妥做法是先写 8255 控制字,再把 PA 和 PB 送 00H,把数码管灭掉,然后初始化 8254,最后清FLAG和TIME。这样上电后屏幕是干净的,拨码开关一拨就能看到从 0 开始计数。要是先开计数再清显示,前几秒的读数可能被清屏动作打断,现象是“第一次计数总少一秒”。

; 上电清显示,避免数码管随机亮段 MOV DX, 288H MOV AL, 00H OUT DX, AL MOV DX, 289H MOV AL, 00H OUT DX, AL MOV FLAG, 0 MOV TIME, 0

逻辑说明:PA 送 00H 让段选全灭,PB 送 00H 让位选全关,两个口都清零后数码管不会显示乱码。参数说明:FLAG=0表示当前不计数,TIME=0表示显示从 0 开始;如果拨码开关默认是高电平,上电就会计数,这时要先读一次开关再清TIME,否则第一个读数不是从零开始。调试时可以用万用表量 PA 口,全灭时 PA0 到 PA7 应该都是低电平;如果有高电平,先查 8255 控制字和片选,不要急着换数码管。

4. 测速与显示:两位数码管扫描和 DOS 同步输出的实现

4.1 时间拆位:DIV 10 之后商和余数别拿反

TIME是 0 到 99 的秒数,要显示到两位数码管,先拆成十位和个位。报告里用DIV BL,BL=10,被除数是AX,商在AL,余数在AH。个位是余数,十位是商,这两个别拿反。拿反的现象很直观:12 秒显示成 21 秒,或者个位一直等于十位。拆位之后查段码表,XLAT用DS:BX+AL取表项,BX指向段码表首地址,AL是 0 到 9 的索引。段码表里3FH对应共阴 0,06H对应 1,5BH对应 2,如果你的实验箱是共阳数码管,整张表要取反,不然显示的是反码。

; TIME 为 0-99 的秒数 MOV AL, TIME MOV AH, 0 MOV BL, 10 DIV BL ; AL = 十位,AH = 个位 MOV TIME_GE, AH ; 个位 MOV TIME_SHI, AL; 十位

逻辑说明:MOV AH,0把AX的高字节清零,保证DIV BL做的是 16 位被除数除以 8 位除数;DIV BL之后AL存商,AH存余数。参数说明:TIME超过 99 时商可能大于 9,两位数码管装不下,方案一显示范围就是 0 到 99 秒;要做更长时间,得扩成三位或改为毫秒计数。TIME_GE和TIME_SHI保存的是 0 到 9 的索引,不是 ASCII 码,后面查表用XLAT,不要直接送数码管。

4.2 动态扫描:先灭、再选位、再送段码

两位数码管是动态扫描,同一时刻只亮一位,靠人眼视觉暂留看起来同时亮。顺序很重要:先把 PA 送 00H 灭掉当前位,再改 PB 选择要亮的位,最后把段码送到 PA。如果先送段码再改位选,切换瞬间上一位的段码会串到新位,现象是重影或亮度不均。报告里个位用PB=01H,十位用PB=02H,每次送完段码调DELAY1延时。延时太短数码管闪,延时太长亮度低,常见 1 到 2ms 一位,0FFFH循环次数可以按实验箱主频微调。

; 个位显示 MOV DX, 288H MOV AL, 00H ; 先送全灭,消隐 OUT DX, AL MOV DX, 289H MOV AL, 01H ; PB0 选右侧数码管 OUT DX, AL MOV DX, 288H MOV AL, TIME_GE ; 已查表后的段码 OUT DX, AL CALL DELAY1 ; 十位显示 MOV DX, 288H MOV AL, 00H OUT DX, AL MOV DX, 289H MOV AL, 02H ; PB1 选左侧数码管 OUT DX, AL MOV DX, 288H MOV AL, TIME_SHI OUT DX, AL CALL DELAY1

逻辑说明:PA 是段选,PB 是位选,先灭再选位再送段码,能避开切换瞬间的残影。参数说明:TIME_GE和TIME_SHI必须是查表后的段码,不是 0 到 9 的索引;DELAY1里的CX值越大,单位停留时间越长,扫描频率越低。如果只有一位亮,先查 PB 位选有没有两个位都置高,或者位选三极管有没有坏;如果两位亮度差很多,先查延时是否对称,再查段码表里两位的限流电阻。

注意:共阴和共阳段码表不能混用,3FH 对应共阴 0,如果你的板子是共阳,段码要取反。

4.3 锁存与读数:先发 80H 锁存,再读低字节和高字节

8254 通道 2 在计数,CPU 直接读可能读到高低字节不一致的值,所以要先发锁存命令。报告里往 283H 写 80H,这是锁存通道 2 的命令:SC1SC0=10 选计数器 2,RW1RW0=00 表示锁存当前值。锁存后先读低字节,再读高字节,中间不要插入其他 8254 操作,否则锁存值可能被覆盖。读回值AX是当前计数值,方案一用0 - AX取补码差,方案二用0FFFFH - AX,都是在算“已经过了多少个脉冲”。方案一最后只取BL,所以显示范围受 8 位限制,0 到 99 秒够用,但超过 255 会回绕。

; 锁存计数器2当前值 MOV DX, 283H MOV AL, 80H ; 计数器2锁存命令 OUT DX, AL MOV DX, 282H IN AL, DX ; 先读低字节 MOV AH, AL IN AL, DX ; 再读高字节 XCHG AH, AL ; AX = 计数值 MOV NUM, AX ; 初值为0时,已计数 = 0 - AX(补码),方案二用0FFFFH-AX MOV BX, 0 SUB BX, AX MOV TIME, BL

逻辑说明:锁存命令让 8254 把当前计数值扣在内部寄存器里,CPU 慢慢读也不会变;IN两次分别读低字节和高字节,XCHG AH,AL把高低字节拼成AX。参数说明:80H 只锁存通道 2,锁存通道 0 或 1 要换命令字;NUM保存原始计数值,方便调试时看十六进制;TIME=BL只取低 8 位,方案二用完整 16 位做减法更稳。DOS 显示子程序SHOW_DOS用INT 21H的 2 号功能逐字符输出,先查ASC表把数字转成 ASCII,再用BUF去重,避免同一秒反复打印。

方案一和方案二的区别可以

本文还有配套的精品资源,点击获取