尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

抢答器控制系统设计:单片机按键扫描、消抖与先到先得锁存

抢答器控制系统设计:单片机按键扫描、消抖与先到先得锁存 简介这份PDF面向自动化、电气与机电类专业学生及PLC初学者是一套完整的五路抢答器控制系统课程设计参考方案。文档以三菱FX2N型PLC为核心控制器依次展开系统硬件配置与输入输出点分析、PLC选型与接线图绘制、I/O地址分配、程序流程图与时序图、梯形图控制程序编写并延伸到上位机组态监控界面设计、仿真调试与结果分析同时说明抢答器在电视台、商业活动及学校知识竞赛中的应用。压缩包仅含1个PDF文件约781KB篇幅紧凑却覆盖从选题到验证的完整链路目前已有34人学习。读者可借此理清PLC项目“硬件—软件—监控—调试”的设计思路掌握抢答规则可编程调整、违例报警与计时显示等实现方法适合用作课程设计或实训报告的写作范例与排错参考。1. 抢答器控制系统设计公平锁存比按键识别更难现场最常见的翻车不是灯不亮而是灯亮错了人。八名选手在主持人喊出「开始」后几乎同时按下按键最后系统显示 4 号但 3 号选手坚持自己先按——这类争议在课堂上很难复盘因为传统方案没有留下时间证据。抢答器控制系统设计这个题目的核心是在主持人控制的开始与复位之间把「第一个有效按键」准确地锁存下来并且让后续所有按键失效。识别按键只是入口真正决定成败的是扫描周期、消抖窗口与锁存时机三者的配合。这套系统适合两类人一类是做单片机课程设计、需要完整跑通输入、显示、声音、定时四件事的学生另一类是想找一个足够小、又能把中断、状态机、去抖都串起来的嵌入式练手项目。2. 抢答器控制系统硬件选型74LS148 纯数字方案与单片机按键扫描拿到一份抢答器任务文档第一件事不是写代码而是决定用纯数字逻辑还是用单片机。两种路线都能做出可演示的系统但它们对「公平」的保证方式完全不同纯数字方案靠器件的电气特性取胜单片机方案靠软件时序控制取胜。下面先把两条链路的信号流讲清楚再给出选型依据和具体的引脚约定。2.1 用 74LS148 优先编码器搭出第一版抢答通道74LS148 是 8 线—3 线优先编码器8 个输入端低电平有效输出 A0/A1/A2 为反码GS 引脚低电平表示「当前有输入」EO 用于多片级联扩展人数。它天然解决了多人同时按下时的优先级问题I7 的优先级最高I0 最低。典型信号链是这样串起来的按键一端接地、一端上拉按下后拉低对应输入74LS148 把最先到达的高优先级输入编码成三位二进制这三位送 74LS373 八 D 锁存器用 GS 作为锁存使能一旦有人按下就把编码冻结住锁存输出接 74LS47共阳或 74LS48共阴七段译码器直接驱动数码管显示编号。主持人复位键接到 373 的清零端按下后清掉锁存系统回到待命。这条链路里有两个必须注意的细节。第一74LS148 的输入和输出都是低有效无按键时输出全高直接接译码器会稳定显示一个「7」所以必须用 GS 做数码管消隐或者把 A0A2 取反后再送译码器。第二纯硬件方案没有消抖环节机械按键的 520ms 抖动会直接反映到锁存器上常见做法是在每个按键与地之间并一只 0.1μF 电容再配合 10k 上拉构成 RC 低通时间常数约 1ms能压掉大部分毛刺但挡不住长抖动和连击。2.2 单片机方案的引脚分配与按键电平约定以 STC89C52 这类 51 内核为例8 路选手按键直接占一个完整端口读取时一次读回 8 位这一点对后面保证公平性很关键。硬件上按键一端接 IO、一端接 GNDIO 口外部并 10k 上拉电阻按下为低电平。下表是一套可直接落线的分配方案。功能引脚电平约定说明选手 18 抢答键P1.0P1.7按下 0独立按键各配 10k 上拉主持人开始键P3.2按下 0也可复用外部中断 INT0主持人复位键P3.3按下 0清锁存、清显示、停倒计时数码管段选P0.0P0.7高电平点亮共阴数码管每段串 330Ω数码管位选P2.0P2.1输出 1 选中经 NPN 三极管拉低公共阴极蜂鸣器P3.7高电平驱动无源蜂鸣器需方波信号这里选择把 8 路按键放在同一个端口上而不是分散到多个端口原因是读取时可以用KEY_PORT一次性拿到 8 位状态避免逐位读取之间插入几十微秒的时间差——这个时间差在两人抢答间隔极短时足以改变结果。2.3 两套方案的成本、可改性与选型边界纯数字方案和单片机方案没有绝对优劣取决于任务文档要求的可改动程度和调试手段。对比维度74LS148 纯数字单片机扫描器件数量58 片布线繁琐1 片 MCU 少量外围消抖能力靠 RC硬约束软件可调灵活响应时间纳秒级编码延迟低扫描周期 消抖窗口毫秒级倒计时功能需另加 555 与计数器一个定时器解决修改人数重新布线改宏定义与循环上限违规抢答判定很难实现状态机里加一个分支适用场景数字电路综合实验课程设计、产品原型如果任务文档要求「有倒计时、能判违规抢答、能显示编号」不要犹豫直接选单片机如果考核点是数字逻辑器件的级联与竞争冒险分析那就老老实实用 74LS148把 RC 去抖和消隐电路做扎实。2.4 上拉电阻、限流电阻与 IO 定义的落地写法数码管限流电阻的取值不能凭感觉。共阴数码管单段工作电流取 510mA 比较稳妥段驱动压降按 2V 估算供电 5V则 R (5 − 2) / 8mA ≈ 375Ω取标准值 330Ω 或 470Ω 都在可接受范围。电阻偏小会让数码管亮度高但端口电流吃紧8 段同时点亮时可能超过单个 IO 的灌电流上限所以更推荐用三极管或专用驱动芯片做位选。#include reg52.h sbit HOST_START P3^2; // 主持人开始键按下为低 sbit HOST_RESET P3^3; // 主持人复位键按下为低 sbit BEEP P3^7; // 无源蜂鸣器驱动脚 #define KEY_PORT P1 // 8 路选手按键一次读回全部状态 #define SEG_PORT P0 // 段选共阴高电平点亮 #define BIT_PORT P2 // 位选高电平经三极管选中 #define KEY_ACTIVE 0 // 按键按下时的电平便于统一修改硬件极性把按键有效电平写成宏是为了在换用「按下为高」的硬件时不改动扫描逻辑把端口定义集中在一处后面调整引脚分配只需要改这几行。硬件定型之后剩下的活全部落在定时器扫描和状态机上。3. 抢答器控制系统控制逻辑扫描周期、消抖窗口与先到先得锁存控制逻辑要回答三个问题多久扫一次按键、连续多久认定为有效按下、第一个有效按下之后如何让其余按键失效。这三个问题的答案互相牵制——扫描太慢会漏掉快速点按消抖窗口太大又会把真实抢答吞掉所以必须把参数和状态机一起设计。3.1 定时器 T0 每毫秒扫描一次消抖窗口该设几毫秒以 12MHz 晶振为例机器周期 1μs要产生 1ms 定时定时器 T0 工作在方式 1 时初值为 65536 − 1000 64536即十六进制 0xFC18。把按键扫描放进这个中断里扫描周期就是稳定的 1ms不受主循环里其他代码执行时间的影响。#define DEBOUNCE_MS 5 // 连续 5ms 采样到低电平才认定按下 unsigned char key_cnt[8]; // 每个按键的连续低电平计数 unsigned char key_latched; // 0 表示无人抢答1~8 表示锁存编号 bit race_running; // 主持人已开始、尚未有人抢到的窗口 void T0_Init(void) { TMOD (TMOD 0xF0) | 0x01; // 保留 T1 设置T0 用方式 1 TH0 0xFC; // 12MHz 下 1ms 定时初值 TL0 0x18; ET0 1; EA 1; TR0 1; } void T0_ISR(void) interrupt 1 { unsigned char i; TH0 0xFC; TL0 0x18; // 中断内重装初值 if (race_running key_latched 0) { for (i 0; i 8; i) { if ((KEY_PORT (1 i)) KEY_ACTIVE) { if (key_cnt[i] DEBOUNCE_MS) { key_cnt[i]; if (key_cnt[i] DEBOUNCE_MS) { // 达到阈值立即锁存 key_latched i 1; race_running 0; break; // 先到先得不再看后面的位 } } } else { key_cnt[i] 0; // 抬起就清零抖动不会累积成有效 } } } }DEBOUNCE_MS取 5 是一个折中机械按键的抖动通常在 520ms取 5 意味着最快 5ms 就能确认一次按下选手体感几乎无延迟同时又能滤掉绝大多数毛刺。如果现场出现「没人按却亮灯」的情况优先把它加到 10 甚至 15如果出现「明明按了却没反应」先检查是不是消抖窗口过大再检查按键是否在锁存发生之后才被扫到。key_latched一旦被写入就停止扫描这就是最朴素的互锁。注意break的位置它让编号靠前的位优先被判定因此扫描顺序本身就是一种隐藏优先级这一点在第 5 章会用测量手段验证。3.2 先到先得的锁存状态机与抢答编号一个能跑得住现场的抢答器状态不超过三个待命、抢答中、已锁存。把它们写成枚举并在事件里做迁移比一堆散落的 if 更容易排查。当前状态事件动作下一状态待命主持人按下开始清锁存与计数、装载倒计时抢答中抢答中首个有效按键记录编号、停倒计时、响提示音已锁存抢答中倒计时归零显示超时提示、不记编号待命已锁存主持人按下复位清显示、清锁存、清倒计时待命待命选手按键记为违规抢答并声光报警待命typedef enum { ST_IDLE, ST_RUN, ST_LOCK } sys_state; sys_state state ST_IDLE; unsigned char countdown; void host_start(void) { if (state ! ST_IDLE) return; // 已在抢答中或已锁存忽略重复开始 key_latched 0; memset(key_cnt, 0, sizeof(key_cnt)); countdown 30; // 30 秒抢答窗口 state ST_RUN; race_running 1; } void host_reset(void) { key_latched 0; memset(key_cnt, 0, sizeof(key_cnt)); countdown 0; race_running 0; state ST_IDLE; }host_start里对状态做了一次判断防止主持人在有人抢到之后重复按开始键造成显示跳变。host_reset把三个变量一起清零任何一处漏清都会留下「幽灵编号」。3.3 主持人开始键、复位键与违规抢答判定主持人键同样有抖动但它不需要像抢答键那样追求 5ms 响应所以用「读当前电平 记录上次电平」的边沿检测就够占用资源少也便于移植到任何主循环里。bit prev_start 1; bit prev_reset 1; void scan_host_key(void) { if (HOST_START ! prev_start) { prev_start HOST_START; if (HOST_START KEY_ACTIVE) host_start(); // 下降沿触发 } if (HOST_RESET ! prev_reset) { prev_reset HOST_RESET; if (HOST_RESET KEY_ACTIVE) host_reset(); } }违规抢答的判定放在待命状态里如果state ST_IDLE且某个选手键被按下并稳定了DEBOUNCE_MS就把这次按下记为违规显示一个区别于编号的提示例如全屏显示一个-或让蜂鸣器长鸣但不写入key_latched。有些任务文档还要求把违规选手的编号也显示出来那就再加一个foul_flag和foul_id变量与key_latched分开管理。3.4 用外部中断直接抢答可行吗优先级与抖动代价有人会想既然要抢速度为什么不把 8 个按键接到外部中断引脚上。问题有两层。第一多数 51 芯片只有两个外部中断入口8 路按键必须经二极管或编码器合流这又引入了额外的器件延迟与竞争。第二机械抖动会让一次物理按下触发多次中断如果中断服务程序里直接锁存编号锁到的可能是抖动而不是真实按键。常见做法是让外部中断只负责置一个「有人按下」的标志位真正的编号判定仍然回到 1ms 定时器里完成这样既不浪费中断资源也保留了软件消抖的可靠性。4. 抢答器显示与声光提示数码管动态扫描与蜂鸣器驱动抢答结果必须让人一眼看到提示音必须让人一听就知道状态变了。显示和声音这两块看起来是「外围」但它们直接决定了现场演示是否顺利很多系统逻辑完全正确却因为数码管重影或蜂鸣器不响而被判不通过。4.1 共阴共阳段码表与 1ms 动态扫描共阴数码管的段码按 a、b、c、d、e、f、g 从低位到高位排列数字 09 对应下表。共阳数码管把每个字节按位取反即可。数字共阴段码数字共阴段码00x3F50x6D10x0660x7D20x5B70x0730x4F80x7F40x6690x6F两位数码管用动态扫描每 1ms 切换一位整屏刷新率 500Hz远高于人眼可察觉的闪烁阈值。切换时必须先消隐再改位选否则上一位的段码会短暂留在下一位上形成重影。const unsigned char seg_code[10] { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F }; unsigned char disp_buf[2]; // disp_buf[0] 十位disp_buf[1] 个位 void display_scan(void) // 每 1ms 调用一次 { static unsigned char idx 0; SEG_PORT 0x00; // 先消隐 BIT_PORT (BIT_PORT 0xF0) | (1 idx); // 选中当前位 SEG_PORT seg_code[disp_buf[idx]]; idx ^ 1; }seg_code表可以放在code存储区节省 RAM。disp_buf里存的是十进制数字而不是段码这样刷新显示编号、倒计时都只需要改缓冲区不必再关心段码。4.2 无源蜂鸣器的驱动频率与两种提示音无源蜂鸣器需要外部给方波频率决定音调有源蜂鸣器只要给高电平就响。课程设计里常见的是无源蜂鸣器直接输出高电平没有声音这是最容易被误判为「蜂鸣器坏了」的坑。void delay_us(unsigned int us) { while (us--) { ; // 12MHz 下约 1us实际值需按编译优化调整 } } void beep(unsigned int freq, unsigned int ms) { unsigned int half 500000UL / freq; // 半周期微秒数 unsigned int i, cycles (unsigned int)((unsigned long)freq * ms / 1000UL); for (i 0; i cycles; i) { BEEP 1; delay_us(half); BEEP 0; delay_us(half); } }抢答成功的提示音用 2kHz、200ms违规提示音用 800Hz、500ms两种音调差异明显现场不用看屏幕也能分辨。这段延时法的缺点是在发声期间 CPU 被占满所以只适合短提示音如果需要长鸣或与倒计时并行就改用定时器翻转 IO。4.3 显示重影、按键误触、蜂鸣器不响的排查顺序现象可能原因排查手段数码管重影未消隐、刷新太慢改位选前先把段选清零检查刷新频率显示编号跳动锁存变量被覆盖检查中断里是否还有第二次写入无人按也亮灯上拉缺失、消抖窗口太小万用表量待机电平加大 DEBOUNCE_MS按下不响应按键接法反了、扫描被阻塞用串口打印按键电平检查主循环耗时蜂鸣器不响无源当有源用、驱动电流不足换有源蜂鸣器或加三极管驱动显示亮度不均限流电阻不一致、位选驱动弱统一电阻位选加三极管排查顺序建议从电平开始先用万用表确认待机时按键脚是高、按下时是低再看显示最后看声音。跳过电平验证直接改代码往往会在错误的方向上反复折腾。4.4 把抢答编号和毫秒时间戳打到串口当争议出现时串口日志是唯一能还原现场的东西。11.0592MHz 晶振下9600bps 的定时器初值是 0xFD初始化只需要几行。void Uart_Init(void) { SCON 0x50; // 方式 18 位 UART允许接收 TMOD | 0x20; // T1 方式 2自动重装 TH1 0xFD; // 11.0592MHz 下 9600bps TL1 0xFD; TR1 1; TI 1; }在锁存成功的那一刻把编号和定时器累计的毫秒数一起打印出来例如ID3 T1042。多台设备对比测试时这些时间戳可以直接判断两个按键的物理先后是否被系统如实记录。5. 抢答器响应时间与公平性验证逻辑分析仪测量的落地技巧逻辑写完之后「有没有先到先得」这件事必须用测量说话而不是靠演示几次感觉正常。5.1 从按键到锁存的延迟怎么量用一台逻辑分析仪或双通道示波器通道 1 接某个选手按键的 IO通道 2 接蜂鸣器驱动脚或锁存输出。主持人按开始后用信号发生器给通道 1 一个下降沿脉冲测量从下降沿到通道 2 出现提示信号的时间差。按前面 1ms 扫描加 5ms 消抖的参数这个延迟应该稳定落在 67ms 之间波动不超过一个扫描周期。如果测出来是 20ms 以上说明扫描周期或者消抖窗口被其他代码拖慢了需要检查主循环里有没有长延时。这里有一个容易被忽略的公平性漏洞扫描循环按i 0到i 7的顺序执行如果一次扫描中恰好有两位选手同时为低编号小的那位会被先判定。两位选手相差不到 1ms 时扫描顺序的影响就超过了物理先后。解决办法是读取端口后先把 8 位状态整体保存下来再根据保存值判断如果同一时刻有多位为低就按事先约定的规则处理判并罚、随机取一个、或者提示主持人重来而不是默默让编号小的赢。5.2 多人同时按下的边界测试怎么造手工按不出稳定的时间差可以用第二块板子或者信号发生器模拟按键。把 8 个 IO 分别通过三极管接到选手按键上由同一路信号驱动就能得到理论上的「绝对同时」再给两路信号之间加 1ms、2ms、5ms 的固定延时观察锁存结果是否与设定的先后一致。建议至少测三组数据模拟时间差期望结果关注点0ms按约定规则处理并提示是否出现两位编号闪烁1ms先到者胜是否受扫描顺序影响5ms 以上先到者稳定胜出锁存是否准确测试时把串口日志打开对比时间戳与锁存编号能直接看出系统分辨能力的下限。一般来说分辨能力等于扫描周期加消抖窗口所以要求分辨 2ms 以内的任务消抖窗口必须压到 2ms 以下同时硬件上必须加 RC 滤波兜底。5.3 参数微调清单参数默认值调整方向观察指标扫描周期1ms要求更快可降到 0.5ms中断负载、主循环是否被挤消抖窗口5ms误触发加大迟滞减小误亮灯次数、响应延迟倒计时初值30s按赛制调整超时提示是否按时出现蜂鸣器频率2kHz800Hz4kHz 之间现场可听度数码管刷新1ms/位不低于 500Hz 整屏是否有可见闪烁调参的原则是先固定扫描周期再调消抖窗口最后调显示和声音。每次只改一个参数改完用 5.1 的方法重新测一次延迟把数据记下来。三次迭代之内一套能经得起现场追问的抢答器控制系统就成型了。本文还有配套的精品资源点击获取
返回列表