简介:这份资源是西南科技大学计算机科学与技术专业《单片微机原理及应用》课程设计2的完整设计报告,面向正在学习51单片机、需要完成课程设计或准备单片机实验考核的本科生。报告围绕AT89C51外部中断应用展开,涵盖中断源与中断标志、中断类型号、IE与IP寄存器配置、中断初始化程序及中断函数编写等知识点,并给出声光报警器的电路原理图、主程序与中断服务程序流程图及关键代码解析。压缩包内仅含1个docx文档,约477KB,按课程设计报告册规范排版,包含知识要求、能力要求、设计目标与任务、电路设计、程序设计思路、代码实现和总结等章节,可直接作为报告撰写模板与实验参考。已有89人学习,适合需要理清中断法与查询法差异、掌握按键响应与数码管、蜂鸣器联动控制的学生对照仿写与查漏补缺。
1. 从两颗按键说起:为什么声光报警器是练中断的最佳切口
单片机课程设计里最容易被写成"流水账"的题目,就是外部中断。原因很简单:需求只有两行字——按 K1 亮一号灯、按 K2 亮二号灯——但真要把它做成一份能过验收的设计报告,中间隔着一整套东西:中断源怎么选、IE 和 IP 寄存器哪几位该置 1、下降沿触发和电平触发差在哪、中断服务程序里能不能写长延时。这套 AT89C51 外部中断声光报警器的方案,就是把 2 个按键、2 个发光二极管、1 个数码管和 1 个蜂鸣器拼成一个小系统,用 K1/K2 走外部中断 INT0/INT1,用 K3/K4 走查询法,让两条技术路线在同一个工程里对照着跑起来。它适合正在做单片微机原理课程设计、需要交一份带电路图、流程图、代码和仿真结果的学生,也适合手头有个 8051 小控制板、想把中断机制重新捋一遍的从业者。
2. 需求拆解与器件选型:四个指示器件怎么挂到 AT89C51 的引脚上
题目给的功能描述很朴素,初始状态两个灯灭;K1 按下后数码管显示 1、D1 闪烁、蜂鸣器报警;K2 按下后数码管显示 2、D2 闪烁、蜂鸣器报警。真正落到原理图上,第一个要决定的事情不是写代码,而是每个器件占哪个引脚。引脚一旦定错,后面代码里所有的sbit声明、段码表、中断向量号都要跟着返工,这是最容易在第二周推倒重来的地方。
2.1 从功能清单反推引脚分配表
我一般会先把功能清单摊成一张表,左边写"这个器件要干什么",右边写"它必须挂在哪个引脚上",判断依据是引脚的复用功能,而不是布线方便。AT89C51 的 P3 口是第二功能口,P3.2 和 P3.3 分别复用为外部中断 0(INT0)和外部中断 1(INT1),K1、K2 必须落在这两个脚上,否则中断源就无从谈起。K3、K4 走查询法,放 P3.4、P3.5 就够,也可以挪到 P1 口,但放在 P3 剩下的脚上布线更整齐。
| 器件 | 引脚 | 有效电平 | 说明 |
|---|---|---|---|
| D1~D4 | P2.0~P2.3 | 低电平点亮 | P2 灌电流能力强,低电平驱动 LED 更稳 |
| 蜂鸣器 | P1.6 | 由程序翻转 | 经三极管驱动,不直连 IO |
| 数码管 a~g、dp | P0.0~P0.7 | 低电平点亮 | 共阳极接法,P0 需外接 10k 上拉排阻 |
| K1 | P3.2 / INT0 | 低电平有效 | 下降沿触发,内部上拉 |
| K2 | P3.3 / INT1 | 低电平有效 | 下降沿触发,内部上拉 |
| K3 | P3.4 | 低电平有效 | 查询法读取 |
| K4 | P3.5 | 低电平有效 | 查询法读取 |
| RST | RST | 高电平复位 | 10μF 电容 + 10k 电阻构成上电复位 |
| XTAL1/XTAL2 | 18、19 脚 | — | 12MHz 晶振 + 两只 30pF 瓷片电容 |
| EA | 31 脚 | 接 VCC | 使用片内程序存储器时必须拉高 |
这张表里有两个容易被忽略的点。一是 EA 脚,很多仿真图里忘了接,Proteus 里可能还能跑,一上实物就取不到指令,程序像"死"了一样;二是 P0 口,它内部没有上拉场效应管,做普通 I/O 输出时必须外加排阻,否则数码管亮度发虚甚至完全不亮。通常的做法是在 P0 和 VCC 之间挂一个 10k 的排阻,成本两毛钱,能省掉半天的排查。
2.2 数码管共阳共阴与段码推导
数码管的段码是这份设计里唯一需要"算"的东西,也是答辩时老师最爱问的地方。七段数码管的 a、b、c、d、e、f、g 七段分别对应端口的最低位到第六位,最高位留给小数点 dp。本设计用的是共阳极数码管,公共端接 VCC,所以某一段要亮,对应的端口位就必须输出 0,这就是"低电平有效"的由来。
以数字 1 为例:只需要 b、c 两段亮,其余段灭。按 a→bit0、b→bit1、c→bit2、d→bit3、e→bit4、f→bit5、g→bit6、dp→bit7 的顺序排列,得到二进制 1111 1001(bit0 是 a 段灭=1,bit1 是 b 段亮=0,bit2 是 c 段亮=0,其余全灭=1),转成十六进制就是 0xF9。同理,数字 2 需要 a、b、d、e、g 五段亮,得 1010 0100 即 0xA4;数字 3 需要 a、b、c、d、g 亮,得 1011 0000 即 0xB0;数字 4 需要 b、c、f、g 亮,得 1001 1001 即 0x99。熄灭全部段就是 0xFF。
| 显示字符 | 点亮段 | 二进制(dp g f e d c b a) | 十六进制 |
|---|---|---|---|
| 1 | b、c | 1111 1001 | 0xF9 |
| 2 | a、b、d、e、g | 1010 0100 | 0xA4 |
| 3 | a、b、c、d、g | 1011 0000 | 0xB0 |
| 4 | b、c、f、g | 1001 1001 | 0x99 |
| 熄灭 | 无 | 1111 1111 | 0xFF |
把这五个值做成code数组存进程序存储器,比在中断里写死P0 = 0xF9更耐改。code是 Keil C51 的关键字,表示数据放在 ROM 里,不占宝贵的 128 字节 RAM,这一点在 8051 上不是可选项而是常识。段码表用code修饰,数组下标就是要显示的数字,取值即段码,扩展成 0~9 也不用改逻辑。
2.3 蜂鸣器与发光二极管的驱动余量
单片机 IO 口的拉电流能力通常只有几十微安,灌电流能力强得多,能到十几毫安。所以 LED 用低电平点亮是合理的:P2 口输出 0,电流从 VCC 经 LED 和限流电阻灌进引脚。限流电阻一般取 330Ω~1kΩ,取 330Ω 时电流约 5mA,八个段同时点亮时 P0 口的总灌电流要控制在不超出手册给出的上限,数码管每一位串一只 330Ω 电阻即可。
蜂鸣器不一样,它是感性负载,直接挂在 P1.6 上轻则声音微弱,重则把端口管子击穿。通常的做法是用一只 PNP 三极管(比如 S8550)做开关:发射极接 VCC,集电极接蜂鸣器负极,蜂鸣器正极接 VCC,基极经 1kΩ 电阻接 P1.6。程序输出低电平时三极管导通,蜂鸣器得电。这里要区分有源和无源:有源蜂鸣器内部带振荡电路,给电就响;无源蜂鸣器需要外部提供 2~4kHz 方波。原设计里用的是buzz = !buzz配合延时不断翻转,说明是按无源的方式驱动的,翻转周期决定了音调。这个细节在报告里要写清楚,否则仿真时听到"嗒嗒"声,答辩老师一问就露怯。
3. 中断法还是查询法:用两条路径把 4 个按键分开处理
四个按键全部用查询也能实现功能,全部用中断也能实现,但这份设计的价值恰恰在于把两种方式放在同一个工程里做对照。K1、K2 响应要快、要和主循环"脱钩",走中断;K3、K4 只是普通电平检测,走查询,代码简单直观。这种混搭不是偷懒,而是真实项目里最常见的分工方式——紧急信号走中断,状态量走轮询。
3.1 IE 与 IP 寄存器到底该设哪几位
AT89C51 的中断系统靠两个寄存器管起来:IE 管"开不开",IP 管"谁优先"。IE 寄存器按位从高到低是 EA、—、ET2、ES、ET1、EX1、ET0、EX0。本设计只用到外部中断 0 和 1,所以只关心 EA、EX0、EX1 三位:EA 是总开关,必须置 1;EX0、EX1 分别允许 INT0 和 INT1;定时器和串口中断全部关掉,避免未使用的中断标志位被误触发。
IP 寄存器按位是 —、—、PT2、PS、PT1、PX1、PT0、PX0。默认全部为 0,表示两个外部中断同优先级。同优先级的中断不能互相嵌套,也就是说 INT0 的服务程序执行期间,INT1 的请求只能挂起等待。如果希望 K1 比 K2 更"急",把 PX0 置 1、PX1 清 0,INT0 就成了高优先级,可以打断正在执行的 INT1 服务程序。课程设计里这一步是可选项,但写进报告里能体现对 IP 寄存器的理解,答辩时是个加分点。
#include <reg51.h> #define uchar unsigned char #define uint unsigned int sbit D1 = P2^0; /* 报警灯 1 */ sbit D2 = P2^1; /* 报警灯 2 */ sbit D3 = P2^2; /* 报警灯 3,查询通道 */ sbit D4 = P2^3; /* 报警灯 4,查询通道 */ sbit BUZZ = P1^6; /* 蜂鸣器,经三极管驱动 */ sbit K3 = P3^4; /* 查询按键 3 */ sbit K4 = P3^5; /* 查询按键 4 */ /* 共阳数码管 0~9 段码,位为 0 表示该段点亮 */ code uchar SEG_CODE[10] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90 }; volatile uchar g_alarm_ch = 0; /* 0=无请求,1=通道1,2=通道2 */ volatile uchar g_alarm_req = 0; /* 主循环与中断共享,必须加 volatile */ void InitExtInt(void) { EA = 1; /* CPU 开中断,总开关 */ EX0 = 1; /* 允许外部中断 0,对应 K1 */ EX1 = 1; /* 允许外部中断 1,对应 K2 */ IT0 = 1; /* INT0 下降沿触发 */ IT1 = 1; /* INT1 下降沿触发 */ PX0 = 1; /* INT0 高优先级,K1 可打断 K2 的处理 */ PX1 = 0; }IT0、IT1这两位其实不在 IE 里,而在 TCON 寄存器里,很多报告会写错位置。置 1 表示下降沿触发,置 0 表示低电平触发。按键按下时引脚从高变低,正好产生一个下降沿,所以置 1 是对的。如果误设成电平触发,按键按住不放会反复进中断,表现就是"按一下响个不停",这是排查时第一个要看的地方。
3.2 K1/K2 走中断、K3/K4 走查询的分工理由
中断法的好处是"事件驱动":主程序在while(1)里空转也好、做别的事也好,只要 K1 一按下,CPU 立刻保存现场跳到中断向量表 0x0003 处执行服务程序,响应延迟只有几个机器周期。查询法则是主程序主动去读引脚,读的间隔取决于循环一圈多久,如果循环里有个 3 秒的延时,这 3 秒内按 K3 是没反应的。
那为什么 K3、K4 还要用查询?因为外部中断只有两个,K1、K2 已经占满了。要四个都用中断,就得借助定时器做软件扩展——定时器每 10ms 中断一次,在定时器服务程序里扫描四个按键。这个方案更专业,但对课程设计来说复杂度上去了,而且失去了"中断法和查询法对照"的教学意义。所以分工的边界很清楚:能直接挂到 INT0/INT1 上的用中断,其余的用查询加软件消抖。
| 对比项 | 中断法(K1/K2) | 查询法(K3/K4) |
|---|---|---|
| 触发方式 | 硬件检测下降沿,自动跳转 | 主程序主动读引脚电平 |
| 响应延迟 | 几个机器周期,几乎实时 | 取决于主循环一圈的耗时 |
| CPU 占用 | 空闲时为 0 | 每轮循环都要读一次 |
| 是否需要消抖 | 硬件触发仍需软件防抖 | 必须软件延时消抖 |
| 适用场景 | 紧急信号、按键、外部事件 | 状态量、慢变信号、按键数量多时 |
| 本设计中的角色 | K1、K2 触发声光报警 | K3、K4 演示查询通道 |
3.3 流程图怎么画成可交付的图
报告里要求的两张流程图——主程序流程图和中断服务程序流程图——不是随手画几个框就行,评审看的其实是"你的程序结构和图上画的是不是一回事"。我建议主流程图按"初始化 → 空闲复位 → 判断有无报警请求 → 执行报警 → 扫描 K3/K4 → 回到空闲"这个闭环来画,把EA、EX0、EX1、IT0、IT1的赋值单独画成一个初始化框,标注清楚每一步在配哪个寄存器。
中断服务流程图则要刻意画得"短":进入中断 → 保存通道号到全局变量 → 置报警请求标志 → 中断返回。只有三个处理框,这恰恰是这张图的得分点,因为它和你后面要讲的"中断里不做耗时操作"是互相印证的。如果画成"进入中断 → 显示数字 → 循环十次翻转灯和蜂鸣器 → 熄灭 → 返回",图上一大串,等于把设计缺陷画出来给老师看。
画图工具不限,Visio、Word 形状、draw.io 都行,但框内文字要写函数名或寄存器名,不要写"处理数据""判断条件"这种空话。判断框的出口标"是/否",不要标"Y/N"混着来,全文统一。
4. 代码落地:中断服务程序、段码表与主循环状态机的分工
代码这一章决定报告的可信度。原始写法是在中断服务程序里直接做十次循环、每次延时 200ms 翻转灯和蜂鸣器,功能上能看到效果,但结构上是错的——中断服务执行了大约 4 秒,这 4 秒里同优先级的另一个外部中断根本进不来,K2 按了也白按。正确的做法是把中断服务压到最短,只做"记下是谁按的",真正的声光动作交给主循环去做。
4.1 中断服务只打标记,报警动作交给主循环
/* 外部中断 0 服务程序,中断号 0,对应 INT0 / K1 */ void ExtInt0_ISR(void) interrupt 0 { g_alarm_ch = 1; /* 记录通道号 */ g_alarm_req = 1; /* 置报警请求标志 */ } /* 外部中断 1 服务程序,中断号 2,对应 INT1 / K2 */ void ExtInt1_ISR(void) interrupt 2 { g_alarm_ch = 2; g_alarm_req = 1; }interrupt 0和interrupt 2是 Keil C51 的中断号,不是随便编的:0 对应外部中断 0(向量地址 0x0003),1 对应定时器 0(0x000B),2 对应外部中断 1(0x0013),3 对应定时器 1,4 对应串口。中断号写错,编译不报错,但程序会跳到错误的地方执行,现象是"一按键就跑飞"或者"完全没反应",这类问题在仿真里尤其难查,只能靠背下来。
两个服务程序加起来不到十行,执行时间只有几个微秒。g_alarm_ch和g_alarm_req必须加volatile,因为它们被中断和主循环同时访问;不加的话编译器优化时可能把变量缓存在寄存器里,主循环永远读到旧值,表现就是"中断进了但灯不闪",这是 8051 上最经典的黑匣子问题之一。
4.2 主循环里的报警执行与非阻塞改造
void DelayNms(uint ms) { uint i, j; for (i = 0; i < ms; i++) for (j = 0; j < 120; j++); /* 12MHz 晶振下约 1ms,需实测校准 */ } /* 执行一次完整的声光报警:数码管显示通道号,对应灯闪 10 次,蜂鸣器同步 */ void RunAlarm(uchar ch) { uchar i; uchar led = (ch == 1) ? D1 : D2; P0 = SEG_CODE[ch]; /* ch=1 显示 0xF9,ch=2 显示 0xA4 */ for (i = 0; i < 10; i++) { led = 0; /* 对应报警灯点亮,低电平有效 */ BUZZ = 0; /* 三极管导通,蜂鸣器响 */ DelayNms(200); led = 1; /* 灯灭 */ BUZZ = 1; /* 蜂鸣器停 */ DelayNms(200); } P0 = 0xFF; /* 数码管熄灭 */ D1 = 1; D2 = 1; BUZZ = 1; } void main(void) { P0 = 0xFF; /* 上电先熄灭数码管 */ D1 = D2 = D3 = D4 = 1; /* 四只灯全灭 */ BUZZ = 1; /* 蜂鸣器关闭 */ InitExtInt(); /* 配置 IE、IP、TCON */ while (1) { if (g_alarm_req) { g_alarm_req = 0; /* 先清标志再执行,避免漏掉后续请求 */ RunAlarm(g_alarm_ch); } ScanKey34(); /* 查询通道,见 4.3 */ } }RunAlarm里用的是led = 0这种写法,靠sbit变量本身的赋值来点亮,比P2 = ~(1<<ch)更直观,也避免误改其他引脚。整段报警耗时约 10×(200ms+200ms)= 4 秒,这 4 秒里主循环被占住,但中断依然能进——K2 在 K1 报警期间被按下,中断服务程序照样把g_alarm_req置 1,等RunAlarm返回后主循环立刻接着执行通道 2 的报警,实现了"排队"。代价是如果连按三次,中间的请求会被最后一次覆盖,课程设计级别可以接受,报告里加一句"如需严格排队可改为环形缓冲区"反而显得有余量。
g_alarm_req = 0放在RunAlarm之前清,是为了防止执行期间新来的请求被误清。如果放在后面清,报警 4 秒里来的新请求会在结束时被一键抹掉,这是真实项目里踩过的坑。
4.3 查询通道与按键消抖
void ScanKey34(void) { if (K3 == 0) { /* 低电平有效,读到 0 视为可能按下 */ DelayNms(20); /* 软件消抖,跳过机械抖动的 10~20ms */ if (K3 == 0) { P0 = SEG_CODE[3]; /* 显示 3 */ D3 = 0; /* 报警灯 3 点亮 */ BUZZ = 0; /* 蜂鸣器响 */ DelayNms(3000); /* 报警持续 3 秒 */ while (K3 == 0); /* 等待按键释放,防止连触发 */ P0 = 0xFF; D3 = 1; BUZZ = 1; } } if (K4 == 0) { /* 通道 4 逻辑与通道 3 完全对称 */ DelayNms(20); if (K4 == 0) { P0 = SEG_CODE[4]; /* 显示 4 */ D4 = 0; BUZZ = 0; DelayNms(3000); while (K4 == 0); P0 = 0xFF; D4 = 1; BUZZ = 1; } } }两次读引脚是消抖的核心:第一次读到低电平不能信,等 20ms 再读一次,两次都是低才判定为真实按下。机械按键在闭合瞬间会有 5~20ms 的抖动,期间电平在高低之间跳好几次,只读一次很容易把一次按下识别成好几次。
这段查询代码是阻塞式的,DelayNms(3000)加while(K4==0)会让主循环卡住 3 秒以上,期间中断照样能进、标志照样能置,但RunAlarm要等它结束才执行。更规范的做法是把"按键状态"和"报警动作"也做成状态机,用定时器 10ms 扫一次,主循环完全不阻塞。课程设计里保持阻塞写法可以,但报告里要主动指出这个局限,说明你清楚它和中断通道的差别,这比装作没问题强得多。
4.4 延时函数的校准与晶振选择
DelayNms的j < 120是个经验值,不是精确值。AT89C51 在 12MHz 晶振下机器周期是 1μs,内层for循环编译出来大约 8 个机器周期,120 次约 960μs,接近 1ms。换成 11.0592MHz 晶振,同样代码大约慢 8%,200ms 的闪烁周期会变成 216ms,肉眼看不出来,但如果报告里写了"精确 200ms"就是硬伤。
严谨的写法是用定时器做基准,或者用示波器实测:把某个引脚在延时前后翻转,示波器读出方波周期的一半就是实际延时。我在验收前一般会挑一个通道测一次,把实测值写进报告,比如"实测 200ms 延时误差 ±3ms,满足设计要求"。这句话的分量比十行代码都重,因为它证明你真的测过。
晶振的选型也要写进报告:12MHz 便于按 1μs 机器周期手算延时,11.0592MHz 便于串口通信时得到整数波特率。本设计不涉及串口,选 12MHz 更直观。晶振旁边两只 30pF 电容不能省,它们是起振电容,省掉之后电路可能起振慢或者根本不起振,现象是"程序下载进去了但一动不动",用示波器量 XTAL2 脚没有波形就能确认。
5. 常见问题排查:五个最容易翻车的点
仿真跑通不等于实物能跑,实物能跑不等于报告能过。下面这五条是这类题目里出现频率最高的问题,每一条我都按"现象—原因—解决"记下来,照着查能省掉大量时间。
第一条:K2 按下去没反应,只有 K1 有效。现象是先按 K1 报警正常,报警过程中按 K2 完全没动静,等 K1 那 4 秒结束再按 K2 才有效。原因是中断服务程序里直接写了十次循环加延时,整个服务程序执行了约 4 秒,而同优先级的 INT1 无法打断 INT0 的服务程序,请求只能挂起。解决办法是把中断服务压缩成"记录通道号 + 置标志"两句话,声光动作搬到主循环的RunAlarm里执行,中断服务执行时间降到微秒级。
第二条:数码管显示乱码或者根本不亮,但蜂鸣器和灯正常。现象是按 K1 时数码管显示的不是 1,而是像"厂"字或者几个段一起亮。原因多半是共阳共阴搞反了:按共阳极推的段码 0xF9,接到共阴极数码管上,0 变成了亮的段,整个编码逻辑翻转。另一种情况是 P0 口没接上拉排阻,段码输出幅度不够,数码管发暗甚至不亮。解决办法是先确认数码管型号(看公共端接 VCC 还是 GND),共阴就把段码按位取反(0xF9 变 0x06),P0 口加 10k 排阻,每一段串 330Ω 限流电阻。
第三条:按一次键,报警响好几遍。现象是手指按下去只按了一次,蜂鸣器却"嘀嘀嘀"响了三五轮才停。原因是 IT0/IT1 设成 1 之后是下降沿触发,而机械按键在闭合瞬间会产生多个下降沿,硬件触发比软件查询更"灵敏",反而放大了抖动。解决办法是在中断服务程序里加软件防抖:进中断后先延时 10~20ms,再读一次 P3.2 或 P3.3,如果已经是高电平说明是抖动,直接返回不置标志;确认低电平才置位。更好的做法是硬件上加一只 0.1μF 电容并联在按键两端做 RC 滤波。
第四条:程序烧进去完全没反应,灯不亮、蜂鸣器不响、按键无效。现象是仿真软件里一切正常,下载到实物后像没上电。原因通常有三个:EA 脚没接高电平,CPU 取不到片内程序;复位电路接错,RST 一直保持高电平导致反复复位;晶振不起振,XTAL2 脚测不到正弦波。解决办法是按顺序查——先量 EA 是不是 VCC,再量 RST 在运行时是不是低电平,最后用示波器看晶振脚。这三步走完,九成的"完全没反应"都能定位。
第五条:蜂鸣器声音很小,或者响几声之后单片机死机。现象是蜂鸣器声音微弱,或者报警几次后程序跑飞。原因是蜂鸣器直接挂在 IO 口上,感性负载断开瞬间产生的反向电动势打穿了端口。解决办法是加三极管驱动(S8550 或 S8050,看是高电平还是低电平驱动),蜂鸣器两端反向并联一只 1N4148 续流二极管,基极串 1kΩ 限流电阻。这三样加起来成本不到一块钱,但能保住整块板子。
6. 验收与答辩:用一张时序图和一份自检表把方案讲圆
验收当天最尴尬的场面不是功能没做出来,而是做出来了却讲不清楚。老师问"你这个 200ms 是怎么来的",回答"随便写的";问"中断服务里为什么不能加延时",答不上来。所以我在提交前会强制自己走一遍自检表,把每个能被追问的点都落到具体数值上。
| 检查项 | 判定标准 | 自查方法 |
|---|---|---|
| 初始状态 | 上电后 D1~D4 全灭、数码管熄灭、蜂鸣器不响 | 上电观察 3 秒 |
| K1 通道 | 显示 1、D1 闪烁 10 次、蜂鸣器同步 | 秒表计时约 4 秒 |
| K2 通道 | 显示 2、D2 闪烁 10 次、蜂鸣器同步 | 秒表计时约 4 秒 |
| K3/K4 通道 | 显示 3/4、对应灯常亮 3 秒、蜂鸣器响 | 观察灯是常亮而非闪烁 |
| 中断嵌套 | K1 报警期间按 K2,结束后自动执行通道 2 | 连按验证排队 |
| 延时精度 | 单次 200ms 误差在 ±5% 内 | 示波器测翻转周期 |
| 复位可靠性 | 连续复位 10 次,每次都能正常进入初始状态 | 反复按复位键 |
答辩讲解我一般按这个顺序走:先讲需求(四个按键、四个指示器件),再讲分工(K1/K2 走中断、K3/K4 走查询,为什么这么分),然后讲寄存器(IE 的 EA/EX0/EX1 三位、TCON 的 IT0/IT1 两位、IP 的 PX0),接着讲代码结构(中断只置标志、主循环执行动作),最后讲实测数据(延时误差、响应延迟)。这五步讲完,通常八分钟,正好是一个课程设计答辩的时长。
有一个技巧特别管用:把示波器的截图打印出来贴在报告里,标上"P1.6 引脚实测方波,周期 400ms,占空比 50%"。这一张图能同时证明三件事——蜂鸣器确实在被翻转驱动、延时函数确实工作在 200ms、你的方案真的测过而不只是仿真过。相比之下,一堆 Proteus 截图的说服力要弱得多,因为仿真里延时是理想值,实物才有误差。
还有个常被忽略的点:报告里的电路图和代码必须对得上。代码里写sbit BUZZ = P1^6,原理图上蜂鸣器的驱动三极管基极就必须接在 P1.6;代码里P0输出段码,原理图上 P0 就必须连着数码管的段选。答辩老师翻报告时最爱干的事就是对照这两处,一旦发现对不上,前面讲得再好也会被打折扣。
从那以后,我每次做这类带中断的小系统,都会在写代码之前先把引脚分配表和段码表钉在报告的第二章,代码严格按表来写,验收前再拿示波器实测一遍延时并截图存档——这三件事做完,报告基本不会被退回来返工。希望帮到你。
本文还有配套的精品资源,点击获取