简介:这份面向微机原理与接口技术课程学习者的实验报告文档,围绕智慧交通车辆测速场景,完整记录从需求分析到结果验证的实现过程,适合正在做接口芯片综合实验、课程设计或物联网交通应用入门的学生参考。压缩包内共1个docx文件,约769KB,正文按实验目的、设备与环境、设计指标、硬件电路图、程序流程图、方案设计及讨论、实验结果与分析、心得体会和团队分工组织,便于直接对照实验环节梳理思路。内容重点涉及8254/8253定时计数、8255驱动LED数码管、传感器信号采集以及DOS屏幕与实验箱同步显示,并给出±5%测速精度、响应时间和抗干扰等指标讨论。已有646人学习,读者可从中了解测速系统从时间测量换算速度的完整方案、调试要点和误差分析写法,也能参考报告结构与分工记录完成自己的实验整理。
1. 定值距离测时间:一个 8254 级联就把车速变成了可读数字
智慧交通里的车辆测速听着像是传感器加算法的事,落到微机原理与接口技术的实验箱上,其实被压缩成了一个很朴素的问题:距离固定,测速就退化成测时间。我第一次做这份智慧交通车辆测速实验时,八成精力都砸在写汇编上,真正把我卡住两天的是 1MHz 时钟怎么干净地分频到 1Hz,以及拨码开关的电平到底该接到哪个引脚。这篇就把这条链路拆开讲:三级分频为什么必须存在、8255 三个端口怎么分工、两套方案各自的能力边界、五个把我打回去重做的现场问题,最后落到一个能把误差压进 ±5% 的时基改法。不管你是要交这份实验报告,还是想拿它当物联网 IoT 侧测速 demo 的入门骨架,下面这些都能直接对着接线和敲代码。
2. 上电之前先算清楚:三级分频链与 8255 口线分工
这部分是我吃过亏之后才养成习惯的:先算,再接线。实验箱一插电、程序一下进去,异常现象是看不出因果的——数码管乱跳,你分不清是分频错了、口线错了还是控制字写错了。所以接线之前,我会把三个数写纸上:计数器位宽、需要的时间分辨率、每级分频系数。这三个数一旦定下来,硬件连接基本就没有自由度了。
2.1 1MHz 为什么不能直接进计数器
8254 是 16 位减法计数器,单个计数器最大计数值 65536。实验箱给的时钟源是 1MHz 和 2MHz,如果拿 1MHz 直接当计时脉冲,65536 个脉冲只对应 65.536ms,计数器就溢出重装了。也就是说你连 0.1 秒都测不到,更别说几十秒的车辆通过时间。反过来,就算位宽够,1MHz 下每秒跳一百万次,数码管刷新和 DOS 打印根本跟不上,读出来的值也是没有意义的瞬时值。
所以分频不是为了“让频率好看”,它的真实目的是建立一条直读关系:让计数器每减 1,恰好代表过去 1 秒。这样读回的计数值减去当前值,就是经过的秒数,中间不需要任何软件换算和浮点运算。在只有汇编、没有浮点单元的環境里,这个设计决定非常关键——所有的时间计算都退化成整数减法。
判断依据也很硬:目标时基 1Hz,输入 1MHz,需要 1,000,000 分频。而单级上限是 65536,1,000,000 远远超过它,所以一级绝对做不到,必须级联。这就是“三级分频链”不是可选项、而是唯一解的原因。我见过有人试图用软件循环延时来凑秒,结果主频一变、插入一次 DOS 调用,时间就全飘了,这类做法在需要可复现的场合直接排除。
2.2 分频系数怎么定:1000×1000 不是唯一解
级联方案有很多种,只要每级系数不超过 65536、乘积等于 1,000,000 就行。1000×1000 是最省心的一种,因为整数好算,而且中间那一级 1kHz 是个很好的观测点——示波器一夹就能看到方波,出问题时能立刻判断是前级坏了还是后级坏了。
| 级数 | 输入 | 工作方式 | 分频系数 | 输出 | 作用 |
|---|---|---|---|---|---|
| 计数器 0 | 1MHz | 方式 3(方波) | 1000 | 1kHz | 粗分频,可观测 |
| 计数器 1 | 1kHz | 方式 3(方波) | 1000 | 1Hz | 生成计时基准 |
| 计数器 2 | 1Hz | 方式 2(分频/速率发生器) | 0 或 0FFFFH | 计数递减 | 记录经过秒数 |
工作方式的选择是有讲究的,不是随手填。前两级用方式 3,因为方式 3 输出的是占空比接近 50% 的方波,边沿干净,直接灌到下一级的 CLK 引脚上最稳;初值 1000 是偶数,输出严格对称。最后一级用方式 2,方式 2 每来 N 个时钟输出一个时钟宽的负脉冲,而且计数值在计数过程中可以随时锁存读取——这正是“读剩余时间”需要的特性。如果最后一级也用方式 3,读到的是方波相位,跟经过时间对不上,读出来纯属玄学。
分频系数也不是非 1000 不可,500×2000、800×1250 都满足条件。我一般会选能让中间频率落在示波器好测、且两级系数接近的方案,这样两级计数器的相对误差接近,累计误差最小。1000×1000 刚好符合。
提示:写初值前先确认控制字里的读写顺序位。8254 规定同一计数器的初值必须先低字节后高字节,只写低字节、高字节会保留上次的残留值,分频系数直接错掉,而且错得毫无规律。
2.3 8255 三个端口的分工与接线对照
8255 在这套系统里干三件事:往数码管送段码、往数码管送位选、把拨码开关的状态读回来。A 口接段选信号(8 根线对应 a~g 加小数点),B 口接位选(两根线选左右两位),C 口接拨码开关做输入。这个分工几乎是固定的,因为 A 口是唯一一个可以整体输出 8 位数据的口,段码正好 8 位。
接线这块,我建议照着表一条条打勾,别凭记忆:
| 连接 | 说明 |
|---|---|
| 译码输出 Y0 → 8254 片选 | 占用 280H~283H |
| 译码输出 Y1 → 8255 片选 | 占用 288H~28BH |
| CLK0 ← 1MHz | 外部时钟源输入 |
| OUT0 → CLK1 | 1kHz 送下一级 |
| OUT1 → CLK2 | 1Hz 计时基准 |
| GATE0、GATE1 → 高电平 | 常通,不允许门控 |
| GATE2 → 拨码开关 | 门控计时启停 |
| PA0~PA7 → 数码管段选 | 段码输出 |
| PB0、PB1 → 数码管位选 | 位选输出 |
| PC0 或 PC7 → 拨码开关 | 读开关状态 |
GATE 这根线是整个实验的“扳机”。8254 的方式 2 和方式 3 都受 GATE 电平控制:GATE 为低时停止计数,为高时允许计数。把 GATE2 接到拨码开关上,就得到了一个纯硬件的启停开关——开关拨上去开始计时,拨下来冻结计数。这个设计比软件轮询开关再控制计数要干净得多,因为计时和判断是并行发生的,不存在“程序正在显示,开关已经拨下”这种漏检窗口。
端口地址的分配来自译码器输出,280H 起的四个地址依次对应计数器 0、计数器 1、计数器 2 和控制寄存器;288H 起的四个地址对应 8255 的 A、B、C 口和控制寄存器。写代码时我习惯用 EQU 把这些地址定义成符号,改接线路时只改一处,不用满篇找立即数。
3. 汇编骨架怎么搭:初始化、扫描、按键、计时四段拆开看
整份程序其实就是四段循环:初始化一次,然后进主循环不停做四件事——刷数码管、刷屏幕、读开关、更新时间。结构清楚了,调试的时候就能一段一段切:数码管不亮就只调显示子程序,值不对就只调计时子程序,别指望一次跑通。下面按这四段拆,附上关键的控制字含义。
3.1 控制字逐位拆:36H、76H、B4H 各写了什么
8254 的控制字是 8 位,最高两位选计数器,中间两位定读写顺序,低三位定工作方式。我把这套实验里用到的四个值列出来,填表的时候对着看比记口诀靠谱:
| 控制字 | 二进制 | 选中 | 读写 | 方式 | 含义 |
|---|---|---|---|---|---|
| 36H | 0011 0110 | 计数器 0 | 先低后高 | 3 | 方波发生器 |
| 76H | 0111 0110 | 计数器 1 | 先低后高 | 3 | 方波发生器 |
| B4H | 1011 0100 | 计数器 2 | 先低后高 | 2 | 速率发生器 |
| 80H | 1000 0000 | 计数器 2 | 锁存 | — | 读当前计数值 |
初始化顺序不能颠倒:先写控制字,再写初值。因为控制字里的读写顺序位决定了后续初值字节的接收方式,顺序反了芯片会把控制字当成初值的一部分吃掉。
; 8254 初始化:1MHz -> 1kHz -> 1Hz MOV DX, 283H ; 控制寄存器端口 MOV AL, 36H ; 计数器0,先低后高,方式3 OUT DX, AL MOV DX, 280H ; 计数器0 端口 MOV AX, 1000 ; 分频系数 1000 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 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 ; 初值 0 在方式2下等价于 65536 OUT DX, AL MOV AL, AH OUT DX, AL这段代码里最容易看漏的是MOV AX, 0。8254 的初值 0 不是“零次计数”,而是“满量程 65536”。对 1Hz 时基来说,这意味着最长可以数 65536 秒,接近 18 小时,远超实验需要。第二套方案里有人用 0FFFFH 作初值,计数上限是 65535,差别只有一格,但取补运算时65535 - 计数值直接就是秒数,少一次判断,这是写法上的取舍。
8255 的控制字同理。方案一用 81H(1000 0001B):A 组方式 0、A 口输出、C 口高 4 位输出、B 组方式 0、B 口输出、C 口低 4 位输入。方案二用 89H(1000 1001B),把 C 口高 4 位也改成输入,好让 PC7 能读开关电平。差别就在 D3 这一位,但接错就是读不到电平。
; 8255 初始化:A口段码输出,B口位选输出,C口低4位输入 MOV DX, 28BH MOV AL, 81H OUT DX, AL3.2 两位数码管的动态扫描与消隐
两位数码管不是同时亮的,是一位一位轮流点,靠人眼视觉暂留拼成“同时显示”。实现上就三步:灭掉当前位、送出位选、送出段码、延时、换下一位。顺序里那个“先灭”很关键,专业点叫消隐,不做的后果是上一位的段码会残留到下一位上,看起来像鬼影。
SHOW_2 PROC PUSH AX PUSH BX PUSH DX MOV BL, 10 MOV AL, TIME MOV AH, 0 DIV BL ; AL=十位,AH=个位 MOV TIME_GE, AH MOV AH, 0 DIV BL MOV TIME_SHI, AH LEA BX, LED MOV AL, TIME_GE XLAT ; 个位转段码 MOV TIME_GE, AL LEA BX, LED MOV AL, TIME_SHI XLAT ; 十位转段码 MOV TIME_SHI, AL MOV DX, L8255_A MOV AL, 00000000B ; 先消隐 OUT DX, AL MOV DX, L8255_B MOV AL, 00000001B ; 选右侧位 OUT DX, AL MOV DX, L8255_A MOV AL, TIME_GE OUT DX, AL CALL DELAY1 MOV DX, L8255_A MOV AL, 00000000B ; 换位前先消隐 OUT DX, AL MOV DX, L8255_B MOV AL, 00000010B ; 选左侧位 OUT DX, AL MOV DX, L8255_A MOV AL, TIME_SHI OUT DX, AL CALL DELAY1 POP DX POP BX POP AX RET SHOW_2 ENDP延时常数0FFFH是这段代码里最需要手调的地方。循环四千多次,在实验箱的主频下大概十几毫秒,两位轮一遍接近三十毫秒,刷新率三十几赫兹,能看但有轻微闪。把常数减到1FFH附近会稳很多,代价是每位点亮的占空比下降、亮度变暗。我的经验是先从 1FFH 试起,暗就往回加,闪就往前减,中间有个窗口。
注意:位选和段码必须写到不同的端口,如果 A 口和 B 口接反了,现象是数码管乱亮且完全无规律,很多人第一反应是段码表错了,其实只是两根排线插反。
3.3 锁存、取补与十进制拆分
读计数值这一步有个时序要求:不能直接读端口,得先发锁存命令。因为计数器在后台不停递减,读低字节和读高字节之间如果恰好发生借位,两次读到的就不是同一个数,拼出来的结果会差一大截。锁存命令把当前值扣进一个影子寄存器,之后两次读都从影子寄存器取,值就是稳定的。
; 读回经过的秒数并显示 MOV AL, 10000000B ; 计数器2 锁存命令 MOV DX, L8254_K OUT DX, AL MOV DX, L8254_2 IN AL, DX ; 低字节 MOV AH, AL IN AL, DX ; 高字节 XCHG AH, AL ; 拼成 16 位,AX = 剩余计数值 MOV BX, 0 SUB BX, AX ; 取补:BX = 已计脉冲数 = 经过秒数 MOV TIME, BL ; 取低 8 位取补这一步SUB BX, AX是整段里最漂亮的地方。计数器做的是减法,从初值一路往下减,读回来的是“剩余量”,用 0 减掉它,借位自动处理,结果直接就是“已经过去的量”。16 位运算一次搞定,不需要判断有没有回绕。方案二里写成MOV BX, 0FFFFH再SUB BX, AX,道理一样,只是把初值对齐到 0FFFFH 省掉一格。
十进制拆分用DIV BL(BL=10):商是十位,余数是个位。这里有个隐含约束——TIME是字节型,最大 255,而两位数码管只能显示 0~99。所以超过 99 秒之后,十位会大于 9,查段码表时越界,屏幕上跳出来的就是乱码。这不是 bug,是设计容量限制,第二套方案只显示一位,容量更小但逻辑更简单。
转 ASCII 输出到 DOS 屏时,小于 10 的数加 30H 就得到 '0'~'9' 的编码;如果做过 BCD 加法或需要拼成两位数,要加 37H 再做调整。方案二里那句CMP BL,9 / JLE PRINT / ADD BL,7H就是在做这个修正,只显示个位,所以看起来有点绕。
4. 两套方案怎么选:连续实时显示与开关门控锁存的取舍
这两套方案我都完整跑过一遍,结论是它们不是“好”和“更好”的关系,而是适用于两种不同的验证目的。方案一适合观察系统是否稳定工作,方案二适合验证单次测量的时序是否正确。下面把能力边界摊开讲。
4.1 方案一:连续计数加双位动态扫描
方案一的主循环是四件事轮着做:刷两位数码管、刷 DOS 屏、读 PC0 判断开关、读计数器更新时间。开关拨上去(PC0 读到高电平),FLAG 置 1,程序开始不断读计数器并刷新 TIME;开关拨下来,FLAG 归 0,TIME 冻结在最后的值上,两位数码管和 DOS 同时停留在那个数上。
这套结构的好处是“所见即所得”:计时过程中数码管是在动的,你能直观看到读数一秒钟跳一格,任何异常(跳两格、不跳、倒退)都会立刻暴露。做硬件联调时这点非常值钱,因为它把“计时准不准”变成了一个可视化的东西,不需要额外仪器。
代价是主循环被拉长了。每一次循环都要跑两个显示子程序加一次计数读取,如果延时常数设大了,扫描周期会超过 50ms,读数更新就变慢,人眼看到的是“半天才跳一次”,容易误判成计数不准。反过来延时设太小,数码管占空比不足,亮度掉下去,白天在实验室几乎看不清。这个平衡点只能现场调。
另外方案一的 TIME 是字节型,容量上限 255 秒,两位数码管显示上限 99 秒。做车辆测速的模拟场景,几十秒量级完全够用,但如果要测更长的过程,就得改成字型并把显示扩到三位,那就不是改一行代码的事了。
4.2 方案二:开关门控加单次锁存读取
方案二的思路不一样:它把整个过程切成“等待—计时—结束—读数”四个阶段。程序先在循环里查 PC7 的电平,开关拨上去开始计时,拨下来表示计时结束,此刻发锁存命令、读回计数值、算出秒数、送一位数码管、再用 DOS 功能调用打印出来,然后回到等待状态,准备下一次。
这种“事件驱动”的写法在小实验里反而更接近真实仪表的逻辑——真实测速设备也是车来了触发、车走了结算,不会一直刷。它的代码量比方案一小一半,状态清晰,单次测量的时序也更好分析。
但它的风险点集中在“读取时机”上。如果锁存命令发出之前计数器因为门控电平抖动又走了一格,读到的值就偏了;如果开关机械抖动,一次拨动被识别成两次,就会多算或少算。这类问题在方案一里被连续刷新掩盖了,在方案二里会直接体现在结果上。所以方案二更适合做“已知输入、验证输出”的定量实验,不适合做在线观测。
4.3 对比表与我的选择
| 维度 | 方案一(连续扫描) | 方案二(门控锁存) |
|---|---|---|
| 显示位数 | 两位,0~99 | 一位,0~9 |
| 计数初值 | 0(等价 65536) | 0FFFFH(65535) |
| 读开关引脚 | PC0 | PC7 |
| 控制字 | 81H(C 口低 4 位输入) | 89H(C 口高 4 位输入) |
| 读数方式 | 循环轮询 | 结束后锁存一次 |
| 代码量 | 大,约五个子程序 | 小,主流程线性 |
| 实时性 | 实时可见 | 结算后显示 |
| 主要风险 | 扫描周期与计时互相拖累 | 读取时序与开关抖动 |
如果是第一次做这套实验,我建议先跑方案二。它流程短,一次只验证一件事,出问题容易定位——是门控没接对、是锁存没发、还是查表算错,能一层层剥。等单次测量准了,再改方案一,把显示和刷新加上去,这时候遇到的问题就只会出在显示层,不会和计时层混在一起。反过来先做方案一,一上来就是“数码管乱跳”,你根本分不清是分频错了还是显示子程序错了,这时候除了玄学没有别的解释。
5. 避坑与排查:五个让我返工的现场问题
这一章是我把两次返工记录整理出来的,每条都按“看到什么—为什么—怎么改”写。硬件实验最难受的地方是现象和原因隔着好几层,下面的对照表能帮你少走几趟弯路。
5.1 数码管发虚、有鬼影、只亮一位
现象:屏幕上两位数字叠在一起,或者只有一位亮,另一位始终是暗的。
原因基本锁定在扫描时序。第一种可能是位选信号没切换,B 口一直只输出00000001B,右边位永远被选中,左边位的段码自然显示不出来;第二种可能是没有消隐,段码先送、位选后切,上一位的段码在切换瞬间被下一位继承,形成重影;第三种是延时常数太小,每位点亮时间只有几百微秒,占空比太低,亮度撑不住。
解决顺序是:先用万用表量 B 口两根线的电平,确认切换时确实在 01 和 10 之间跳;再在每次换位前插入一条送00H到 A 口的消隐指令;最后调DELAY1里的循环常数,从1FFH开始往上加,加到不闪为止。三步里前两步是逻辑问题,必须改对,第三步是手感问题,可以现场调。
5.2 段码整体反相:该亮的全灭
现象:数码管显示的是“反色”效果,本该点亮的段是暗的,本该灭的段反而亮,看起来像一堆乱码。
原因只有一个:共阴和共阳搞反了。段码表3FH, 06H, 5BH...是共阴极编码,3FH对应“a~f 亮、g 灭”显示 0。如果实验箱的数码管是共阳极,输出高电平反而熄灭,整张表要按位取反(3FH变C0H)。
解决方式很简单,把段码表整体按位取反,或者干脆在输出前加一条NOT AL。判断实验箱是哪种,不用翻手册——把 A 口输出00H,如果八段全灭就是共阴,全亮就是共阳。这个测试三十秒能做完,比查资料快。
5.3 读数纹丝不动,或者一口气跑满
现象:开关拨上去之后,显示值一直停在 0,或者瞬间跳到上限值不动了。
第一种情况,先查 GATE2 的接线。方式 2 的计数受 GATE 电平控制,GATE 为低时计数器完全停住,读回来永远是初值。用万用表量 GATE2 对地电压,拨动开关看它有没有从 0 跳到高电平,如果没有,多半是开关没接上拉电阻,引脚悬空读到的是随机值。
第二种情况,检查控制字的读写顺序位。如果控制字写的是“只写低字节”,而代码按低高两字节写,第二个字节会被当成新的控制字吃掉,分频系数直接错掉,输出频率变成几毫秒一个脉冲,计数器瞬间跑满。这种情况最迷惑人的地方是:程序不报错,芯片也不报错,只有结果是错的。解决办法就是每次写初值前后各打印一次控制字状态,确认写进去了。
5.4 DOS 屏上什么都不打印
现象:数码管显示正常,时间在跳,但 DOS 屏幕上干干净净。
这套程序里屏幕输出被 FLAG 挡了一道:CMP FLAG, 0 / JZ SHOW_DOS_END,开关没拨上去时直接跳过打印。所以如果数码管在动而屏幕不动,先确认 FLAG 真的被置成了 1——有可能开关接的是 PC0,代码读的却是 PC1,两边对不上。
还有一种更隐蔽的情况:BUF缓存比较。程序里有一句“当前值和上次打印的值相同就跳过”,目的是避免重复刷同一行。但如果第一次进入时BUF的初值恰好等于当前 TIME,第一次打印就被跳过了,看起来像程序卡死。把BUF初始化成一个不可能的值(比如0FFH)就能解决。
最后别忘了回车换行。DOS 的 02H 功能只输出单个字符,不自动换行,几十次输出全挤在一行里,看起来像只有一个数。要在打印完补一个0DH和0AH。
5.5 查到一半程序跑飞,实验箱像重启了
现象:运行几秒后数码管全灭、DOS 输出中断,重新上电又正常,反复如此。
这类现象多半是查表基址被覆盖了。方案二里有一句MOV AL, [BX+LIST],如果 BX 装的是计数值而不是表内偏移,[BX+LIST]会指向数据段之外的内存,读到的字节被当成段码送出去还算轻的,严重时读到的内容会破坏堆栈,程序直接跑飞。
正确写法是把表首地址装进 BX,偏移单独放:LEA BX, LIST再XLAT或者MOV AL, [BX+SI]。同理,锁存读回的计数值要先取补、再压缩到 0~15 的有效范围内,才能拿去当表索引。我在这一条上翻过两次车,第二次是因为算出来的秒数刚好落在表尾之外,前 15 秒都正常,第 16 秒开始乱码,排查时差点以为是硬件热漂移。
6. 复现验证清单:把 ±5% 误差压下去的几个动作
把整条链路跑通只是及格线,真正决定这份实验报告有没有说服力的是误差分析这一段。我给自己的验证流程整理成了一张清单,每一条都能现场做:
| 检查项 | 方法 | 合格标准 |
|---|---|---|
| 时钟源频率 | 示波器测 CLK0 | 1MHz ±1% 以内 |
| 第一级分频 | 示波器测 OUT0 | 1kHz 方波,占空比接近 50% |
| 第二级分频 | 示波器测 OUT1 | 1Hz 方波,周期 1s |
| 门控电平 | 万用表测 GATE2 | 拨动时在 0 与高电平间切换 |
| 单次计时 | 秒表对比 3 次 | 偏差 ≤1 秒 |
| 重复性 | 同一时长测 5 次 | 极差 ≤1 秒 |
清单里最值得说的是最后两项。1Hz 时基意味着时间分辨率就是 1 秒,量化误差 ±1 秒是硬约束,跟代码写得多好没关系。测 24 秒时,±1 秒的相对误差是 4.2%,已经快贴到 ±5% 的指标线上了。也就是说,用 1Hz 时基做短时测量,误差预算几乎全被量化误差吃光,再谈什么“抗干扰能力”都是空的。
我后来改的办法不是优化代码,而是换时基:把第二级分频系数从 1000 改成 100,OUT1 输出 10Hz,每个脉冲代表 0.1 秒。计数器 2 读回值除以 10 取整就是秒,余数就是十分位。这样量化误差从 ±1 秒压到 ±0.1 秒,24 秒时相对误差 0.4%,±5% 的指标一下就有了大半余量。
; 时基改 10Hz:1MHz -> 1kHz -> 100Hz-> 实际取 10Hz 只需改第二级系数 MOV DX, 283H MOV AL, 76H ; 计数器1 仍为方式3 OUT DX, AL MOV DX, 281H MOV AX, 100 ; 1kHz / 100 = 10Hz,每脉冲 0.1 秒 OUT DX, AL MOV AL, AH OUT DX, AL ; 读数时先算脉冲数,再按 0.1 秒换算 MOV BX, 0 SUB BX, AX ; BX = 已计脉冲数 MOV AX, BX MOV BL, 10 DIV BL ; AL = 整数秒,AH = 十分位这段改动的代价是显示要处理小数位,两位数码管不够用,得扩到三位或者用小数点兼做分隔。但换来的是误差余量,值。另一条路是多次测量取平均,用 N 次测量的均值把随机误差压到 1/√N,但量化误差是系统性偏差,平均消不掉,只能靠提高时基频率。这个区别我在报告里专门写了一小段——很多人把量化误差当随机误差处理,平均了半天发现值还是偏,就是因为方向搞错了。
回过头看,这份实验最容易让人走偏的地方,是把注意力全放在“代码能不能跑”上,而忽略了“测量系统本身的误差从哪来”。我现在的习惯是,凡是带时基的实验,接线之前先把分辨率和误差预算算一遍,把 ±1 个脉冲对应的物理量换算成百分比,看看指标还剩下多少空间,再决定分频系数怎么取。那一次返工之后,我每份实验报告的“结果分析”里都会先放这张误差分解表,再谈数据。
如果你手上正在做同一套实验,建议先照第 2 章的接线表接一遍、用第 6 章的清单验证一遍,再回头改代码,顺序反了会很痛苦。需要的话,这份整理好的报告文档可以直接拿去对照,能省下你至少两个晚上的示波器时间。希望帮到你。
本文还有配套的精品资源,点击获取