
简介一套基于AT89C51的00~99秒数码管秒表课程设计报告面向单片机初学者、物联网工程及相关专业学生适合课程设计、项目实践与期末答辩参考。报告以AT89C51单片机为核心结合MAX7219驱动芯片控制数码管显示完整覆盖秒表设计中的定时器/计数器原理、硬件电路搭建、软件程序设计以及万用板制作流程可实现正确计时、暂停、清零和数码管显示等功能对理解动态显示、按键处理、中断服务等知识点很有帮助。压缩包仅含1个doc文档大小915KB内容为完整设计报告包含设计目标、系统方框图、复位电路、晶振电路、显示电路、键盘电路等单元说明结构清晰便于按章节查阅。目前已有3605人学习浏览资源内容紧凑且实用性强对单片机秒表开发流程和课程设计报告撰写均有直接参考价值。1. 一次搞懂 00~99 秒数码管秒表AT89C51 加 MAX7219 的课程设计这份资源是一套以 AT89C51 为核心、用 MAX7219 驱动共阴数码管实现 00~99 秒显示的课程设计源码用汇编语言写成覆盖了定时器中断、键盘消抖、拆位显示和记录保存等完整流程。适合三类人刚学完定时器和中断、正在做课程设计的在校生手头有开发板但不想折腾动态扫描的电子爱好者以及需要把一个能暂停、保存、翻页的秒表方案快速搬到自己板子上的工程师。它的核心特点是把数码管扫描交给 MAX7219单片机只在 10ms 中断里维护两个计数变量工程量比传统 P0 口逐位扫描小很多也更容易调通。2. 硬件方案与电路拆分为什么是 AT89C51 MAX7219整个系统的信号流很直接AT89C51 的 P3 口用三根线把数据发给 MAX7219MAX7219 再驱动四位共阴数码管P1 口的六个按键给出开始、暂停、保存、上翻、下翻和复位指令。真正决定这套方案能不能稳定跑起来的是三块电路时钟、复位和显示接口。2.1 AT89C51 的选型理由4K Flash 与 P1 口内部上拉AT89C51 是带 4K 字节 Flash 存储器的低电压、高性能 CMOS 8 位微处理器指令系统与工业标准的 MCS-51 兼容。片内 Flash 可以反复擦除 1000 次课程设计期间改程序、重新烧录非常方便不需要像 8751 那样依赖紫外线擦除器。对秒表这种规模的项目4K 字节代码空间完全够用外部程序存储器、锁存器和地址译码器都可以省掉硬件电路会变得很干净。这款芯片有 4 个 8 位 I/O 口P0、P1、P2、P3。P0 口在扩展外部存储器时才承担数据总线和地址总线功能不扩展时做普通 I/O 用但内部没有上拉电阻做输出需要外接上拉排阻。P1 口不同它内部自带上拉电阻做输入时只要把引脚写成 1按键另一端接地按下时就会读到低电平。所以键盘电路全部放在 P1 口是最省事的做法不需要外部上拉软件里先MOV P1, #0FFH再读回来的值就是真实的按键状态。选择 AT89C51 还有一层原因它内部有定时器/计数器 T0可以工作在 16 位定时器模式溢出时触发中断。秒表的核心基准就靠它产生不需要额外的时钟芯片。最高振荡频率可以到 24MHz课程设计里选择 11.0592MHz 晶振一方面是因为这个频率是很多串口通信工具的常用频率另一方面它配合 T0 的初值可以精确分频出 10ms 时基。这部分在第三章会展开算一遍。2.2 MAX7219 显示驱动把动态扫描做成“黑匣子”如果不用 MAX7219直接拿单片机的 P0 和 P2 驱动四位共阴数码管最常见的结果是要么 I/O 口不够用要么动态扫描的刷新时序没处理好数码管亮度不均匀、甚至有拖影。MAX7219 是一种集成化的串行输入/输出共阴极显示驱动器内部包含 BCD 编码器、多路扫描回路、段字驱动器和 8×8 静态 RAM。对使用者来说只需要通过四线串行接口把地址和数据写进去芯片会自动完成位选扫描和段码输出。MAX7219 的四线接口分别是 DIN、LOAD、CLK以及用于级连扩展的 DOUT。DIN 是串行数据输入端LOAD 是装载数据控制端也就是片选信号CLK 是串行时钟输入数据在 CLK 上升沿被送入内部移位寄存器。DIG0~DIG7 用于从共阴极数码管吸入电流SEG A~SEG G 和 DP 输出段驱动。ISET 引脚通过一个 10kΩ 电阻接到 VCC用来设置段电流也就是决定数码管亮度。在这份课程设计里MAX7219 与单片机的连接方式如下MAX7219 引脚连接到 AT89C51DINP3.0LOADP3.1CLKP3.2ISET经 10kΩ 电阻接 VCCDIG0~DIG3四位共阴数码管位选SEG A~SEG G、DP数码管段选从软件角度看MAX7219 就是三个位引脚加一个串行协议。单片机不参与动态扫描只负责在秒数变化时把 7 段码数据写入芯片内部的显示 RAM。这样写出来的代码结构很清晰定时器负责计时主循环负责查键盘显示只在数值变化时更新。2.3 复位电路、晶振电路与键盘电路时基和输入都从这里来复位电路采用按键电平复位。AT89C51 的复位引脚 RST 保持两个机器周期以上的高电平就可以完成复位。电路里用一个 10uF 电解电容和一个按键并联上电瞬间电容充电RST 短暂保持高电平实现上电自动复位程序跑飞时按下复位按键RST 被强制拉到高电平实现手动复位。对于课程设计和实际调试这个“后悔药”很关键很多异常状态直接按一下复位就能回到起点。晶振电路由 XTAL1、XTAL2 外接石英晶体和两个 33pF 电容组成。单片机内部的高增益反相放大器与外部晶振构成自激振荡器电容 C1、C2 对频率有微调作用。这里选 11.0592MHz是为了让 T0 每 10ms 中断一次的计算值刚好落在整数上。晶振旁边尽量靠近单片机引脚走线要短否则可能出现起振困难或频率偏移。键盘电路用的是六个独立轻触按键。P1.0 是开始键P1.1 是暂停键P1.2 是保存键P1.3 是下翻键P1.4 是上翻键P1.5 是复位键。因为 P1 口有内部上拉按键另一端直接接地按下时对应引脚读到 0。硬件上不需要额外上拉电阻但要注意按键消抖不能省真实的机械按键在按下和释放瞬间会有 10ms 左右的抖动必须靠软件延时去抖否则一次按下会被识别成好几次。3. 软件框架与核心代码定时中断、MAX7219 写入和键盘消抖软件部分采用模块化设计主程序由初始化、显示、键盘查询和定时器中断组成。下面代码按报告整理其中DELAY10和WRIT_7219是补全的通用实现方便直接编译运行。位定义部分把 P3.0、P3.1、P3.2 分别映射为 DIN、LOAD、CLK后面所有程序都通过这三个位名操作 MAX7219。3.1 定时器 T0 的 10ms 中断初值计算与重装T0 工作在方式一也就是 16 位定时器。要让它在 11.0592MHz 晶振下每 10ms 溢出一次需要计算初值机器周期是 12 个振荡周期所以定时 10ms 需要 0.01s 除以 12/11.0592MHz等于 9216 个机器周期。16 位定时器计满需要 65536 个周期初值就是 65536 减 9216等于 56320即 0xDC00因此TH0#0DCH、TL0#00H。DIN BIT P3.0 LOAD BIT P3.1 CLK BIT P3.2 ORG 0000H LJMP MAIN ORG 000BH LJMP IT0P ORG 1000H MAIN: MOV SP, #60H MOV TMOD, #01H MOV TH0, #0DCH MOV TL0, #00H SETB EA SETB ET0 LCALL START LCALL KEYIN START: MOV 50H, #0 MOV 51H, #0 MOV 52H, #0 MOV 53H, #0 MOV 54H, #0 MOV 55H, #0 MOV 56H, #0 MOV 57H, #0 MOV 58H, #0 MOV 59H, #0 MOV R0, #50H MOV R1, #51H LCALL INIT_7219 MOV R4, #0 MOV R5, #0 MOV DPTR, #TAB LCALL XS0 LCALL XS1 RET IT0P: PUSH ACC PUSH PSW INC R5 MOV A, R5 CJNE A, #100, IT0P_END MOV R5, #0 INC R4 MOV A, R4 CJNE A, #100, IT0P_END MOV R4, #0 IT0P_END: MOV TH0, #0DCH MOV TL0, #00H POP PSW POP ACC RETI这里的关键参数是 TMOD 和中断重装。TMOD#01H表示 T0 工作在 16 位定时器方式GATE 位为 0由 TR0 直接控制启动。中断服务程序里维护两个变量R4 存放秒值 0~99R5 存放百分秒值 0~99。每进入一次中断R5 加 1加到 100 时清零并向秒进位。99 秒再加 1 时变回 00符合两位数码管显示范围。初值重装必须放在中断末尾而且最好在保存现场和恢复现场之间完成。如果重装放在主循环里一旦按键处理子程序执行时间过长下一次定时器溢出会提前发生计时就会偏快。3.2 MAX7219 写入时序16 位数据包与寄存器配置MAX7219 的每一次写入都包含 16 位串行数据其中高 8 位是寄存器地址低 8 位是写入值。地址从高位开始发送对应 DIG0 的是 0x01DIG1 是 0x02依次类推。这份课程设计用 4 位数码管所以显示寄存器地址就是 0x01、0x02、0x03、0x04。程序中用 41H 存放地址、40H 存放数据每次调用WRIT_7219完成一次 16 位写入。WRIT_7219: CLR LOAD MOV A, 41H LCALL SEND_BYTE MOV A, 40H LCALL SEND_BYTE SETB LOAD RET SEND_BYTE: MOV R6, #08H SEND_LOOP: RLC A MOV DIN, C SETB CLK CLR CLK DJNZ R6, SEND_LOOP RET INIT_7219: MOV 41H, #0CH MOV 40H, #01H LCALL WRIT_7219 MOV 41H, #09H MOV 40H, #00H LCALL WRIT_7219 MOV 41H, #0AH MOV 40H, #05H LCALL WRIT_7219 MOV 41H, #0BH MOV 40H, #03H LCALL WRIT_7219 RETWRIT_7219先把 LOAD 拉低然后逐位发送地址字节和数据字节全部发完再把 LOAD 拉高。MAX7219 在 LOAD 上升沿锁存这批数据所以 LOAD 的电平顺序不能反。初始化时依次配置了四个关键寄存器0x0C 地址写入 0x01让芯片从关闭模式进入正常操作模式0x09 地址写入 0x00关闭硬件译码直接用软件查表得到的 7 段码0x0A 地址写入 0x05把亮度设为中间值0x0B 地址写入 0x03设置扫描限制为 4 位只点亮 DIG0 到 DIG3。如果把 0x09 写为 0xFFMAX7219 会开启 BCD 译码模式数字位可以直接发送 0~9。但这份程序要显示小数点和自定义效果所以用无译码模式显示数据全部来自段码表。千万注意写入段码时要在共阴数码管的段码表基础上查表否则会出现亮灭反相的问题。3.3 键盘查询10ms 消抖和等待释放键盘查询是一个死循环。在没有按键按下时P1 口读回来是 0xFF程序一直循环等待。检测到按键后先用 30H 保存第一次读到的值延时 10ms 再读一次两次一致才认为按键有效。这个设计可以滤掉机械抖动带来的毛刺也可以避免人体感应造成的误触发。KEYIN: MOV P1, #0FFH NOP MOV A, P1 CJNE A, #0FFH, QUDOU LJMP KEYIN QUDOU: MOV 30H, A LCALL DELAY10 MOV A, P1 CJNE A, 30H, KEYIN KEY0: MOV C, P1.0 JC KEY1 LJMP PKEY0 KEY1: MOV C, P1.1 JC KEY2 LJMP PKEY1 KEY2: MOV C, P1.2 JC KEY3 LJMP PKEY2 KEY3: MOV C, P1.3 JC KEY4 LJMP PKEY3 KEY4: MOV C, P1.4 JC KEY5 LJMP PKEY4 KEY5: MOV C, P1.5 JC KEYIN LJMP PKEY5消抖子程序用两层循环实现大约 10ms 延时。对 11.0592MHz 晶振下面这个循环在 10ms 左右按键确认已经够用。DELAY10: MOV R7, #20 DELAY_LOOP: MOV R6, #250 DJNZ R6, $ DJNZ R7, DELAY_LOOP RET按键处理程序在确认按键有效后会继续轮询 P1 口直到按键释放才执行动作。这一条非常重要。例如开始键 PKEY0 的代码里先循环判断CJNE A, #0FFH, PKEY0等 P1 恢复成全 1 后才SETB TR0。这样做的原因是如果不等待释放长按一个键会被重复识别成多次按下秒表会连续跳秒。3.4 拆位显示DIV AB 与段码表结合秒值 R4 和百分秒值 R5 都是 0~99 的两位十进制数要送到四位数码管显示需要把每个数拆成十位和个位。汇编里最直接的办法是使用DIV AB。执行后A 中是商也就是十位B 中余数是个位。查段码表后分别写入 MAX7219 的 0x01 和 0x02 地址就完成了前两位显示。TAB: DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH XS0: MOV B, #10 MOV A, R4 DIV AB MOVC A, ADPTR MOV 41H, #01H MOV 40H, A LCALL WRIT_7219 MOV A, B MOVC A, ADPTR ADD A, #80H MOV 41H, #02H MOV 40H, A LCALL WRIT_7219 RET XS1: MOV B, #10 MOV A, R5 DIV AB MOVC A, ADPTR MOV 41H, #03H MOV 40H, A LCALL WRIT_7219 MOV A, B MOVC A, ADPTR MOV 41H, #04H MOV 40H, A LCALL WRIT_7219 RET段码表 TAB 中的值是共阴数码管 0~9 的标准 7 段码。ADD A, #80H是在显示 R4 个位时把小数点段点亮所以实际显示效果是“秒.百分秒”例如 12.34。第三、第四个数码管显示百分秒 R5但这里不再加小数点因为百分秒不需要与秒分隔中间的自然间隔已经够清楚。WAIT这有个细节第一位和第二位是秒值的十位和个位第三和第四位是百分秒。报告原文里 R4 对应前两位R5 对应后两位与这个解释一致。显示刷新策略是每次 R4 或 R5 变化后调用一次 XS0 或 XS1不是反复刷屏。由于 MAX7219 内部有 RAM 锁存刷一次后芯片会持续输出单片机不需要在主循环里不停扫描。4. 从仿真到万用板照着搭一套能跑的课程设计硬件连接和软件框架都清楚了接下来就是动手。课程设计报告里除了原理图还包含 Proteus 仿真思路和万用板制作过程。实际做的时候我建议按“先仿真再焊板后烧录”的顺序走避免一次翻车找不着北。4.1 器件清单与资源结构这份资源对应的硬件清单如下按 PCB 焊接顺序排列序号器件规格/型号数量1单片机AT89C5112显示驱动MAX721913数码管7SEG-MPX4-CC四位共阴14晶振11.0592MHz15瓷片电容33pF26电解电容10uF17电阻10kΩ18轻触按键6×6 或 12×1269万用板、排针、导线若干-报告里一般会附完整原理图、PCB 或仿真图、汇编源码和设计文档。源码中已经把位定义、主程序、中断服务、显示子程序、键盘子程序都划分好拿到后可以先在 Proteus 里跑一遍确认功能正常再焊实物。4.2 先在 Proteus 里跑通避免直接焊板子“翻车”Proteus 仿真可以把硬件接线错误提前暴露出来。搭建步骤很简单新建工程从元件库中搜索 AT89C51、MAX7219、7SEG-MPX4-CC、BUTTON、RESISTOR、CAPACITOR 等器件。按第二章的引脚连接表连线。P3.0 接 DINP3.1 接 LOADP3.2 接 CLK。将晶振设置为 11.0592MHz电容设置为 33pF。双击 AT89C51加载用汇编器编译生成的 HEX 文件。点击运行按下 P1.0 对应的按键观察数码管是否从 00.00 开始每秒加 1。如果 Proteus 版本较旧、元件库找不到 MAX7219常见做法是换用较新的版本或者用 74HC595 做替代验证。要注意 MAX7219 是共阴驱动如果仿真库里用的是共阳数码管段码表需要按共阳反相计算否则显示出来全是反的。4.3 焊接顺序与上电检查先保证电源和地线干净万用板焊接和普通模块搭线不同我一般按以下顺序先焊单片机插座把电源和地线单独走粗线再焊晶振电路和复位电路然后焊 MAX7219、数码管和按键。为什么最后焊数码管因为 MAX7219 的 ISET 引脚如果虚焊数码管亮度会异常提前把电源和驱动芯片的供电确认好排错范围会小很多。上电前先用万用表蜂鸣档测 VCC 和 GND 之间是否短路。这一步能避免很多“烧录没反应、数码管全亮”的灵异现象。确认不短路后再给 MAX7219 的 ISET 引脚接 10kΩ 电阻到 VCC。这个电阻值不要太随意段电流靠它决定电阻过大数码管偏暗过小偏亮甚至长期过热。焊接按键时要注意方向。轻触按键的四只引脚两两互通如果分不清公共端按下时可能永远读不到低电平。有一个简单的检查方法按下按键后用万用表导通档量任意两只引脚能导通的那对才属于同一开关组。4.4 烧录与运行HEX 文件怎么进入芯片AT89C51 内部有 4K Flash程序编译成 HEX 文件后需要通过支持的编程器写入芯片。对于课程设计常见做法是把芯片从万用板上取下来放入编程器烧写再放回去也有带 ISP 功能的版本但 AT89C51 本身没有串口下载能力严格来说都要走并行编程或专用编程器。烧录前确认三件事芯片型号选对HEX 文件路径正确编程器写入完成后做了校验。芯片插回板子后EA/VPP 引脚必须接高电平否则单片机会从外部程序存储器取指内部 Flash 里的代码不执行。上电后按一下复位键再按 P1.0 开始正常现象是数码管从 00.00 开始走秒。5. 调试与避坑数码管不亮、秒数乱跳的排查记录把工程项目从“仿真能跑”变成“实物能跑”中间往往要踩几个坑。下面五条是我在实际调试中遇到过的典型问题每一条都按现象、原因、解决三个步骤来写。5.1 现象MAX7219 驱动的数码管全亮或显示乱码最常遇到的状况是一上电数码管全亮数字完全不是预期的秒数。这个时候先不要怀疑代码先看硬件。MAX7219 的 LOAD 脚如果悬空或接触不良16 位数据会被分成两次错误锁存显示自然就乱了。原因通常有三个LOAD 信号没有在发送完 16 位数据后才拉高DIN 和 CLK 两根线接反供电电压低于 4V芯片内部逻辑不稳定。解决方法是先用万用表量 P3.0、P3.1、P3.2 到 MAX7219 对应引脚的导通情况再用示波器看 CLK 上是否有连续脉冲。如果示波器不方便也可以写一个固定的段码写入测试程序把 0x3F 写到 DIG0如果能稳定显示数字 0说明时序链路是通的。5.2 现象秒表每一分钟都快几秒或慢几秒秒表计时不准第一反应是晶振不对。报告里明确要求 11.0592MHz 晶振配TH0#0DCH、TL0#00H这样每次中断正好 10ms。如果板子上实际用的是 12MHz 晶振按照同样初值计算每次中断只有 9.216ms100 次中断只有 0.9216 秒一分钟差不多快 5 秒。反过来如果用 6MHz 晶振又会偏慢。解决方法是先确认晶振频率再按实际频率反推初值。初值计算公式是65536 减去定时周期除以机器周期。机器周期等于 12 除以晶振频率。重装初值必须放在中断服务程序里主循环重装会因为键盘查询时间不稳定而引入随机误差。如果实测误差固定说明晶振频率和程序初值不匹配如果实测误差忽快忽慢优先检查晶振旁边的 33pF 电容是否漏焊、虚焊。5.3 现象按一下开始键秒表连续跳了好几秒按键按下一次系统却识别成多次本质是消抖逻辑不完整。单纯的延时消抖只能滤掉按下瞬间的抖动如果程序没有等待按键释放长按或松开瞬间的二次抖动会被当成新按键。解决方法是坚持“按键处理前等待释放”的原则。第一次读 P1 后延时 10ms再次读值一致才确认确认有效后在功能代码开头继续循环CJNE A, #0FFH, 功能号等 P1 恢复为 0xFF 再执行SETB TR0或CLR TR0。这样无论按得快还是按得慢一次按下只触发一次动作。5.4 现象断电重启后保存的数据全部清零这份设计把记录数据放在 50H 到 59H一共 5 组。问题是 50H 这些地址是单片机内部 RAM掉电后内容不保留而且 START 初始化子程序每次复位都把 50H~59H 清零。所以保存的数值只能在同一上电周期里查看断电后就没了。理解这个边界很重要。课程设计报告里写的保存、上翻、下翻功能本质是在“本次运行期间保存 5 组时间”不是掉电保存。如果你需要真正的断电保存常见做法是外接 AT24C02 这类串行 EEPROM或者改用带片内 EEPROM 的单片机。这一点拿去答辩时也要主动说清楚否则老师会追问。5.5 现象烧录成功后芯片没有任何反应程序烧录校验通过但芯片装在板子上不动作。这个时候先量 EA 引脚AT89C51 的 EA/VPP 必须接 VCC它决定 CPU 从片内 ROM 还是外部 ROM 取指。EA 悬空或接地单片机会到外部去取指令而外部没有程序存储器程序自然跑不起来。另外检查复位电路。上电瞬间 RST 需要高电平持续两个机器周期如果 10uF 电容虚焊或按键短路复位信号可能一直保持高电平芯片永远停在复位状态。常见判断方法是上电后用万用表量 RST 电压正常工作时应该接近 0V按下复位按键时接近 5V。如果 RST 始终是 5V程序是不可能运行的。6. 扩展与验证双秒表记录、99 秒进位和误差校准这份秒表资源做到 00~99 秒显示只是基础功能。报告里增加了保存、暂停、上翻和下翻实际使用可以把 R0、R1 看作记录指针。R0 指向保存秒的地址R1 指向保存百分秒的地址初始分别是 50H 和 51H。每保存一组把 R0 加 2、R1 加 2就能把 5 组数据依次写进 50H~59H。上翻和下翻按键在查询状态下修改 R0、R1 的偏移量再把对应内存里的值送到数码管显示。这样做的好处是逻辑简单缺点是需要自己在显示函数里加一个“回放模式”标志不然会把当前秒数和记录数值混在一起。验证计时精度时不要只在程序里看。我的习惯是把秒表做成“计圈”一个标准秒表同时计时运行 60 秒后对比。如果误差是固定值说明晶振频率偏移或初值计算有偏差。更精确的办法是不焊接 11.0592MHz 晶振的 33pF 微调电容前先用频率计测一下晶振输出没有频率计可以把某个引脚配置成每 10ms 翻转一次用示波器量翻转频率换算后就知道实际中断周期。测得每 100 次中断的实际时间如果是 1.003 秒就把 TH0/TL0 初值整体微调比如减少几个计数周期来补偿。还有一种更实用的验证思路先把所有显示和按键功能断开只保留定时器中断在中断里加一个对 P3.7 的电平翻转然后用示波器看 P3.7 的周期。中断频率稳定说明时基没问题再接入显示和键盘中断频率不稳则先查晶振和复位电路。从那以后我每次拿到单片机课设都强制自己先写一个最小可运行版本只跑定时器、只刷一个数码管、只接一个按键跑通了再往上加暂停、保存、翻页。这个习惯帮我省掉了大量“最后十分钟找不到 bug”的尴尬。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。