简介:这份四人智力竞赛抢答器完整课程设计,面向电子信息、自动化等专业学生及需要完成课程设计或电子制作实践的读者,围绕抢答器这一典型数字电路课题提供完整方案。资源包共1个doc文档,约857KB,内容涵盖前言、总体方案设计与论证、单元模块设计、主要器件介绍、系统功能调试、总结体会及附录等章节,结构完整、便于按模块查阅。设计从硬件与软件两方面展开:硬件采用74373、14599等锁存器辅以逻辑门实现第一抢答者信息的存储与信号阻断,用555定时器配合减法计数器完成倒计时,用十进制可逆计数器实现答对加10分、答错扣10分的计分功能;软件部分则探讨以单片机或微控制器实现无线抢答的思路。文中还给出各单元电路分别设计、调试再合成的流程,并附有器件原理与调试方法,适合作为课程设计参考与数字电路综合练习。目前已有4723人学习下载。
1. 四人智力竞赛抢答器:从“谁先按下”到“谁先锁存”的工程真相
做过四人智力竞赛抢答器课程设计的人,大多经历过同一个翻车现场:台上四位选手几乎同时拍下按钮,数码管却显示两个甚至三个“1”,裁判盯着电路板一脸茫然。问题不在按钮,也不在选手手速,而在于你用的锁存逻辑根本没处理“同时到达”这件事。四人智力竞赛抢答器(完整课程设计)这个题目,表面是数字电路入门作业,实际考的是三件事:第一,如何用硬件或单片机在微秒级判定按键先后;第二,如何做到“一人抢中、全员锁死”,不给后来者任何可乘之机;第三,抢答倒计时、违规检测、分数显示这些附加功能怎么在不增加太多成本的前提下塞进去。它适合电子、自动化、计算机相关专业正在做课设的学生,也适合想用一块开发板把数字逻辑、中断、定时器、显示驱动串起来练一遍的入门工程师。常见实现路线有两条:纯 74 系列芯片搭的硬件方案,和单片机加按键扫描的软件方案。前者练逻辑,后者练代码,选哪条取决于你的课设验收老师看重什么。
2. 硬件方案与软件方案怎么选:先看验收标准,再看你手头有什么
2.1 纯数字芯片方案:74LS373 + 74LS148 的经典组合
纯硬件方案的核心思路是用编码器把四路按键转成二进制码,再用锁存器把第一个到达的信号钉死。常见做法是 74LS148(8-3 优先编码器)负责判断哪一路先按下,74LS373(三态输出锁存器)负责把编码结果锁住,同时用一个与非门产生锁存使能信号,一旦锁存成功就封锁后续输入。这个方案的优点是逻辑透明,示波器一挂就能看到信号竞争过程,答辩时容易讲清楚“为什么先按下的能赢”。缺点是 74LS148 的输入是低电平有效,按键需要上拉电阻,而且编码器本身有传播延迟,四路同时按下时输出不稳定,需要额外加 RC 滤波或施密特触发器整形。我一般会建议在按键和编码器之间加一级 74LS14 施密特反相器,把机械抖动的毛刺压掉,否则锁存器可能锁到抖动产生的假信号。
2.2 单片机方案:STC89C52 或 STM32 的按键扫描与中断
单片机方案更灵活,成本也更低。用 STC89C52 这类 51 单片机,四个按键接 P3.2 到 P3.5,其中一路接外部中断 INT0,其余三路用轮询。抢答开始时开中断,任意按键触发中断后,在中断服务函数里读 P3 口状态,判断是哪一路,然后立即关闭中断并置忙标志。这个方案的关键在于中断响应时间——51 单片机从触发到进入 ISR 大约需要 3 到 8 个机器周期,晶振 12MHz 时约 1 到 2 微秒,足够区分人手不可能达到的“同时按下”。如果用 STM32,可以用 EXTI 外部中断加 NVIC 优先级,响应更快,还能顺便做倒计时和 LCD 显示。选型建议:如果课设要求“必须用数字芯片搭建”,那就老老实实走 74 系列;如果允许用单片机,优先选 STC89C52,资料多、烧录简单、成本不到十块钱。
2.3 两种方案的参数对比与适用场景
| 对比项 | 纯数字芯片方案 | 单片机方案 |
|---|---|---|
| 判定精度 | 受编码器延迟限制,约 10-20ns | 受中断响应限制,约 1-2μs |
| 同时按下处理 | 需额外防抖电路,否则输出不稳 | 软件消抖,逻辑可控 |
| 附加功能 | 倒计时、计分需额外芯片 | 定时器+显示驱动,代码实现 |
| 调试难度 | 信号竞争肉眼可见,但改逻辑要重新布线 | 改代码即可,但中断优先级容易踩坑 |
| 成本 | 约 15-25 元 | 约 10-15 元 |
| 适合场景 | 数字电路课程,强调门级逻辑 | 单片机课程,强调中断与定时器 |
提示:如果验收老师明确要求“不能使用可编程器件”,那就不要碰单片机,否则答辩时会被追问“你这还算数字电路课设吗”。
3. 用 STC89C52 跑通四人抢答:最小系统、按键扫描与锁存逻辑
3.1 硬件连线:四个按键、一位数码管和蜂鸣器怎么接
先确认最小系统:STC89C52 加 11.0592MHz 晶振,复位电路用 10μF 电容加 10k 电阻,电源 5V。四个按键一端接地,另一端分别接 P3.2、P3.3、P3.4、P3.5,同时各接一个 10k 上拉电阻到 VCC。这样按下时对应引脚为低电平,松开为高电平。数码管用共阳一位管,段选接 P0 口,位选直接接地(只显示一位)。蜂鸣器用 PNP 三极管驱动,基极接 P2.0,发射极接 VCC,集电极接蜂鸣器正极,蜂鸣器负极接地。抢答开始时 P2.0 输出低电平,三极管导通,蜂鸣器响。按键按下后 P2.0 拉高,蜂鸣器停。这个连线方式的好处是:按键低电平有效,与 51 单片机中断下降沿触发天然匹配,不需要额外反相。
3.2 按键扫描与中断服务函数:谁先按下谁先锁
#include <reg52.h> sbit KEY1 = P3^2; // 选手1按键,接INT0 sbit KEY2 = P3^3; // 选手2按键 sbit KEY3 = P3^4; // 选手3按键 sbit KEY4 = P3^5; // 选手4按键 sbit BUZZ = P2^0; // 蜂鸣器控制 unsigned char winner = 0; // 0表示无人抢答,1-4表示对应选手 bit locked = 0; // 锁存标志,1表示已有人抢中 void delay_ms(unsigned int ms) { unsigned int i, j; for(i = 0; i < ms; i++) for(j = 0; j < 110; j++); } void ext_int0_isr() interrupt 0 { if(locked) return; // 已锁存,直接退出 delay_ms(10); // 软件消抖 if(KEY1 == 0) { // 确认选手1按下 winner = 1; locked = 1; BUZZ = 1; // 关蜂鸣器 } } void main() { IT0 = 1; // INT0下降沿触发 EX0 = 1; // 使能INT0中断 EA = 1; // 开总中断 BUZZ = 0; // 抢答开始,蜂鸣器响 while(1) { if(!locked) { if(KEY2 == 0) { delay_ms(10); if(KEY2 == 0) { winner = 2; locked = 1; BUZZ = 1; } } if(KEY3 == 0) { delay_ms(10); if(KEY3 == 0) { winner = 3; locked = 1; BUZZ = 1; } } if(KEY4 == 0) { delay_ms(10); if(KEY4 == 0) { winner = 4; locked = 1; BUZZ = 1; } } } // 此处可添加数码管显示winner的代码 } }这段代码的逻辑是:选手1走外部中断,响应最快;选手2、3、4走主循环轮询,但一旦locked置1,轮询不再生效。中断服务函数里先判断locked,避免重复进入,然后延时10ms消抖,再确认按键确实按下。参数说明:delay_ms(10) 的10ms是机械按键典型抖动时间,太小消抖不干净,太大可能漏掉快速连按。IT0=1 设置下降沿触发,因为按键按下是电平从高到低。EA=1 是总中断使能,缺了它中断永远不会进。注意:如果四位选手同时按下,中断和轮询可能在同一时刻竞争,但由于中断优先级高于主循环,选手1永远优先。如果课设要求绝对公平,可以把四路都接到中断引脚,但51单片机只有两个外部中断,需要扩展。
3.3 数码管显示与倒计时:用定时器 T0 做 1 秒基准
unsigned char code seg_code[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; // 共阳数码管0-9段码 unsigned char countdown = 30; // 30秒倒计时 unsigned char tick = 0; void timer0_isr() interrupt 1 { TH0 = (65536 - 50000) / 256; // 50ms定时 TL0 = (65536 - 50000) % 256; tick++; if(tick >= 20) { // 20 * 50ms = 1秒 tick = 0; if(countdown > 0) countdown--; } } void main() { TMOD = 0x01; // T0工作方式1,16位定时 TH0 = (65536 - 50000) / 256; TL0 = (65536 - 50000) % 256; ET0 = 1; // 使能T0中断 EA = 1; TR0 = 1; // 启动定时器 // ... 其余初始化 while(1) { if(locked) { P0 = seg_code[winner]; // 显示抢中选手编号 } else { P0 = seg_code[countdown % 10]; // 显示倒计时个位 } } }定时器 T0 设为 50ms 中断一次,累计 20 次就是 1 秒。countdown 初始 30,每次减 1,减到 0 时如果还没人抢答,可以触发超时处理(比如蜂鸣器长响)。参数说明:TH0/TL0 的计算公式是 (65536 - 定时时间/机器周期),11.0592MHz 晶振下机器周期约 1.085μs,50ms 对应约 46080 个计数,所以初值约 19456。seg_code 数组是共阳数码管段码,如果用的是共阴管,需要取反。注意:数码管显示和按键扫描都在主循环里,如果显示刷新太慢会影响按键响应,建议把显示刷新放在定时器中断里,或者用更快的扫描频率。
4. 抢答器避坑指南:从“同时按下显示两个1”到“蜂鸣器一直响”
4.1 现象:两位选手几乎同时按下,数码管显示两个不同的数字
原因:按键消抖时间不一致,或者中断和轮询同时检测到按键。选手1走中断,选手2走轮询,如果选手2的按键在中断消抖的10ms内被轮询到,winner会被覆盖。解决:在轮询里也加 locked 判断,并且把 winner 的赋值放在 locked 置1之后,确保一旦锁存就不再修改。更彻底的做法是四路都用中断,或者用硬件锁存器。
4.2 现象:抢答开始后蜂鸣器一直响,按下按键也不停
原因:蜂鸣器控制引脚初始电平设错。如果 BUZZ 接 PNP 三极管,低电平导通,高电平截止。代码里 BUZZ=0 是响,BUZZ=1 是停。如果初始化时忘了给 BUZZ 赋值,或者按键按下后没有把 BUZZ 拉高,蜂鸣器就会一直响。解决:在 main 函数开头明确 BUZZ=0 表示开始,在中断和轮询里确认按键后立即 BUZZ=1。
4.3 现象:倒计时不走,或者走得特别快
原因:定时器初值计算错误,或者晶振频率和代码里假设的不一致。常见错误是用 12MHz 的初值去跑 11.0592MHz 的晶振,导致定时偏慢约 8%。解决:先确认晶振频率,再按公式重算 TH0/TL0。如果不确定,可以用示波器测 P1.0 翻转周期,反推定时是否准确。
4.4 现象:按键按下后数码管闪烁,或者显示乱码
原因:数码管段选和位选共用端口,或者显示刷新和按键扫描冲突。如果 P0 口既接段选又接按键上拉,按键按下时 P0 电平被拉低,数码管会灭。解决:段选和按键分开端口,或者用锁存器隔离。另外,共阳数码管段码写错也会显示乱码,对照段码表逐位检查。
4.5 现象:抢答成功后,其他选手再按按钮,winner 会变
原因:locked 标志只在中断里判断,主循环轮询没有检查 locked。解决:把 locked 的判断加到所有按键处理分支的最前面,并且用原子操作——在 51 里就是先关中断再改 locked,改完再开中断,防止中断和主循环同时写。
注意:如果课设要求“抢答后显示抢答时间”,需要额外加一个计时变量,在锁存瞬间读取定时器计数值,再换算成毫秒。这个功能在纯数字芯片方案里很难做,建议直接选单片机方案。
5. 从课设到可演示作品:加一个“违规检测”和“分数累计”的进阶技巧
课设验收时,老师往往不只看“谁先按下”,还会问“如果有人提前按了怎么办”“能不能记分”。这两个需求其实可以用同一套逻辑扩展。违规检测的思路是:在主持人宣布“开始”之前,如果任何按键被按下,就判定为违规,直接锁定该选手并扣分。实现方法是在 main 循环里加一个状态机,用 start_flag 表示抢答是否开始,start_flag=0 时检测到按键就置违规标志,start_flag=1 时才进入正常抢答流程。分数累计更简单,用一个 unsigned char score[4] 数组,每次抢中后对应选手加 1 分,数码管轮流显示或通过按键切换显示。我一般会建议把这两个功能做成“加分项”,不要影响基础抢答逻辑的稳定性。具体代码片段如下:
unsigned char score[4] = {0, 0, 0, 0}; bit start_flag = 0; // 0表示未开始,1表示已开始 bit violate = 0; // 违规标志 void check_violate() { if(!start_flag) { if(KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0) { delay_ms(10); if(KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0) { violate = 1; BUZZ = 0; // 违规报警 delay_ms(500); BUZZ = 1; } } } } void add_score(unsigned char player) { if(player >= 1 && player <= 4) { score[player - 1]++; } }这段代码里,start_flag 由主持人通过一个独立按键控制,按下后置1并启动倒计时。违规检测只在 start_flag=0 时生效,检测到按键就报警并锁定,不允许进入正常抢答。add_score 在 winner 确定后调用,把分数存进数组。显示分数时可以用一个按键切换查看四位选手的得分,或者用四位数码管分别显示。这个扩展的代价是多用一个按键和几行代码,但能让课设从“及格”变成“优秀”。最后说一个我自己的习惯:每次焊完板子先不插芯片,用万用表测一遍电源和地有没有短路,再插芯片上电。这个动作救过我至少三次,希望帮到你。
本文还有配套的精品资源,点击获取