基于 51 单片机的8 路抢答器设计教程

从硬件连接、按键消抖到首按锁存与 Proteus 仿真

最终效果 上电后数码管显示"-";任意选手按下 K1~K8 后,系统显示对应编号 1~8 并锁定结果;主持人按下 START/RESET 后进入下一轮。

适用器件:AT89C51 / AT89C52 / STC89C52 系列

开发环境:Keil C51 + Proteus

目录

使用说明与学习目标

完成后你应能做到

学习路线

[1 功能要求与总体方案](#1 功能要求与总体方案)

[1.1 功能要求](#1.1 功能要求)

[1.2 系统结构](#1.2 系统结构)

[2 元器件与端口分配](#2 元器件与端口分配)

[2.1 元器件清单](#2.1 元器件清单)

[2.2 端口分配表](#2.2 端口分配表)

[3 硬件电路设计](#3 硬件电路设计)

[3.1 51 单片机最小系统](#3.1 51 单片机最小系统)

[3.2 8 路按键输入电路](#3.2 8 路按键输入电路)

[3.3 主持人 START/RESET 键](#3.3 主持人 START/RESET 键)

[4 数码管显示电路](#4 数码管显示电路)

[4.1 共阳极数码管的逻辑](#4.1 共阳极数码管的逻辑)

[4.2 段码表](#4.2 段码表)

[4.3 限流与负载注意](#4.3 限流与负载注意)

[5 Proteus 原理图搭建](#5 Proteus 原理图搭建)

[5.1 放置元件](#5.1 放置元件)

[5.2 接线自检](#5.2 接线自检)

[6 软件设计](#6 软件设计)

[6.1 状态与变量](#6.1 状态与变量)

[6.2 消抖方法](#6.2 消抖方法)

[6.3 控制流程](#6.3 控制流程)

[7 完整 C51 程序](#7 完整 C51 程序)

[7.1 端口、段码与基础函数](#7.1 端口、段码与基础函数)

[7.2 按键译码与消抖](#7.2 按键译码与消抖)

[7.3 主函数:锁存与复位](#7.3 主函数:锁存与复位)

[7.4 关键语句解释](#7.4 关键语句解释)

[8 Keil 工程建立与编译](#8 Keil 工程建立与编译)

[8.1 编译前检查](#8.1 编译前检查)

[8.2 推荐的工程目录](#8.2 推荐的工程目录)

[9 Proteus 仿真步骤](#9 Proteus 仿真步骤)

[9.1 预期现象](#9.1 预期现象)

[10 测试与验收](#10 测试与验收)

[10.1 最小测试集](#10.1 最小测试集)

[10.2 验收结论](#10.2 验收结论)

[11 常见故障与排查](#11 常见故障与排查)

[12 设计改进与扩展](#12 设计改进与扩展)

[13 实验总结](#13 实验总结)

[附录 速查表](#附录 速查表)


使用说明与学习目标

教程默认使用一个共阳极一位数码管显示获胜者编号,8 个选手按键占用 P0 口,数码管占用 P1 口,主持人复位键接 P3.2。

完成后你应能做到

  1. 解释"扫描---消抖---判定---锁存---复位"的完整控制过程。
  2. 正确连接 51 单片机最小系统、P0 外接上拉、共阳极数码管与限流电阻。
  3. 在 Keil 中编译 C51 程序并生成 HEX 文件。
  4. 在 Proteus 中完成仿真,验证 8 个按键、锁定和复位功能。
  5. 根据故障现象判断是按键悬空、段码极性、端口映射还是复位逻辑出错。

学习路线

阶段 主要任务 可验证结果
1. 方案 确定输入、输出和锁存规则 能画出系统框图
2. 硬件 连接最小系统、8 个按键和数码管 端口电平关系明确
3. 软件 编写消抖、编号译码和状态锁存 程序能够生成 HEX
4. 仿真 加载 HEX 并执行测试用例 首按有效、其余锁定、复位恢复

编号约定 **:**K1 接 P0.0,K2 接 P0.1,依次类推,K8 接 P0.7。

1 功能要求与总体方案

1.1 功能要求

功能 要求 实现方式
待机提示 上电或复位后显示"-" P1 输出共阳极横杠段码 0xBF
8 路输入 K1~K8 任一路可参与抢答 P0.0~P0.7 低电平有效
首按判定 只记录第一位有效选手 消抖后译码并写入 winner
结果锁定 后续选手按键无效 winner 非 0 时停止扫描选手键
新一轮 主持人可清除结果 P3.2 的 START/RESET 键将 winner 清零

1.2 系统结构

图 1 8 路抢答器总体结构

核心思想是把"是否已经有人抢答"保存为一个状态变量 winner。winner 等于 0 时允许扫描选手键;winner 变为 1~8 后立即显示编号并停止接收新的选手输入;只有主持人复位才能把 winner 重新清零。

同时按下怎么办? 单片机并不能判断物理上绝对同时的先后。本程序按 P0.0→P0.7 的顺序译码,因此同一采样周期内多键同时为低电平时,编号较小者优先。

2 元器件与端口分配

2.1 元器件清单

元器件 建议规格 数量 作用
51 单片机 AT89C52 / STC89C52 1 完成按键扫描、锁存和显示控制
一位数码管 共阳极 7 段 1 显示 1~8 或"-"
选手按键 常开轻触开关 8 K1~K8,按下接地
主持人按键 常开轻触开关 1 START/RESET,接 P3.2
P0 上拉电阻 4.7 kΩ~10 kΩ 8 为 P0 提供稳定高电平
段限流电阻 220 Ω~330 Ω 8 限制数码管段电流
晶振与电容 12 MHz;22~33 pF 1+2 构成单片机时钟
复位元件 10 μF、10 kΩ、按键 各 1 构成上电与硬件复位
去耦电容 0.1 μF 陶瓷 1 抑制电源瞬态干扰
电源 +5 V 稳压 1 为系统供电

2.2 端口分配表

端口 连接对象 有效电平 / 方向 说明
P0.0~P0.7 K1~K8 输入,低有效 每一路必须外接上拉电阻
P1.0~P1.7 a、b、c、d、e、f、g、dp 输出,低电平点亮 每个段串联限流电阻
P3.2 START/RESET 输入,低有效 主持人清除锁存结果
RST 硬件复位网络 高电平复位 与主持人复位不是同一功能

两个 " 复位 " 要区分 RST 引脚用于重启整个单片机;P3.2 的 START/RESET 只清除本轮抢答结果。做简化版时可以取消 P3.2,直接用硬件复位开始下一轮,但连续操作不够方便。

3 硬件电路设计

3.1 51 单片机最小系统

  1. 电源:VCC 接 +5 V,GND 接地;在 VCC 与 GND 附近并联 0.1 μF 去耦电容。
  2. 时钟:12 MHz 晶振跨接 XTAL1 与 XTAL2,晶振两端各用 22~33 pF 电容接地。
  3. 复位:RST 通过 10 kΩ 电阻接地、通过 10 μF 电容接 +5 V,并用按键将 RST 直接接 +5 V。
  4. 程序存储器:EA 接 +5 V,表示使用片内程序存储器。

3.2 8 路按键输入电路

P0 口是漏极开路结构,作为普通输入时没有像 P1/P2/P3 那样的内部上拉能力。因此每个 P0 引脚都要通过 4.7 kΩ~10 kΩ 电阻接 +5 V,按键另一端接地。未按下时读取 1,按下时读取 0。

按键状态 P0 引脚电平 读取位值 程序含义
未按下 被上拉至 +5 V 1 没有人抢答
按下 通过按键接地 0 该路发出抢答请求

例如 K3 接 P0.2。K3 按下时 P0 的理想读数是 11111011B,即 0xFB。程序不要求整个字节必须等于某个固定值,而是逐位检查,因此同时按下多个键也能给出确定的优先级。

3.3 主持人 START/RESET 键

将 P3.2 设为输入(向该位写 1),按键按下时接地。程序检测到稳定低电平后,把 winner 清零、数码管重新显示"-",并等待主持人键和全部选手键释放,再进入下一轮。

4 数码管显示电路

4.1 共阳极数码管的逻辑

共阳极数码管的公共端接 +5 V,各段阴极经限流电阻连接 P1。当 P1 某位输出 0 时,对应段导通点亮;输出 1 时熄灭。因此,段码与"1 点亮"的共阴极数码管相反。

图 2 P1 与共阳极数码管的段线映射

4.2 段码表

显示 1 2 3 4 5 6 7 8
共阳极段码 0xF9 0xA4 0xB0 0x99 0x92 0x82 0xF8 0x80 0xBF

段码成立的前提 **:**上表假定 P1.0~P1.7 依次连接 a、b、c、d、e、f、g、dp。若你的元件引脚顺序不同,数码管会显示乱码,需要按实际连线重新计算段码。

4.3 限流与负载注意

  1. 每一个段都要单独串联 220 Ω~330 Ω 电阻,不能只在公共端串一个电阻。
  2. 本实验只驱动一位数码管,静态显示即可,不需要动态扫描。
  3. 实物若亮度要求较高或驱动多位数码管,应增加三极管或专用驱动芯片,不要:让单片机端口长期承受过大电流。

5 Proteus 原理图搭建

5.1 放置元件

  1. 新建原理图,放置 AT89C52、CRYSTAL、CAP、RES、BUTTON、共阳极一位数码管和电源端子。
  2. 完成 +5 V、GND、EA、晶振和硬件复位网络,先保证最小系统完整。
  3. 把 K1~K8 分别接 P0.0~P0.7,每一路放置独立上拉电阻,按键另一端接地。
  4. 把 P1.0~P1.7 经 220 Ω~330 Ω 电阻接数码管 a~dp,共阳极端接 +5 V。
  5. 把主持人 START/RESET 键接 P3.2,另一端接地。

图 3 所附实验报告中的 Proteus 连接结构(元件参数以本教程为准)

5.2 接线自检

  1. P0 的 8 根输入线是否都存在上拉电阻,且按键按下时能接地。
  2. 数码管是否选择共阳极型号,公共端是否接 +5 V。
  3. P1 与 a~dp 的顺序是否与段码表完全一致。
  4. EA 是否接 +5 V,晶振频率是否与 Keil 工程设置一致。
  5. 主持人键是否接 P3.2,而不是误接到某一路选手键。

6 软件设计

6.1 状态与变量

对象 取值 含义
winner 0 待机,可扫描 K1~K8
winner 1~8 已锁定对应选手,忽略其他选手键
P0 0xFF 全部选手键释放
P1 0xBF 显示"-"
P1 seg_cawinner 显示获胜编号

6.2 消抖方法

机械按键刚闭合时会在 0 和 1 之间快速跳变。程序先读取一次 P0,发现不是 0xFF 后延时约 10 ms,再读取一次;两次读数一致才认为按键有效。这个方法适合教学和低速人机输入。对精确定时或高可靠系统,建议改用定时器周期扫描。

6.3 控制流程

图 4 抢答器的软件状态与复位路径

7 完整 C51 程序

下面的程序适用于 Keil C51,默认 12 MHz 晶振、共阳极数码管和本教程的端口连接。简单循环延时只用于按键消抖,精度不作为实验验收指标。

7.1 端口、段码与基础函数

cpp 复制代码
#include <reg52.h>

typedef unsigned char  u8;
typedef unsigned int   u16;

#define KEY_PORT   P0
#define SEG_PORT   P1
#define SEG_DASH   0xBF

sbit START_KEY = P3^2;

/* Index 1..8 is used; index 0 is unused here. */
u8 code seg_ca[9] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99,
    0x92, 0x82, 0xF8, 0x80
};

/* Approximate millisecond delay at 12 MHz. */
void delay_ms(u16 ms)
{
    u16 i;
    while (ms--)
    {
        for (i = 0; i < 110; i++);
    }
}

7.2 按键译码与消抖

cpp 复制代码
u8 decode_first_key(u8 value)
{
    if ((value & 0x01) == 0) return 1;  /* K1 */
    if ((value & 0x02) == 0) return 2;  /* K2 */
    if ((value & 0x04) == 0) return 3;  /* K3 */
    if ((value & 0x08) == 0) return 4;  /* K4 */
    if ((value & 0x10) == 0) return 5;  /* K5 */
    if ((value & 0x20) == 0) return 6;  /* K6 */
    if ((value & 0x40) == 0) return 7;  /* K7 */
    if ((value & 0x80) == 0) return 8;  /* K8 */
    return 0;
}

u8 read_key(void)
{
    u8 first;
    u8 second;

    first = KEY_PORT;
    if (first == 0xFF) return 0;

    delay_ms(10);
    second = KEY_PORT;

    if (second != first) return 0;
    return decode_first_key(second);
}

7.3 主函数:锁存与复位

cpp 复制代码
void main(void)
{
    u8 winner = 0;

    KEY_PORT = 0xFF;     /* Release P0 for input. */
    START_KEY = 1;       /* Configure P3.2 as input. */
    SEG_PORT = SEG_DASH; /* Ready indication. */

    while (1)
    {
        /* Host starts a new round. */
        if (START_KEY == 0)
        {
            delay_ms(10);
            if (START_KEY == 0)
            {
                winner = 0;
                SEG_PORT = SEG_DASH;

                while (START_KEY == 0);
                while (KEY_PORT != 0xFF);
                delay_ms(10);
            }
        }

        /* Only scan players before a winner is latched. */
        if (winner == 0)
        {
            winner = read_key();
            if (winner != 0)
            {
                SEG_PORT = seg_ca[winner];
            }
        }
    }
}

7.4 关键语句解释

  1. KEY_PORT = 0xFF:P0 写 1 后处于释放状态,再由外部上拉电阻提供稳定高电平。
  2. decode_first_key:从低位到高位检查,因此多键同采样时 K1 的优先级最高。
  3. winner == 0:只有在尚未产生结果时才扫描选手键,实现软件锁存。
  4. SEG_PORT = seg_cawinner:winner 直接作为数组下标,显示编号 1~8。
  5. 等待全部选手键释放:避免主持人开始下一轮时,上一轮仍按住的选手立即再次抢答。

如果只使用硬件复位 **,**可以删除 P3.2 复位判断,并在显示获胜编号后停在循环中;按下 RST 重新上电即可回到"-"。

8 Keil 工程建立与编译

  1. 打开 Keil uVision,选择 Project → New uVision Project,建立工程目录。
  2. 在器件列表中选择 Atmel AT89C52(或与你的芯片兼容的 8051/8052 器件)。
  3. 新建 main.c,把完整程序粘贴进去,并通过 Add Existing Files to Group 添加到 Source Group 1。
  4. 打开 Options for Target,在 Target 页把晶振频率设置为 12.0 MHz。
  5. 在 Output 页勾选 Create HEX File,确认生成文件目录。
  6. 点击 Build;出现 0 Error(s) 后,在 Objects 目录找到 .hex 文件。

8.1 编译前检查

  1. 文件扩展名必须是 .c,不要误保存为 .txt。
  2. 头文件使用 reg52.h;若选择的是其他厂商芯片,可按器件支持包调整头文件。
  3. sbit START_KEY = P3^2; 是 Keil C51 语法,不能直接用普通桌面 C 编译器编译。
  4. 若改变晶振频率,软件逻辑仍可工作,但 delay_ms 的实际时间会随之改变。

8.2 推荐的工程目录

bash 复制代码
Responder8/
|-- main.c
|-- Responder8.uvproj
|-- Objects/
|   |-- Responder8.hex
|-- Listings/

生成 HEX 是关键 Proteus 加载的是编译后的 .hex 文件,不是 main.c。修改程序后必须重新 Build,Proteus 才能使用新逻辑。

9 Proteus 仿真步骤

  1. 双击 AT89C52,在 Program File 中选择 Keil 生成的 Responder8.hex。
  2. 把 Clock Frequency 设置为 12 MHz,与 Keil 工程和晶振保持一致。
  3. 启动仿真,确认数码管首先显示"-"。
  4. 依次单击 K1~K8,观察显示是否与按键编号一致;每次测试前按 START/RESET。
  5. 在已显示一个编号后再按其他选手键,显示应保持不变。
  6. 按下 START/RESET,释放全部按键后,数码管重新显示"-",进入新一轮。

9.1 预期现象

操作 P0 典型值 数码管 系统状态
上电 0xFF 等待抢答
K1 按下 0xFE 1 锁定 K1
K4 按下 0xF7 4 锁定 K4
K8 按下 0x7F 8 锁定 K8
锁定后按其他键 任意 保持原编号 仍锁定
按 START/RESET 等待释放后 0xFF 新一轮

不要只测一个按键 8 路系统最常见的问题是个别线路接错。必须逐个测试 K1~K8,并额外测试"锁定后继续按键"和"复位后重新抢答"。

10 测试与验收

10.1 最小测试集

编号 测试步骤 通过标准 结果
T01 上电,不按任何键 稳定显示"-" □ 通过 □ 失败
T02 分别让 K1~K8 首先按下 分别显示 1~8 □ 通过 □ 失败
T03 K3 获胜后再按 K6 继续显示 3 □ 通过 □ 失败
T04 按 START/RESET 清除结果并显示"-" □ 通过 □ 失败
T05 复位时保持某选手键按下 等待其释放,不立即误抢答 □ 通过 □ 失败
T06 近似同时按 K2 与 K5 按设定优先级显示 2 □ 通过 □ 失败
T07 快速轻触任意选手键 不乱码、不重复跳变 □ 通过 □ 失败

10.2 验收结论

当 T01~T07 全部通过,说明电源与最小系统、8 路输入、数码管输出、消抖、首按锁存和主持人复位均满足设计要求。若只验证"某一个键能点亮某一个数字",不能视为完成 8 路抢答器验收。

11 常见故障与排查

现象 常见原因 排查与处理
数码管全灭 共阳/共阴型号用错;公共端未接 +5 V 核对器件型号与公共端,确认低电平点亮
显示乱码或段错位 P1 与 a~dp 顺序不一致 逐段点亮测试,按实际连线重排段码
未按键却随机抢答 P0 没有外接上拉或地线悬空 检查 8 个上拉电阻和公共地
只有部分按键有效 某路按键、上拉或 P0 连接错误 用逻辑探针检查未按为 1、按下为 0
显示 0~7 而不是 1~8 沿用了原报告的数组下标 使用 seg_ca1~seg_ca8 并返回编号 1~8
复位后立即又锁定 上一轮选手键仍被按住 等待 P0 恢复 0xFF 后再开始扫描
Proteus 现象未更新 修改代码后未重编译或未重新加载 HEX Build 工程并确认 Program File 路径
实物反复重启 电源不稳、复位网络或去耦不当 检查 +5 V、RST 波形并增加 0.1 μF 去耦

12 设计改进与扩展

这些扩展大家可以试试去实现。

扩展方向 增加内容 软件变化
蜂鸣提示 P2.0 接三极管驱动蜂鸣器 锁存获胜者时鸣叫 0.2~1 s
倒计时 增加两位或四位数码管 用定时器中断做动态扫描与秒计时
违规抢答 主持人增加"开始"状态 开始前按键则记录违规者并报警
公平性提升 外部中断或并行锁存器 降低顺序扫描造成的固定优先级
记录多轮结果 EEPROM / 串口 / LCD 保存并显示历史获胜编号
按键节省 IO 矩阵键盘或 74HC165 改为行列扫描或串行读取

13 实验总结

8 路抢答器把单片机实验中最常见的几个知识点串联起来:P0 的电气特性、按键低电平输入、软件消抖、数组段码、端口静态输出以及状态锁存。真正决定系统是否可靠的并不是 switch 或 if 的形式,而是输入是否稳定、编号映射是否一致、获胜状态是否只写入一次,以及复位后是否能干净地回到待机。

按照本教程完成后,系统应具有清晰且可重复验证的行为:待机显示"-",第一位有效选手被显示并锁定,后续按键不能改变结果,主持人复位后重新开始。这个结构还可以自然扩展到蜂鸣器、倒计时、违规检测和多位显示。

最终检查 逐项确认:P0 外接上拉、共阳极段码、1~8 编号、10 ms 消抖、winner 锁存、P3.2 复位、HEX 已重新编译并加载。

附录 速查表

项目 速查内容
选手键 K1~K8 → P0.0~P0.7;低电平有效;每路 4.7 kΩ~10 kΩ 上拉
主持人键 START/RESET → P3.2;低电平有效
显示端口 P1.0~P1.7 → a、b、c、d、e、f、g、dp;每段 220 Ω~330 Ω
待机段码 共阳极"-" = 0xBF
获胜段码 1~8 = F9、A4、B0、99、92、82、F8、80
关键状态 winner = 0 可抢答;winner = 1~8 已锁定
优先级 同一采样周期多键同时按下时,P0.0 优先于 P0.7
相关推荐
萌动的小火苗1 小时前
嵌入式开发中的栈与队列:任务调度为什么依赖数据结构
数据结构·c++·单片机·嵌入式硬件
振浩微433射频芯片2 小时前
工业遥控器总在关键时刻“掉链子”?——433MHz芯片方案如何破局
网络·单片机·嵌入式硬件·物联网·工业遥控
blevoice3 小时前
抖抖燃脂机单 AC6966B 主控调试踩坑:Type-C 整机供电喇叭无声排障
c语言·开发语言·单片机
三易串口屏4 小时前
三易串口屏开发教程:如何使用键盘控件输入参数并发送给单片机
单片机·嵌入式硬件·串口屏·三易串口屏·键盘控件
小大宇5 小时前
mongoDB dump技巧
数据库·mongodb
2CM_Embed5 小时前
F28379D 下载后 VOFA+ 无数据、Reset 后恢复:一次 TZ 中断误触发排查记录
笔记·单片机·sci·c2000·f28379d·vofa·tz
吴声子夜歌5 小时前
MongoDB 4.x——微服务入门
java·mongodb·微服务
国科安芯5 小时前
空间机电一体化:AS32S601型抗辐射MCU在卫星推进与执行机构控制中的关键技术研究
单片机·嵌入式硬件·物联网·机器人·云计算
国科安芯5 小时前
AS32S601型抗辐射MCU在分布式太空算力架构中的技术演进与应用前景
人工智能·分布式·单片机·嵌入式硬件·架构·边缘计算