☰
基于AT89C51外部中断的声光报警器设计与查询法对照
2026/11/3 11:28:14 网站建设 项目流程

简介:这份资源是西南科技大学计算机科学与技术专业《单片微机原理及应用》课程设计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~D4P2.0~P2.3低电平点亮P2 灌电流能力强,低电平驱动 LED 更稳
蜂鸣器P1.6由程序翻转经三极管驱动,不直连 IO
数码管 a~g、dpP0.0~P0.7低电平点亮共阳极接法,P0 需外接 10k 上拉排阻
K1P3.2 / INT0低电平有效下降沿触发,内部上拉
K2P3.3 / INT1低电平有效下降沿触发,内部上拉
K3P3.4低电平有效查询法读取
K4P3.5低电平有效查询法读取
RSTRST高电平复位10μF 电容 + 10k 电阻构成上电复位
XTAL1/XTAL218、19 脚—12MHz 晶振 + 两只 30pF 瓷片电容
EA31 脚接 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)十六进制
1b、c1111 10010xF9
2a、b、d、e、g1010 01000xA4
3a、b、c、d、g1011 00000xB0
4b、c、f、g1001 10010x99
熄灭无1111 11110xFF

把这五个值做成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 就必须连着数码管的段选。答辩老师翻报告时最爱干的事就是对照这两处,一旦发现对不上,前面讲得再好也会被打折扣。

从那以后,我每次做这类带中断的小系统,都会在写代码之前先把引脚分配表和段码表钉在报告的第二章,代码严格按表来写,验收前再拿示波器实测一遍延时并截图存档——这三件事做完,报告基本不会被退回来返工。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询