51单片机00~99秒数码管秒表:AT89C51+MAX7219方案
简介这份文档面向电子信息、物联网及计算机相关专业学生与单片机初学者围绕AT89C51单片机配合MAX7219驱动数码管实现00~99秒计时显示可用于《单片机原理及应用》课程设计、秒表类项目参考与硬件软件联调学习。压缩包内共1个doc文件约915KB主体为一份课程项目设计报告内容涵盖设计目的与要求、系统总体方案、AT89C51与MAX7219器件说明、系统方框图与工作原理、复位与晶振电路、显示及键盘电路、软件流程和万用板制作等模块。报告还呈现计时、暂停、清零及数码管显示功能的实现思路读者可据此理解定时器/计数器计时原理、MAX7219显示驱动方式和按键输入处理并参考其章节组织与硬件单元设计完成自己的课设文档或实验方案。目前已有3606人学习下载适合需要完整项目框架与报告写法的读者查阅。1. 从一块四位数码管说起00~99 秒秒表到底要交什么课程设计里「51单片机 00~99 秒数码管显示」这个题目最容易被低估看上去只是让四位数码管每秒加一真焊起来才会撞上三件事——定时器怎么定到 10ms 不漂、四位数字怎么在有限 I/O 上刷得稳、按键在抖动里怎么保证按一次只加一次。这套方案用 AT89C51 做主控用 MAX7219 串行驱动四位数码管把「亮」这件事从单片机手里拿走单片机只管计时和键盘计时范围 00.00 到 99.99 秒配开始、暂停、记录、上翻、下翻、复位六个按键显示用 7SEG-MPX4-CC 共阴四位一体管。适合正在做单片机课设、需要一份能焊出来、能跑起来、答辩时讲得清信号流向的完整方案的人。下面按选型、硬件、软件、避坑、验收的顺序往下推。2. 选型定案AT89C51 管算、MAX7219 管亮的分工边界2.1 AT89C51 的端口与定时资源盘点AT89C51 的账面参数很朴素4KB 片内 Flash、128 字节 RAM、32 根 I/O 口分成 P0 到 P3 四组、两个 16 位定时器/计数器、5 个中断源、一个全双工串口工作电压 4.0 到 5.5V最高能跑到 24MHz。这个题目里真正被用到的资源其实很少一个定时器 T0 负责 10ms 节拍6 根 P1 引脚做键盘3 根 P3 引脚做 MAX7219 的串行接口剩下的口全部空着。资源不紧张反而说明设计的重点不在「够不够用」而在「分配得清不清楚」。资源分配说明定时器 T0方式 116 位10ms 中断100 次进 1 秒定时器 T1未使用留给后续加串口通信P1.0~P1.5六个独立按键输入内部上拉按下为 0P3.0 / P3.1 / P3.2DIN / LOAD / CLK驱动 MAX7219P0、P2未使用不扩展外部存储器留空RAM 的划分也值得提前定下来别写到一半再回头改。30H 拿来做按键键值的暂存单元40H 和 41H 是给 MAX7219 写数据用的「数据口」和「地址口」50H 到 59H 这 10 个字节正好放 5 组记录、每组占 2 字节秒和百分秒各一个堆栈指针 SP 设到 60H。把 SP 放在 60H 是有讲究的20H 到 2FH 是位寻址区30H 到 7FH 才是普通用户 RAM堆栈从 60H 往上长既避开了工作寄存器组也给子程序嵌套留了 32 字节深度六层调用绰绰有余。2.2 为什么不用三极管动态扫描改用 MAX7219四位共阴数码管最省钱的做法是直接拿 I/O 口怼8 根段选线加 4 根位选线共 12 根口线位选线上再挂 4 只三极管做电流放大。这个做法在很多课程设计里能跑通但代价藏在细节里——每 1 到 2ms 必须刷新一次否则肉眼就能看见闪烁刷新只能放在定时中断里做主循环稍微写长一点显示就开始抖亮度调节得靠改占空比或者改限流电阻调起来全靠试。对一份要答辩的方案来说这些都是说不清的地方。换成 MAX7219 之后分工变得干净单片机把要显示的数字通过三根线写进它的内部寄存器剩下的事情它自己做。这颗芯片内部有 8×8 的静态 RAM 存每一位的数据有多路扫描回路自动轮询 8 位数字有片上的 BCD 译码器把 0 到 9 直接翻成七段码还有一个亮度寄存器和扫描位数寄存器。也就是说只要写一次数据数码管就一直亮着单片机哪怕在跑一段死循环显示也不会灭。方案占用 I/O是否要软件刷新亮度调节额外器件直接动态扫描12 根要1~2ms 一次改电阻或占空比4 只三极管 限流电阻74HC595 级联3 根要依旧靠软件刷靠 PWM 改占空比2 片 595MAX72193 根不要硬件自动扫描寄存器 0~15 共 16 级1 片 7219 1 只电阻代价也要说清楚多一片 24 脚的 DIP 芯片成本比四只三极管高三根线的写时序必须自己写16 位数据一位一位移出去时序错一位显示就全乱。我个人的判断是这笔交易对课设非常划算——省下来的 9 根 I/O 和中断里的刷新时间换成的是「显示永远稳」这个答辩时最容易被追问的点。2.3 器件清单与引脚分配把清单先列出来采购和焊接的时候不容易漏。核心器件就四类主控 AT89C51 一片、显示驱动 MAX7219 一片、四位共阴数码管 7SEG-MPX4-CC 一只、11.0592MHz 石英晶振一只其余都是阻容和按键。器件型号/参数数量作用单片机AT89C511计时、键盘、写显示显示驱动MAX72191多路扫描、BCD 译码、段驱动数码管7SEG-MPX4-CC1四位共阴显示晶振11.0592MHz1时钟基准瓷片电容33pF2晶振负载电容电解电容10μF1复位电路电阻10kΩ2复位下拉、ISET 限流轻触按键6×6 直插6人机输入引脚分配是这份方案里最不能含糊的一页。P3.0 接 DIN串行数据输入P3.1 接 LOAD装载/片选P3.2 接 CLK串行时钟P1.0 到 P1.5 依次接开始、暂停、记录、下翻、上翻、复位。这里有一处必须提前想明白P3.0 和 P3.1 同时是串口的 RXD 和 TXD占掉它们就等于放弃了串口通信。如果后续想加「把计时结果发给上位机」这类功能正确的做法是把 DIN 和 LOAD 挪到 P2.0、P2.1CLK 保留在 P3.2 或者一起挪走别等到焊完了才发现串口调不通。3. 硬件总体设计晶振、复位、键盘、显示四路电路怎么接3.1 系统方框图与信号流向整个系统可以画成一个以 AT89C51 为中心的放射结构四条支路各司其职。左上角是时钟电路晶振跨接在 XTAL1 和 XTAL2 之间两只 33pF 电容分别从这两个引脚接地左下角是复位电路10μF 电容正极接 VCC、负极接 RST 引脚一只 10kΩ 电阻从 RST 拉到地复位按键并联在电容两端右侧是三线串行的 MAX7219它再往下用 8 根位选线和 8 根段选线去推四位共阴数码管下方是键盘六只按键一端接 P1 口、一端接地。信号流向顺着这个结构走一遍就清楚了晶振给单片机提供机器周期定时器 T0 在这个节拍上数到 9216 就产生一次中断中断里累加秒和百分秒主循环不停扫描 P1 口识别到按键就修改计时状态或者读写记录区无论是中断还是按键改了数值最终都通过 P3.0 到 P3.2 这三根线把「地址 数据」的 16 位组合推进 MAX7219由它负责把数字变成七段码并轮流点亮四位数码管。整个链路里没有任何需要 CPU 持续参与的环节这也是这套结构最舒服的地方。3.2 晶振电路与复位电路的参数取值晶振选 11.0592MHz 而不是随手抓一只 12MHz理由要讲在明处。12MHz 下机器周期是 1μs10ms 对应 10000 个机器周期初值 65536−10000 55536也就是 0xD8F0同样能算得整整齐齐11.0592MHz 下机器周期是 12/11.0592 ≈ 1.0851μs10ms 对应 9216 个机器周期初值 65536−9216 56320即 0xDC00。两者都能做到 10ms 无误差区别在于 11.0592MHz 是 9600 波特率的整数倍频以后要加串口时不用为波特率误差头疼。所以别迷信「必须 11.0592」关键是初值要和晶振配套算换了晶振不换初值秒表就走不准。复位电路采用按键电平复位。上电瞬间电容相当于短路RST 被拉到接近 VCC 的高电平随着电容通过 10kΩ 电阻充电RST 电压按 RC 时间常数下降10kΩ 乘 10μF 等于 0.1 秒远大于 AT89C51 要求的两个机器周期复位脉宽所以上电一定能可靠复位。按键按下时电容被短接放电RST 又变高松开后重新充电这就是手动复位。这里常见的翻车是把电容选成 1μFRC 只有 10ms上电时电源还没稳复位脉冲已经结束单片机会跑飞到不知道哪里去反过来选 100μF复位时间太长按下按键要愣一秒才有反应答辩演示时很尴尬。3.3 键盘电路与六个按键的职责键盘用最朴素的独立按键接法六只轻触开关一端统一接地另一端分别接 P1.0 到 P1.5。AT89C51 的 P1 口内部自带上拉电阻按键没按下时读回来是 1按下时被拉到地读回来是 0不需要外接上拉。这个接法的好处是电路简单到不需要原理图坏处是没有任何硬件消抖按下和松开的瞬间触点会弹跳几毫秒读回来是一串 0 和 1 的乱跳。六个键的职责必须一次定死写代码时才好对号入座引脚键名按下后的动作P1.0开始置位 TR0定时器启动秒表开始走P1.1暂停清零 TR0停止计时同时把当前值存入记录区P1.2记录把当前计时值另存一组用于双计时对比P1.3下翻查看记录区里后一组数据P1.4上翻查看记录区里前一组数据P1.5复位清零 TR0秒和百分秒全部归零回到 00.00暂停和记录这两个键容易混淆设计上要划清界限暂停是「停表并存档」记录是「不停表也能存」。如果只做一个键赛场上就会出现「想看看刚才那圈成绩结果把正在跑的计时打断了」这种问题。3.4 显示电路位选、段选与小数的处理数码管选 7SEG-MPX4-CC型号里的 MPX4 表示四位一体CC 表示共阴也就是每一位的公共端要接低电平才亮。MAX7219 的 DIG0 到 DIG3 接数码管的四位公共端SEG A 到 SEG G 加 DP 接八段段选注意 7219 的段驱动是「输出低电平点亮」和共阴管正好匹配不用再加反相器。ISET 引脚通过一只 10kΩ 电阻接到 VCC这只电阻决定段电流大小阻值越小越亮、芯片越热调试时如果觉得刺眼把电阻换大一点就行别去动程序里的亮度寄存器——那是两回事。小数点的处理是这份方案里一个容易被忽略的细节。00.00 的显示需要一个点分隔秒和百分秒做法是在送第二位秒的个位数据时把最高位 D7 置 1。MAX7219 在 BCD 译码模式下只译码低 4 位D7 独立控制小数点所以往寄存器 2 写 0x8X 就会出现「X.」的效果。如果采用全译码模式寄存器 0x09 写 0xFF送进去的数字只需要 0 到 9 本身段码表根本不需要如果采用不译码模式才需要自己维护一张共阴段码表。两种方式只能选一种混用的后果在第五章会专门讲。4. 软件落地10ms 定时中断、拆位显示与 MAX7219 写时序4.1 定时器 T0 方式 1 的初值计算与中断服务定时器用方式 1也就是 16 位定时器不用方式 2 的自动重装8 位最多只能定 256 个机器周期凑不出 10ms。初值算法很直接需要的机器周期数 10ms ÷ 机器周期11.0592MHz 下等于 9216用 65536 减掉就是 56320拆成高八位 0xDC、低八位 0x00。计数器从这里数到 65536 溢出正好 9216 个机器周期也就是 10.000ms。ORG 0000H LJMP MAIN ORG 000BH ; T0 中断入口 LJMP IT0P MAIN: MOV SP, #60H ; 堆栈避开位寻址区和工作寄存器组 MOV TMOD, #01H ; T0 方式116位定时 MOV TH0, #0DCH ; 10ms 初值高字节 MOV TL0, #00H ; 10ms 初值低字节 SETB EA ; 开总中断 SETB ET0 ; 开 T0 中断 LCALL INIT_7219 ; 初始化显示驱动 MOV R4, #0 ; R4 秒00~99 MOV R5, #0 ; R5 百分秒00~99 SETB TR0 ; 上电即开始计时 SJMP $ ; 主循环只做键盘扫描 IT0P: PUSH PSW PUSH ACC MOV TH0, #0DCH ; 方式1不自动重装必须软件重装 MOV TL0, #00H INC R5 ; 每 10ms 百分秒加一 CJNE R5, #100, T0_DISP MOV R5, #0 INC R4 ; 满 100 次进位成 1 秒 CJNE R4, #100, T0_DISP MOV R4, #0 ; 99 秒后回到 00形成循环 T0_DISP: LCALL XS0 ; 刷新前两位 LCALL XS1 ; 刷新后两位 POP ACC POP PSW RETI这段代码有几个地方值得停一下。重装初值写在中断服务的最前面是为了让「响应中断 重装」这段固定延迟尽量短虽然每次会多花几个机器周期但 100 次累计下来误差还不到千分之一用手机秒表对 60 秒都看不出差别。R4 和 R5 用的是工作寄存器中断里必须 PUSH PSW 保护寄存器组选择位否则主循环里如果用到了另一组 R 寄存器返回后就会拿到被改过的值这种 bug 查起来非常玄学。还有一点显示刷新放在中断里而不是主循环里是因为中断每 10ms 一定发生一次刷新节奏天然稳定如果放主循环键盘扫描稍微慢一点数码管就开始闪。4.2 四位数码管的拆位显示R4 里存的是 0 到 99 的秒数要显示成两位十进制最省事的办法是用 DIV 指令。把 R4 送进 AB 装 10执行 DIV AB 之后 A 里是商十位、B 里是余数个位分别送给第 1 位和第 2 位。R5 同样处理商送第 3 位、余数送第 4 位。这样就不需要写循环减法两条指令解决。; 把 R4秒拆成两位送到数码管 1、2 XS0: MOV B, #10 MOV A, R4 DIV AB ; A 十位B 个位 MOV 40H, A ; 待写数据 MOV 41H, #01H ; 寄存器地址 1对应 DIG0 LCALL WRIT_7219 MOV A, B ADD A, #80H ; D7 置 1点亮小数点作分隔 MOV 40H, A MOV 41H, #02H ; 寄存器地址 2对应 DIG1 LCALL WRIT_7219 RET ; 把 R5百分秒拆成两位送到数码管 3、4 XS1: MOV B, #10 MOV A, R5 DIV AB MOV 40H, A MOV 41H, #03H LCALL WRIT_7219 MOV A, B MOV 40H, A MOV 41H, #04H LCALL WRIT_7219 RET这里的前提是 MAX7219 工作在 BCD 译码模式送 0 到 9 它自己翻成七段码所以代码里看不到段码表。如果改用不译码模式就得在 DIV 之后加一步查表MOV DPTR, #TAB然后MOVC A, ADPTRTAB 表里按 0 到 9 的顺序放好共阴段码0x3F、0x06、0x5B、0x4F、0x66、0x6D、0x7D、0x07、0x7F、0x6F。两种写法都能跑选一种坚持到底。频率上不用担心四次写操作加起来不到 200 个机器周期10ms 的中断间隔里做这件事绰绰有余。4.3 MAX7219 初始化与 16 位写时序MAX7219 的通信协议是 16 位一帧高 8 位是寄存器地址低 8 位是数据高位先发。CLK 的每一个上升沿把 DIN 上的电平移进内部移位寄存器16 位收齐之后 LOAD 产生一个上升沿数据被锁存生效。时序的关键点是 LOAD 必须在整个 16 位发送期间保持低电平发完再拉高——这一点写反了显示就是全黑或者乱码。DIN BIT P3.0 ; 串行数据 LOAD BIT P3.1 ; 装载低电平期间接收数据 CLK BIT P3.2 ; 串行时钟上升沿移入 ; 写一帧41H 放地址40H 放数据 WRIT_7219: CLR LOAD ; 拉低准备接收 MOV A, 41H LCALL SEND_BYTE MOV A, 40H LCALL SEND_BYTE SETB LOAD ; 上升沿锁存 16 位 RET ; 从 A 中移出 8 位高位在前 SEND_BYTE: MOV R7, #8 SB_LP: CLR CLK RLC A ; 最高位进 CY MOV DIN, C SETB CLK ; 上升沿写入 DJNZ R7, SB_LP RET ; 上电初始化四步缺一不可 INIT_7219: MOV 41H, #09H MOV 40H, #0FFH ; 译码模式8 位全部 BCD 译码 LCALL WRIT_7219 MOV 41H, #0BH MOV 40H, #03H ; 扫描位数只扫 4 位 LCALL WRIT_7219 MOV 41H, #0AH MOV 40H, #07H ; 亮度0~15 取中间值 7 LCALL WRIT_7219 MOV 41H, #0CH MOV 40H, #01H ; 关断寄存器写 1退出休眠 LCALL WRIT_7219 RET四个初始化寄存器的顺序可以换但一个都不能少。0x09 决定译码方式0x0B 决定扫几位写 0x03 表示扫 4 位写 0x07 会扫 8 位后四位没接数码管就会看起来像缺位0x0A 决定亮度0x0C 是关断控制——芯片上电默认处于关断状态这一位不写 1前面三步全做完屏幕也是黑的。这几行是整个驱动里最像「开关」的部分恰恰也是新手最容易漏的部分。4.4 按键消抖与六键状态处理按键扫描的骨架是「读—比对—延时—再读」。先给 P1 口写 0xFF读之前先置高这是 51 的规矩读回一个值如果还是 0xFF 说明没按键直接返回如果有变化先把这个值存进 30H延时 10ms 再读一次两次一致才认为是真按下这叫软件消抖。10ms 这个数字不是拍脑袋轻触开关的抖动时间通常在 5 到 10ms取 10ms 能盖住绝大多数按键又不至于让人感觉迟滞。KEYIN: MOV P1, #0FFH ; 读前先写 1 NOP MOV A, P1 CJNE A, #0FFH, QUDOU ; 有变化去抖 LJMP KEYIN QUDOU: MOV 30H, A LCALL DELAY10 ; 延时 10ms MOV A, P1 CJNE A, 30H, KEYIN ; 两次不一致是抖动重来 JB P1.0, K1 ; 逐位判断谁按下走谁 LJMP PKEY0 ; 开始 K1: JB P1.1, K2 LJMP PKEY1 ; 暂停并存档 K2: JB P1.2, K3 LJMP PKEY2 ; 记录 K3: JB P1.3, K4 LJMP PKEY3 ; 下翻 K4: JB P1.4, K5 LJMP PKEY4 ; 上翻 K5: JB P1.5, KEYIN LJMP PKEY5 ; 复位还有一步不能省处理完一个按键必须等它松开再返回扫描循环否则手指按住 0.5 秒程序会把同一个键当成按了几十次秒表就在开始和暂停之间疯狂横跳。写法是循环读 P1 直到恢复 0xFF 才跳回 KEYIN。这一步加上之后按键手感才正常——按下去响应一次松手之后才接受下一次。血泪经验是消抖只做一半只延时、不等释放的方案在实验室里自己按能过答辩老师手重一点就原形毕露。4.5 五组记录的缓存与上下翻页记录功能的价值在于「双计时」和「多次成绩对比」所以缓存不能只留一个格子。50H 到 59H 这 10 个字节分成 5 组每组两个字节前一个存秒R4后一个存百分秒R5。用 R0 指向当前组的秒字节、R1 指向百分秒字节初始都指向第一组R0 50HR1 51H。按下暂停或记录键时把 R4、R5 分别写进 R0 和 R1然后 R0 和 R1 各加 2指向下一组。加 2 而不是加 1是因为一组占两个字节加 1 会让秒和百分秒错位翻页时显示出一组根本不存在的数据。指针越界要处理第 6 次记录时把 R0、R1 拨回 50H、51H覆盖最早的一组等于一个 5 格环形缓冲。工控场景里通常还会加一个「已存组数」计数器满了就不再覆盖并给出提示课设这个规模用环形覆盖足够。上翻和下翻就是把 R0、R1 按 ±2 移动然后从 R0 和 R1 里取值走一遍和 XS0、XS1 相同的拆位流程显示出来。这里有个细节要留意翻页显示的时候秒表的计时不能停中断里的 XS0、XS1 每 10ms 会把实时值刷上去翻页看到的数据瞬间就被冲掉。可行的做法是设一个「查看标志」标志置位时中断里跳过刷新只由翻页程序负责显示按复位或者开始键再清掉标志回到实时显示。这个标志位不加翻页功能就等于白做。5. 避坑清单调试台上最容易翻车的五个点5.1 现象数码管乱码数字缺段或者全亮原因几乎只有两个。一是译码模式和数据内容不匹配寄存器 0x09 写了 0xFF 开了全 BCD 译码程序里却又送了查表得到的段码比如 0x3F7219 只认低 4 位0x3F 的低 4 位是 0xF译出来就是乱码。二是 0x09 写了 0x00 关了译码程序里却直接送 0 到 9结果只亮一部分段。解决方式是在初始化里把模式定死然后全篇统一全译码模式送 0~9 加 0x80 表示小数点不译码模式则维护一张 10 个字节的共阴段码表两者的代码不能混着抄。5.2 现象计时偏快或偏慢跑一分钟差好几秒先查晶振和初值是否配套。用 12MHz 的晶振却按 11.0592MHz 算了 0xDC00机器周期从 1.0851μs 变成 1μs10ms 实际只走了 9.2ms秒表就快 8% 左右一分钟能差出五秒。反向搞错也一样换成 11.0592MHz 却用 12MHz 的初值 0xD8F0定时就变长。解决是把公式写死在心里机器周期 12 ÷ 晶振频率重装初值 65536 − 定时常数 ÷ 机器周期换晶振必须重算。另一个容易被忽略的点是中断里忘了重装初值方式 1 不会自动重装溢出后从 0 开始数那就慢得离谱了。5.3 现象按一次键秒表跳好几次或者状态乱跳抖动没消干净或者消抖做了但没等按键释放。现象很典型轻轻一碰就连续触发长按一下更是灾难。解决分两步一是延时 10ms 后二次确认电平二是处理完动作后死等 P1 恢复 0xFF 再返回。还有一种情况是按键接在 P3 口上又同时被复用成串口读到的电平根本不受按键控制这种只能改硬件接线软件补不回来。5.4 现象只有一位或者前两位亮后两位死活不亮先看扫描位数寄存器 0x0B。写成 0x00 只扫 1 位写成 0x07 会去扫 8 位后四位悬空看起来像坏了。正确值是 0x03四位。其次看位选线有没有接错顺序DIG0 对应的是最低位还是最高位取决于你写寄存器的顺序显示成「倒着读」的时候不用怀疑芯片把 XS0 和 XS1 里写的地址对调一下就好。最后看数码管是共阴还是共阳7SEG-MPX4-CC 是共阴如果错买了共阳的整块屏只会微弱发亮或者完全不亮。5.5 现象按下复位键数字还在跳或者残留旧值复位键的处理里有两个动作容易漏。一是没清 TR0定时器还在跑变量刚清零又被中断加回去屏幕上就看见 00.00 闪一下又往回跳二是只清了 R4、R5没有把记录区和显示缓冲一起清掉上翻的时候还能翻出上一轮的成绩。解决是把复位写成一个完整的「归零序列」先 CLR TR0 停表再清 R4、R5、记录区 50H~59H、记录指针 R0 和 R1最后调一次 XS0、XS1 把 00.00 写进 7219让屏幕立刻反映出来。6. 验收与答辩怎么用一张测试表证明你的秒表是准的答辩现场最怕的不是功能少而是说不清「它到底准不准」。我的做法是提前准备一张测试表当着老师的面按表操作一项一项打勾比嘴上说「能跑」有说服力得多。表格不用复杂四列足够测试项、操作方法、期望现象、判定依据。测试项操作方法期望现象判定依据上电初值接通 5V 电源显示 00.00无乱码、无缺位计时准确性与标准计时器同时启动跑 60 秒两者差值不超过 0.1 秒误差来自晶振精度肉眼不可辨开始/暂停按开始走 5 秒按暂停数字停住且不再变化连续观察 10 秒不动记录与翻页跑 3 组不同成绩后按上翻、下翻依次显示 3 组数据数值与当时读数一致复位计时中按复位立即回到 00.00 并停表无残留、不自动重启连续按压快速连按开始键 20 次状态不混乱每次按键只响应一次计时准确性这一项要单独讲方法。不要用眼睛看拿手机自带的秒表同时启动跑满 60 秒两个读数并排比对。如果差值在 0.1 秒以内说明定时初值和晶振配套正确如果差出好几秒直接回到 5.2 去查初值。老师如果追问「为什么能保证准」答案就一句话10ms 中断由晶振分频得来11.0592MHz 下 9216 个机器周期正好 10ms中断里立刻重装初值100 次进一位误差只来自晶振本身的精度跟程序无关。答辩时还有两个高频问题值得提前准备。一个是「为什么用 MAX7219 不直接驱动」回答要落到 I/O 数量和刷新占用上别只说「因为好用」。另一个是「如果要做 0 到 99 分钟怎么办」思路是把 R4 拆成分钟和秒两个字节中断里改成 6000 次进一分钟显示改到 6 位硬件上把扫描位数寄存器改成 0x05。能顺着现有结构说出改动点比背一遍代码强。从那以后我每次带人做这类计时类课设都强制走一遍「先定资源表、再定时序图、最后跑测试表」这三步不管题目多简单。因为翻车从来不是因为难而是因为觉得简单就跳过验证。希望帮到你。本文还有配套的精品资源点击获取