资讯动态

1MHz到1Hz:8254/8255车辆测速实验的定时与显示链路

发布时间:2026/10/28 5:04:59 来源:尧图企业网站定制
简介《微机原理与接口技术——智慧交通车辆测速实验》是一份面向高校微机原理与接口技术课程学习者、物联网及嵌入式初学者的实验报告文档围绕智慧交通场景下的车辆测速系统设计展开可用于实验预习、报告撰写参考与接口技术复盘。压缩包内仅含1个docx文件大小约769KB内容以实验报告正文和插图为主结构按实验目的、设备环境、设计指标、硬件电路、程序流程、方案讨论、结果分析、心得体会与团队分工组织。文档结合8254/8253定时计数、8255并行接口与LED数码管显示说明车辆通过时的时间测量、速度计算及DOS屏幕同步显示的实现思路并讨论传感器选型、抗干扰、测速精度与响应时间等指标。已有644人学习适合需要对照完整实验流程、理解数据采集处理显示链路或查找误差分析写法的读者参考。1. 车辆测速实验的真相整条链路里没有一个器件真的测过速度这台装置里没有雷达没有地感线圈也没有任何模拟前端。8254 只管数脉冲8255 只管把字节搬到线上实验箱上那颗 1MHz 晶振也不会因为车开得快慢而变一点点。所谓车辆测速本质是把速度换成时间把时间换成脉冲个数最后把脉冲个数换成 8254 内部一个 16 位寄存器里的整数。这套微机原理与接口技术里最经典的换算链闭合点在哪、误差在哪一步被放大又被哪一步吃掉比照着接线图把线插对要难得多。整条链路被压缩进一段三百行的汇编任何一环松了数码管上就只剩乱码。2. 分频链1MHz 是怎么被压成 1Hz 计时基准的2.1 为什么不能拿 1MHz 直接计时1MHz 意味着每 1 微秒来一个脉冲。8254 每个通道是 16 位递减计数器最大初值 65536单通道一次最多数 65536 个脉冲在 1MHz 下就是 65.536 毫秒。车辆从进入测速段到离开慢一点要几秒快一点也有几百毫秒直接拿 1MHz 去计计数器会溢出几十次。溢出本身不致命8254 的方式 2 和方式 3 都会自动重装初值继续数。问题在于你读回来的只是「当前这一轮还剩多少」软件必须另外统计溢出了多少次而「读计数器」和「读溢出次数」这两件事在时间上不原子。两次读之间正好溢出一次结果就整体偏掉 65536 个计数换算成时间是几十毫秒的跳变显示出来就是一个莫名其妙的数字。另一种思路是降低计数分辨率、提高量程可 16 位位宽是死的怎么分配都逃不开这个天花板。所以必须降频。降频的目标频率由什么决定由显示格式倒推。这个实验要求两位数码管显示 0 到 99最自然的解释就是「秒」那计时脉冲就应该是 1Hz读出来的计数直接就是秒数中间不做任何换算。这是一个很典型的「输出格式反向约束时基」的设计很多人以为先定时基再想怎么显示实际工程里常常反过来。代价是分辨率。1Hz 时基下最小刻度 1 秒量化误差正负 1 秒。走完测速段要 10 秒相对误差 10%要 100 秒误差 1%。实验里那段「距离」必须足够长不是物理上需要是这块 16 位计数器加 1Hz 时基的组合逼出来的。注意把时基改成 10Hz 或 100Hz量程分别变成 6553.6 秒和 655.36 秒对测速段依然够用而分辨率能提到 0.1 秒和 0.01 秒。选 1Hz 是为了显示方便不是精度最优。2.2 两级 1000 分频级联的真正原因1MHz 到 1Hz 需要 10^6 分频8254 单个通道最大 65536 分频一个通道干不了这件事。所以拆成 1MHz 到 1kHz、1kHz 到 1Hz 两级每级 1000 分频1000 远小于 65536余量充足。级联的动机就这么朴素纯粹是位宽不够没有别的玄学。接线是 OUT0 接 CLK1OUT1 接 CLK2GATE0 和 GATE1 接高电平GATE2 接拨码开关。通道 0 和通道 1 都工作在方式 3。方式 3 是方波发生器初值为偶数 N 时输出高低各 N/2 个时钟为奇数时高电平多一个时钟。1000 是偶数OUT0 输出 1kHz、占空比 50% 的方波。方波的好处是它既能被下一级当 CLK 用8254 是下降沿触发又能直接被示波器看清调试时一眼判断分频对不对。通道 2 换成了方式 2这是分频器模式减到 0 时输出一个时钟周期宽的低脉冲然后重装初值继续。作为计时器方式 2 和方式 3 都能数数差别在输出行为方式 3 在计数过程中一直翻转示波器上看不出「停没停」方式 2 只在计到 0 那一刻出脉冲拨码开关拉低之后输出静止观察起来干净得多。这是实现层面的偏好不是硬性规定但排查问题时这点差别能省不少时间。; 8254 初始化两级分频 一级计时 MOV DX, L8254_K ; 283H 控制寄存器 MOV AL, 36H ; 通道0先低后高方式3二进制 OUT DX, AL MOV AX, 1000 ; 1MHz / 1000 1kHz MOV DX, L8254_0 ; 280H 通道0数据口 OUT DX, AL ; 先写低字节 E8H MOV AL, AH OUT DX, AL ; 后写高字节 03H MOV DX, L8254_K MOV AL, 76H ; 通道1先低后高方式3二进制 OUT DX, AL MOV AX, 1000 ; 1kHz / 1000 1Hz MOV DX, L8254_1 ; 281H 通道1数据口 OUT DX, AL MOV AL, AH OUT DX, AL MOV DX, L8254_K MOV AL, 0B4H ; 通道2先低后高方式2二进制 OUT DX, AL MOV AX, 0 ; 初值0在16位计数器里等价于65536 MOV DX, L8254_2 ; 282H 通道2数据口 OUT DX, AL MOV AL, AH OUT DX, AL1000 的十六进制是 03E8H所以先写 E8 再写 03。8254 的 16 位初值必须分两次写控制字的 D5D4 决定先低后高还是先高后低这里三个控制字的 D5D4 都是 11统一先低后高。写完控制字必须紧接着写初值因为 8254 收到控制字之后下一次对同一通道数据口的写操作会被硬件当成初值低字节中间插进别的操作初值就整体错位。通道 2 初值写 0在 16 位计数器里等价于 65536方式 2 下它从 65536 减到 1 再输出脉冲、重装。65536 秒将近 18 小时对这个实验来说等于「不会溢出」。2.3 控制字逐位拆解与写入顺序的坑36H 展开成二进制是 0011 0110D7D6 等于 00 选通道 0D5D4 等于 11 表示先读写低字节再读写高字节D3D2D1 等于 011 是方式 3D0 等于 0 表示二进制计数而不是 BCD 计数。76H 是 0111 0110D7D6 等于 01 选通道 1其余位与 36H 相同。B4H 是 1011 0100D7D6 等于 10 选通道 2D3D2D1 等于 010 是方式 2D5D4 仍为先低后高。D5D4 这两位最容易翻车。如果误写成 01只读写低字节初值只能写 8 位1000 被截成 E8H 等于 232分频比变成 232OUT0 出 4310Hz整条链的时间基全错。如果写成 10先高后低而代码还是先写 AL 再写 AH1000 会被解释成 E803H 等于 59395OUT0 只有 16.8Hz后面所有显示都慢得离谱。这两种错误在示波器上一测就现原形可如果不测、只盯着数码管很容易误判成程序逻辑问题然后去改显示代码越改越远。比较稳妥的做法是初始化完立刻用示波器量 OUT0确认 1kHz、占空比接近 50%再往下调。这两分钟能省掉后面几个小时的猜。2.4 计数初值的算式必须闭合两级分频的乘积必须等于时钟源频率除以目标频率。实验箱给了 1MHz 和 2MHz 两路可选用 1MHz 时两级各 1000如果用 2MHz第一级要分 2000第二级 1000乘积仍然是 10^6。两条通道的初值不能随便凑必须是整数且插得进 16 位。1MHz 除以 1000 正好整除所以不存在累积误差如果换成 1MHz 分 999输出是 1001.001Hz长时间跑下来显示会慢慢偏这种「看起来对、跑久了不对」的问题最难查。选一个能整除的分频系数比选一个「接近目标」的系数重要得多。3. 门控与锁存计数什么时候开始读的时候怎么不撕裂3.1 GATE 电平才是真正的秒表开关8254 每个通道有一根 GATE 引脚。方式 2 和方式 3 下GATE 为高电平时计数器才递减为低电平时停止并保持当前值。这个特性让「计时开始」和「计时结束」完全交给硬件软件不需要在某个时刻去清零计数器——8254 根本没有软件清零指令它只有靠 GATE 或重新写初值来复位。方案里 GATE2 接拨码开关拨上去变高通道 2 从 65536 往下数拨下来变低通道 2 停在某个值上。这个停住的值就是全部信息。如果不用 GATE 而让通道 2 一直计读回来的永远是「当前这一轮还剩多少」这一轮数完自动重装 65536 再来一轮你没法区分读到的 0x8000 属于第一轮中间还是第二轮中间。所以门控不是可选项是这个方案能成立的前提。两个方案对 GATE 的处理还有细微差别。方案一里 GATE2 直接接拨码开关同时 PC0 也接同一个开关软件通过 PC0 判断现在是「计」还是「停」方案二把 PC0 和 GATE2 连在一起程序轮询 PC0 判断状态。电气连接略有不同机制一致一个开关同时驱动 GATE 和一根可读的 IO 线硬件负责计数软件只负责观察。注意GATE0 和 GATE1 必须接高电平否则前两级分频根本不工作OUT0 和 OUT1 没有输出通道 2 连时钟源都没有。这是「完全没反应」类故障的首要原因。3.2 方式 2 的计数逻辑与用减法反推时间方式 2 的计数器从初值 N 开始递减减到 0 时 OUT 输出一个时钟周期宽的低脉冲然后自动重装 N 继续。从开始计到「已经数了 k 个脉冲」这一刻寄存器里剩的是 (N - k) mod N。方案一里通道 2 初值写 0即 N 等于 65536。开关拨上去之后数了 k 个 1Hz 脉冲寄存器剩 65536 - k。程序读回 AX 之后做一条减法MOV BX, 0 SUB BX, AX ; 16位减法0 - (65536-k) k (mod 65536) MOV TIME, BL ; 只取低8位因为0~99秒 256在 16 位补码下0 减 AX 等于 65536 减 AX正好就是 k。这一步是整个实验里最漂亮的地方不用额外记初值不用判断溢出一条减法把「剩余量」翻译成「已用量」。取 BL 是因为实验只跑 0 到 99 秒低字节够用如果跑到 255 秒以上这里会静默截断数字会在 256 处回绕。方案二里初值写 0FFFFHN 等于 65535用 SUB BX, AX 配 BX 等于 0FFFFH 得到的是 65535 减剩余逻辑相同只是 N 少 1。方案二还用 LIST 表直接按时间值查段码时间超过 15 秒就会取到 A 到 F 的段码所以它的显示子程序里有 CMP TIME, 0FH 的保护。这也是为什么方案一用除 10 拆位加两位显示的做法更合理——它天然能显示到 99。3.3 锁存命令读 16 位计数器为什么必须先写 80H8254 的计数器数据口只有一字节宽读 16 位值必须读两次先低字节后高字节。如果两次读之间计数器还在递减就可能读到撕裂的值。举个极端例子。计数器当前是 0100H你读低字节得到 00H就在这时它减到 00FFH你再读高字节得到 00H。拼起来是 0000H实际值是 00FFH差了 255 个计数。1Hz 时基下就是 255 秒的误差数码管上会突然闪出一个离谱的数字然后下一轮又恢复正常。这种「偶尔跳一下」的现象最容易被当成接触不良。8254 的对策是锁存命令。往控制口写一个 D7D6 选通道、D5D4 等于 00 的控制字硬件会把当前计数值复制进内部锁存器之后两次读都来自这个快照读完自动解锁不影响计数器继续跑。MOV AL, 10000000B ; 通道2 锁存计数值 MOV DX, L8254_K ; 283H 控制口 OUT DX, AL MOV DX, L8254_2 ; 282H 通道2 数据口 IN AL, DX ; 第一次读低字节 MOV AH, AL ; 暂存到 AH IN AL, DX ; 第二次读高字节 XCHG AH, AL ; 交换后 AX 才是完整的计数值 MOV NUM, AXXCHG AH, AL 这一步是因为 8254 先输出低字节后输出高字节而 x86 的 16 位值低字节在 AL、高字节在 AH。先读的低字节被存进了 AH后读的高字节进了 AL交换一下才对得上。这个交换很容易漏漏了之后读出来的值高低字节颠倒显示会变成完全无规律的数而且因为高字节通常很小看起来只是「个位数乱跳」。锁存命令的 D5D4 如果误写成 01锁存的就是状态信息而不是计数值读回来是一串读状态字看起来也是数字但跟时间毫无关系。这个坑很隐蔽程序不报错、不崩溃只是数字全错。4. 显示链路8255 怎么把字节搬到数码管和屏幕4.1 控制字 81H 与三个端口的分工81H 展开是 1000 0001D7 等于 1 是方式设置标志D6D5 等于 00 表示 A 组方式 0D4 等于 0 表示 PA 输出D3 等于 0 表示 PC 高 4 位输出D2 等于 0 表示 B 组方式 0D1 等于 0 表示 PB 输出D0 等于 1 表示 PC 低 4 位输入。结果就是 PA 出段码、PB 出位选、PC0 读拨码开关。这个分配几乎是唯一合理的选择段码正好 8 位占一个口位选两位用另一个口剩下的 C 口拆成高低两半一半输入读开关。硬件的引脚数刚好卡在这个组合上。方案二用的是 89H 等于 1000 1001D3 等于 1 表示 PC 高 4 位输入因为它的开关接在 PC7 而不是 PC0。同一块芯片、同一个实验线换了一根控制字就必须跟着改。控制字不是常数是接线的镜像这句话在这两个方案的对照里体现得最清楚。端口地址用途8255 PA288H数码管段码8255 PB289H数码管位选8255 PC28AH读拨码开关状态8255 控制口28BH方式字写入8254 通道0280H1kHz 分频8254 通道1281H1Hz 分频8254 通道2282H计时计数8254 控制口283H控制字与锁存命令4.2 动态扫描SHOW_2 的时序账两位数码管不是同时亮的是轮流点亮靠人眼视觉暂留合成两位同时显示。SHOW_2 的步骤是PA 送 00H 全灭PB 送 01H 选中右位PA 送个位段码延时PA 送 00H 全灭PB 送 02H 选中左位PA 送十位段码延时。那两次「送 00H」就是消隐。如果省掉顺序变成先换位选再送新段码那么在位选切换完成到新段码写入 PA 之间的几个机器周期里PA 上还挂着上一位的段码这个段码会被打到新选中的数码管上形成鬼影。当两位数字不同比如 1 和 2时鬼影表现为数字边缘发虚或者两个数字叠在一起。消隐的顺序也必须先灭段码再换位反过来先换位再灭同样会闪只是闪的方向相反。这个先后次序在书上很少写但实际调试时占用的时间不少。延时长度是亮度和闪烁的折中。延时长每一位亮的时间长、亮度高但两位切换慢人眼可能察觉闪烁延时短切换快不闪但每位占空比低亮度下降。代码里的 CX 是 0FFFH在 8086 上大约几个毫秒两位一轮下来接近几十毫秒刚好落在闪烁阈值的边上。换一台更快的机器这段延时要重算。注意数码管发暗或抖动时先调这个延时常数别急着怀疑段码表或 8255 接线。4.3 拆位、查表与两张表的分工TIME 是一个 0 到 99 的整数要变成两位十进制数字用两次除 10MOV BL, 10 MOV AL, TIME MOV AH, 0 DIV BL ; AL 商十位AH 余数个位 MOV TIME_GE, AH ; 存个位 MOV AH, 0 DIV BL ; 再除一次AL 0AH 十位 MOV TIME_SHI, AH ; 存十位第一次除法把 TIME 拆成商和余数第二次把商再拆一次。因为 TIME 不超过 99第二次的商一定是 0余数就是十位。这个写法比一次除法多一条指令但省掉了一个寄存器保存中间值在寄存器紧张的实模式下更划算。拆出的 0 到 9 要变成数码管能认的段码用 XLAT 查 LED 表。LED 表是共阴极段码数字段码点亮的分段03FHa b c d e f106Hb c25BHa b d e g34FHa b c d g466Hb c f g56DHa c d f g67DHa c d e f g707Ha b c87FH七段全亮96FHa b c d f g共阴极的意思是公共端接地段引脚给高电平才点亮。所以 3FH 等于 0011 1111最低位 a 到第六位 f 是 1第七位 g 是 0显示 0。如果实验箱配的是共阳极数码管整张表要逐位取反这是最容易搞混的地方插上线发现数字全是反的先查这个。DOS 显示用的是另一张 ASC 表内容是 30H 到 39H也可以直接 ADD AL, 30H 算出来。保留表的写法是为了一致性将来要显示 A 到 F改表比改指令方便。4本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑