基于单片机的球类比赛专用计分与暂停管理系统设计

1、基于单片机的球类比赛专用计分与暂停管理系统设计

点击链接下载protues仿真设计资料:https://download.csdn.net/download/m0_51061483/91738505

2、系统总体概述

2.1 设计背景与应用场景

在篮球、排球、手球、曲棍球、乒乓球团体赛等球类比赛中,计分与暂停管理是比赛组织与裁判工作的重要组成部分。传统比赛计分方式常见于手动记分牌或机械翻牌,存在显示不够直观、计分容易出错、暂停次数难以同步管理等问题;一些电子计分牌虽然功能完善,但价格较高、结构复杂,不适合学校体育教学、社团活动、社区比赛以及小型赛事的快速部署。

因此,设计一套基于单片机的球类比赛专用计分与暂停管理系统具有较高的实用价值。本系统通过按键实现双方独立加分、减分,利用LED数码管实时显示双方比分;同时为每队提供6次暂停机会,暂停剩余次数也通过数码管显示;当系统进入暂停状态时,计分按键自动失效,防止误操作导致比分错误。系统逻辑清晰,操作简单,结构成本低,适合便携式计分设备或固定安装计分牌使用。

2.2 设计目标与功能需求

系统需实现以下核心功能:

(1)双方独立计分:

  • A队加分按键、A队减分按键
  • B队加分按键、B队减分按键
  • 分数实时显示在LED数码管上
    (2)暂停次数管理:
  • 每队有6次暂停机会
  • A队剩余暂停次数显示在数码管
  • B队剩余暂停次数显示在数码管
    (3)暂停模式控制:
  • 系统可进入暂停状态(由暂停按键触发或自动触发)
  • 暂停状态下计分加分/减分按键无效,防止误操作
  • 暂停结束后恢复计分按键功能
    (4)系统稳定可靠:
  • 按键必须去抖,避免误触发
  • 计分不得出现负数(减分最低到0)
  • 暂停次数不得小于0,使用完不再减少
  • 显示刷新稳定无闪烁

2.3 系统总体结构与模块划分

本系统可划分为以下硬件与软件模块:

(1)单片机控制核心模块:负责按键扫描、显示驱动、计分逻辑、暂停管理、状态机运行。

(2)按键输入模块:包括双方加分/减分按键、双方暂停按键、总暂停/恢复按键(可选)、复位按键(可选)。

(3)LED数码管显示模块:显示A队比分、B队比分、A队暂停剩余次数、B队暂停剩余次数。可使用多位数码管动态扫描显示。

(4)蜂鸣器提示模块(可选):用于按键确认音、暂停开始/结束提示、暂停次数不足提示等。

(5)电源与抗干扰模块:提供稳定电源与去耦滤波,保证显示与按键扫描稳定。

软件系统采用"定时器节拍 + 按键事件 + 状态机"方式实现,逻辑非常适合实时控制类应用:

  • 定时器产生固定时间基准(1ms或10ms)
  • 按键扫描模块输出短按事件
  • 主状态机处理计分、暂停、显示更新
  • 在暂停状态下屏蔽计分事件,实现按键失效保护

3、系统功能设计详解

3.1 双方加分、减分与LED数码管显示

3.1.1 计分规则设计

为了适配不同球类比赛,本系统采用最通用计分方式:

  • 按一次加分键:对应队伍比分 +1
  • 按一次减分键:对应队伍比分 -1(最低不小于0)
    这种方式适用于大多数比赛;若需要篮球的+2/+3或排球每球+1等规则,可在软件中扩展为多档加分键或长按加分。题目要求为加分与减分操作,因此采用+1/-1为基本规则。

3.1.2 显示方式设计

LED数码管显示要求直观且实时。建议显示布局:

  • A队比分:两位或三位数码管(例如0099或000999)
  • B队比分:两位或三位数码管
  • A队暂停剩余:1位数码管(0~6)
  • B队暂停剩余:1位数码管(0~6)

若采用8位数码管动态扫描,可分配如下:

  • 第12位:A队比分(0099)
  • 第34位:B队比分(0099)
  • 第5位:A队暂停剩余(0~6)
  • 第6位:B队暂停剩余(0~6)
  • 第7~8位可用于显示暂停状态、比赛节次、时间等扩展信息(题目未要求,可预留)。

动态扫描的优点是节省IO口,显示亮度可控;缺点是需要刷新频率足够高并注意抗干扰。若资源充足也可用专用驱动芯片(如MAX7219)进一步降低单片机负担,但本题侧重单片机设计,动态扫描更符合课程设计与工程入门。

3.1.3 分数边界与防错策略

系统必须保证比分合理:

  • 加分不得超过上限(可设置为99或199等);若超过可保持最大值或回绕(回绕会导致严重错误,不推荐)。
  • 减分不得小于0,低于0时保持0。
  • 在暂停状态下,计分按键无效,不改变比分。
    同时建议加入"按键确认反馈",例如蜂鸣器短鸣或显示闪烁一瞬间,帮助裁判确认按键已生效,减少重复按压导致的误加分风险。

3.2 暂停次数管理功能(每队6次)

3.2.1 暂停次数设置原则

题目要求每队比赛过程中有6次暂停机会。系统上电或复位时:

  • A队暂停剩余次数 = 6
  • B队暂停剩余次数 = 6
    当一方申请暂停时,该队剩余次数 -1,直到减到0不再减少。

此设计在比赛中非常实用:裁判或教练可随时查看每队剩余暂停次数,避免争议,并且能够自动记录使用次数,减少人为统计错误。

3.2.2 暂停触发方式

暂停触发可有两种设计思路:

(1)双方独立暂停按键:A队暂停键和B队暂停键分别用于申请暂停。按下后:

  • 若该队剩余暂停次数 >0,则进入暂停状态并扣除1次。
  • 若剩余次数为0,则不扣除并可蜂鸣器长鸣提示"无暂停可用"。
    (2)统一暂停键 + 队伍选择:通过选择开关决定当前暂停由哪队使用。该方案按键数量少,但操作复杂易出错。

题目强调双方独立管理,因此推荐方案(1):分别设置A暂停键、B暂停键。这样操作直观,误操作概率低,也便于裁判使用。

3.2.3 暂停状态显示策略

暂停状态下,除了显示双方比分与剩余暂停次数,还应给出明确提示,避免裁判忘记退出暂停或误认为计分失效是故障。显示提示可以采用:

  • 数码管某一位显示"P"(可用段码模拟)
  • 或闪烁显示比分区域
  • 或显示"- -"代表暂停
    题目未要求必须显示暂停标志,但工程上建议加入,尤其在按键失效设计下,若没有提示用户可能误认为按键坏了。

3.3 暂停状态下计分按键失效(防误操作)

3.3.1 设计必要性

比赛暂停期间通常会发生:

  • 裁判或工作人员调整设备
  • 球员与教练靠近计分台
  • 观众或工作人员误碰按键
    如果暂停期间计分按键仍然有效,极容易产生误加分或误减分,导致比赛争议。因此,暂停状态下屏蔽计分按键是非常关键的防误操作设计。

3.3.2 实现方式

暂停状态屏蔽计分按键可以通过软件逻辑完成:

  • 按键扫描仍然工作(避免按键卡住无法释放)
  • 但在暂停状态下,对"加分/减分事件"直接忽略
  • 仅允许"暂停结束按键"或"恢复键"生效
    这样能保证系统一直运行、显示正常刷新,同时避免计分变化。

此外还应考虑:

  • 若按键在进入暂停时被按住,必须等待释放后再允许恢复状态(避免恢复瞬间产生误触发)。
  • 暂停结束后恢复计分功能时,可增加100~200ms的"防连击锁定时间",防止用户长按导致系统退出暂停后立刻加分。

3.3.3 暂停结束方式

暂停结束可以通过以下方式实现:

(1)独立"恢复/继续"按键:按下即退出暂停。

(2)再次按暂停键退出:例如进入暂停后,按任意暂停键再按一次作为恢复。

(3)计时自动结束:例如30秒或60秒自动恢复(适合某些训练场景,但正式比赛不一定需要)。

为了操作清晰与减少误触发,推荐增加一个"继续/恢复"按键,暂停开始后裁判按此键结束暂停并恢复计分键功能。如果必须减少按键数量,也可以规定"再次按暂停键退出"。

4、系统电路设计

4.1 电路设计总体说明

本系统硬件电路主要由单片机最小系统、按键输入电路、LED数码管显示驱动电路、电源去耦与抗干扰电路组成。若加入蜂鸣器提示,也需蜂鸣器驱动电路。

电路设计重点在于:

(1)数码管驱动电流:数码管段电流需要限流电阻,动态扫描时需要位选驱动能力。

(2)按键输入稳定:按键应配合上拉/下拉并进行硬件与软件去抖。

(3)抗干扰能力:动态扫描与按键线可能受到干扰,需要合理布线与去耦。

(4)可扩展性:预留接口便于加入时间显示、节次显示、无线控制等功能。

4.2 单片机最小系统模块

4.2.1 单片机选型

推荐使用STC89C52/AT89C52等51系列单片机,原因:

  • 资源成熟,资料丰富,适合课程与工程入门
  • IO口数量足够可驱动按键与数码管
  • 定时器可用于动态扫描与按键扫描节拍
    若想简化数码管控制,也可选择带更多IO或更高主频的51增强型单片机。

4.2.2 时钟电路

  • 晶振选用11.0592MHz或12MHz
  • 两端加22pF左右匹配电容
  • 晶振走线尽量短,靠近芯片布置,避免干扰进入时钟导致系统不稳定

4.2.3 复位电路

复位电路采用RC上电复位并可增加手动复位按钮:

  • 上电后复位保持一段时间,保证系统启动稳定
  • 手动复位用于重新开始比赛或异常恢复

4.2.4 电源去耦与滤波

  • 单片机电源脚附近放置0.1uF陶瓷电容
  • 系统电源输入放置10uF~47uF电解电容
  • 若系统由电池供电,还需加入稳压与欠压保护(扩展)
    良好的电源去耦可减少数码管切换电流导致的电压波动,避免单片机误复位或按键误判。

4.3 按键输入模块电路设计

4.3.1 按键数量与功能分配

按键最少配置建议:

  • A+(A队加分)
  • A-(A队减分)
  • B+(B队加分)
  • B-(B队减分)
  • A暂停(A队使用暂停)
  • B暂停(B队使用暂停)
  • 恢复/继续(退出暂停)
    可扩展:复位键(比赛清零)、功能键(节次/计时)等。

4.3.2 输入方式与上拉电阻

按键输入一般采用上拉输入:

  • IO口通过电阻上拉到VCC
  • 按键按下时接地,读取低电平
    这种方式抗干扰较强且容易实现。上拉电阻可用内部上拉(部分单片机支持)或外接10kΩ电阻。

4.3.3 按键硬件防抖与保护

可选硬件防抖:在按键与地之间并联小电容(0.01uF~0.1uF),形成RC滤波。

若按键线较长,建议加入:

  • 串联小电阻(几十欧姆)
  • ESD保护二极管(可选)
    提高抗静电能力与可靠性。

4.4 LED数码管显示模块电路设计

4.4.1 数码管类型选择

数码管可选择共阴极或共阳极。设计时要统一:

  • 共阴极:段选输出高电平点亮
  • 共阳极:段选输出低电平点亮
    推荐共阴极,逻辑直观。

4.4.2 动态扫描驱动原理

动态扫描由两部分构成:

  • 段选:a~g段与dp段,用于输出段码(通常由一个端口输出,如P0)
  • 位选:控制哪一位数码管点亮(通常由P2或P1控制)

动态扫描关键点:

  • 每次只点亮一位数码管,快速轮询各位
  • 刷新频率需足够高(>100Hz),否则会闪烁
  • 每位点亮时段电流较大,需要限流电阻并可能需要位选三极管驱动

4.4.3 限流与驱动设计

  • 每段串联限流电阻(220Ω~1kΩ)
  • 若数码管位数较多或亮度要求高,建议位选端加三极管驱动(NPN或PNP,视共阴/共阳而定)
  • 段选端口若驱动能力不足,也可加入段驱动芯片或三极管阵列(如ULN2803)

4.5 蜂鸣器提示模块(可选)

蜂鸣器用于:

  • 按键确认(短鸣)
  • 暂停开始/结束提示
  • 暂停次数用尽提示
    建议使用有源蜂鸣器:IO输出高电平即可鸣叫,控制简单。若需要不同音调,可使用无源蜂鸣器并用PWM驱动,但并非本题必需。

4.6 电源模块与抗干扰设计

系统运行时数码管切换会带来较大瞬态电流,按键输入又容易受干扰,因此电源与布局要求:

  • 数码管供电与单片机供电做好滤波
  • 数码管地线回流尽量避免经过按键地线
  • 按键走线远离数码管段选线
  • 关键电容靠近芯片引脚放置

5、程序设计

5.1 软件总体架构

软件采用"定时器中断驱动显示刷新 + 主循环处理按键事件与状态机"的架构:

(1)定时器中断每1ms或2ms执行一次:

  • 数码管动态扫描刷新
  • 系统tick计数
    (2)按键扫描每10ms执行一次:
  • 去抖处理
  • 输出短按事件(A+、A-、B+、B-、A暂停、B暂停、恢复)
    (3)主循环处理事件:
  • 若非暂停:执行计分加减
  • 若暂停:忽略计分事件
  • 处理暂停次数扣减与暂停状态切换
  • 更新显示缓存

这种架构的优势:

  • 显示刷新稳定,不受主循环影响
  • 按键识别可靠,去抖效果好
  • 控制逻辑清晰,暂停屏蔽易实现
  • 系统易扩展,例如加入计时功能、节次管理等

5.2 数据结构与变量设计

核心变量包括:

  • scoreA、scoreB:双方比分
  • timeoutA、timeoutB:双方剩余暂停次数(初始6)
  • state:系统状态(正常/暂停)
  • display_buf[]:显示缓冲区(每位数码管要显示的数字或符号)
  • key_event:按键事件结构(哪个键被短按/长按)

暂停状态变量:

  • pause_active:1表示暂停中,0表示正常
  • pause_team:记录是哪一队触发的暂停(可用于显示提示或统计)
  • lock_after_resume_ms:退出暂停后短时间锁定,防止误操作(建议200ms)

5.3 按键扫描与事件识别模块

5.3.1 去抖策略

按键去抖常用方法:

  • 每10ms读取一次按键状态
  • 连续3次相同状态才确认按下/松开
  • 确认松开时产生短按事件
    此方法稳定且实现简单。

5.3.2 暂停状态下按键事件过滤

按键扫描仍然运行,但在事件处理阶段:

  • 若pause_active = 1,则A+/A-/B+/B-事件直接丢弃
  • 仅允许"恢复键"事件生效
  • 暂停键可选择是否允许再次触发(一般不需要)

同时,进入暂停时可以清空未处理的计分事件队列,防止在暂停瞬间遗留事件导致暂停中比分改变。

5.4 计分控制模块

计分控制逻辑必须保证边界:

  • 加分:score++,若超过最大值则保持最大(例如99)
  • 减分:若score>0则score--,否则保持0
    为了适应不同球类,可把最大分数设为99或199等,按显示位数决定。

5.5 暂停次数管理模块

5.5.1 暂停次数扣减逻辑

当按下A暂停键:

  • 若timeoutA > 0:timeoutA--,进入暂停状态
  • 若timeoutA == 0:不进入暂停,蜂鸣器提示不可用
    当按下B暂停键同理。

5.5.2 暂停进入与退出机制

进入暂停:

  • pause_active = 1
  • 记录暂停开始时间或显示提示
    退出暂停:
  • pause_active = 0
  • 可设置短暂锁定时间lock_after_resume_ms,避免按键连击导致误加分
  • 恢复显示正常模式

5.6 数码管显示模块程序设计

5.6.1 显示内容编码

假设采用6位数码管:

  • 第1位:A比分十位
  • 第2位:A比分个位
  • 第3位:B比分十位
  • 第4位:B比分个位
  • 第5位:A暂停剩余
  • 第6位:B暂停剩余

显示缓冲区display_buf[6]存放要显示的数字(0~9)或特殊符号(例如暂停显示P)。

动态扫描中断每次刷新一位:

  • 输出段码到SEG_PORT
  • 选择对应位选
  • 延时极短后切换下一位

5.6.2 暂停状态显示策略

暂停状态下可采用以下方式之一:

(1)比分区域闪烁:每500ms熄灭一次,再点亮

(2)显示固定符号:在第6位或第1位显示"P"

(3)显示"- -"代替比分

推荐闪烁比分区域,既不影响比分读取,又能明显提示处于暂停状态。

6、程序示例代码(51单片机C语言框架)

说明:以下示例代码提供一个完整思路:按键扫描去抖、事件处理、暂停屏蔽计分、动态扫描显示。引脚定义与段码需要根据实际硬件(共阴/共阳、位选方式)调整。

6.1 全局定义与变量

c 复制代码
#include <REGX52.H>

typedef unsigned char u8;
typedef unsigned int  u16;

#define MAX_SCORE 99
#define INIT_TIMEOUT 6

// ====== 系统状态 ======
#define STATE_NORMAL 0
#define STATE_PAUSE  1

volatile u8 g_state = STATE_NORMAL;

// ====== 比分与暂停次数 ======
volatile u8 scoreA = 0;
volatile u8 scoreB = 0;
volatile u8 timeoutA = INIT_TIMEOUT;
volatile u8 timeoutB = INIT_TIMEOUT;

// ====== 显示缓冲区(6位) ======
volatile u8 disp_buf[6] = {0};

// ====== 系统tick ======
volatile u16 tick_ms = 0;
volatile u16 lock_after_resume = 0; // 退出暂停后的锁定时间ms

// ====== 按键IO定义(示例:低电平按下) ======
sbit KEY_A_ADD   = P3^0;
sbit KEY_A_SUB   = P3^1;
sbit KEY_B_ADD   = P3^2;
sbit KEY_B_SUB   = P3^3;
sbit KEY_A_TO    = P3^4;
sbit KEY_B_TO    = P3^5;
sbit KEY_RESUME  = P3^6;

// ====== 数码管段选输出(示例:P0) ======
#define SEG_PORT P0

// 位选(示例:P2低6位)------实际可用三极管驱动
#define DIG_PORT P2

6.2 段码表与位选控制

c 复制代码
// 共阴极段码 0~9
code u8 seg_lut[10] = {
    0x3F, //0
    0x06, //1
    0x5B, //2
    0x4F, //3
    0x66, //4
    0x6D, //5
    0x7D, //6
    0x07, //7
    0x7F, //8
    0x6F  //9
};

void Digit_Select(u8 pos)
{
    // pos:0~5,对应6位数码管
    // 示例:低电平选通(根据硬件调整)
    DIG_PORT = ~(1 << pos);
}

6.3 显示缓冲更新函数

c 复制代码
void Update_DisplayBuffer(void)
{
    // A队比分
    disp_buf[0] = scoreA / 10;
    disp_buf[1] = scoreA % 10;

    // B队比分
    disp_buf[2] = scoreB / 10;
    disp_buf[3] = scoreB % 10;

    // 暂停次数
    disp_buf[4] = timeoutA; // 0~6
    disp_buf[5] = timeoutB; // 0~6
}

6.4 动态扫描显示(Timer0中断1ms)

c 复制代码
void Timer0_Init(void)
{
    TMOD &= 0xF0;
    TMOD |= 0x01;     // Timer0方式1

    // 12MHz时1ms重装值0xFC18
    TH0 = 0xFC;
    TL0 = 0x18;

    ET0 = 1;
    EA  = 1;
    TR0 = 1;
}

void Timer0_ISR(void) interrupt 1
{
    static u8 scan_pos = 0;

    TH0 = 0xFC;
    TL0 = 0x18;

    tick_ms++;

    // 退出暂停锁定计时
    if(lock_after_resume > 0) lock_after_resume--;

    // 暂停闪烁控制:每500ms翻转一次显示开关
    static bit blink = 0;
    if((tick_ms % 500) == 0) blink = ~blink;

    // 刷新一位
    Digit_Select(scan_pos);

    if(g_state == STATE_PAUSE && blink == 0) {
        // 暂停且闪烁灭:比分区熄灭(0~3位)
        if(scan_pos <= 3) {
            SEG_PORT = 0x00;
        } else {
            SEG_PORT = seg_lut[disp_buf[scan_pos]];
        }
    } else {
        SEG_PORT = seg_lut[disp_buf[scan_pos]];
    }

    scan_pos++;
    if(scan_pos >= 6) scan_pos = 0;
}

6.5 按键扫描去抖与事件产生(每10ms调用)

c 复制代码
typedef struct {
    bit a_add;
    bit a_sub;
    bit b_add;
    bit b_sub;
    bit a_to;
    bit b_to;
    bit resume;
} KeyEvent;

KeyEvent g_evt;

void Clear_Events(void)
{
    g_evt.a_add = 0;
    g_evt.a_sub = 0;
    g_evt.b_add = 0;
    g_evt.b_sub = 0;
    g_evt.a_to  = 0;
    g_evt.b_to  = 0;
    g_evt.resume= 0;
}

void KeyScan_10ms(void)
{
    static u8 last[7] = {1,1,1,1,1,1,1};
    static u8 stable_cnt[7] = {0};
    u8 now[7];

    now[0] = KEY_A_ADD;
    now[1] = KEY_A_SUB;
    now[2] = KEY_B_ADD;
    now[3] = KEY_B_SUB;
    now[4] = KEY_A_TO;
    now[5] = KEY_B_TO;
    now[6] = KEY_RESUME;

    // 去抖:检测到稳定按下->松开时触发短按事件
    {
        u8 i;
        for(i=0;i<7;i++)
        {
            if(now[i] == last[i]) {
                if(stable_cnt[i] < 3) stable_cnt[i]++;
            } else {
                stable_cnt[i] = 0;
                last[i] = now[i];
            }

            if(stable_cnt[i] == 3) {
                // 这里简化:用"松开瞬间触发"
                // 若按键为低电平按下:当last从0变1且稳定确认,则触发事件
                // 因为上面last已更新,这里需要保存上一状态,工程中可用更完整结构
            }
        }
    }
}

为了让示例更清晰,下面给出更常用的"按下确认触发事件"的去抖写法(更适合计分):

c 复制代码
void KeyScan_10ms_Simple(void)
{
    static u8 key_state[7] = {1,1,1,1,1,1,1};
    static u8 key_cnt[7]   = {0};
    u8 key_now[7];
    u8 i;

    key_now[0] = KEY_A_ADD;
    key_now[1] = KEY_A_SUB;
    key_now[2] = KEY_B_ADD;
    key_now[3] = KEY_B_SUB;
    key_now[4] = KEY_A_TO;
    key_now[5] = KEY_B_TO;
    key_now[6] = KEY_RESUME;

    for(i=0;i<7;i++)
    {
        if(key_now[i] != key_state[i]) {
            key_cnt[i]++;
            if(key_cnt[i] >= 3) { // 30ms确认
                key_state[i] = key_now[i];
                key_cnt[i] = 0;

                // 低电平按下触发事件
                if(key_state[i] == 0) {
                    switch(i) {
                        case 0: g_evt.a_add = 1; break;
                        case 1: g_evt.a_sub = 1; break;
                        case 2: g_evt.b_add = 1; break;
                        case 3: g_evt.b_sub = 1; break;
                        case 4: g_evt.a_to  = 1; break;
                        case 5: g_evt.b_to  = 1; break;
                        case 6: g_evt.resume= 1; break;
                    }
                }
            }
        } else {
            key_cnt[i] = 0;
        }
    }
}

6.6 事件处理与暂停屏蔽逻辑

c 复制代码
void Score_Add(volatile u8 *score)
{
    if(*score < MAX_SCORE) (*score)++;
}

void Score_Sub(volatile u8 *score)
{
    if(*score > 0) (*score)--;
}

void Enter_Pause(u8 team) // team:0=A,1=B
{
    g_state = STATE_PAUSE;
    // 可记录team用于扩展显示/统计
}

void Exit_Pause(void)
{
    g_state = STATE_NORMAL;
    // 退出暂停后锁定200ms,防止按键连击误加分
    lock_after_resume = 200;
}

void Process_Events(void)
{
    // 退出暂停锁定期间不处理计分事件
    bit score_locked = (lock_after_resume > 0) ? 1 : 0;

    // ===== 恢复键优先处理 =====
    if(g_evt.resume) {
        g_evt.resume = 0;
        if(g_state == STATE_PAUSE) {
            Exit_Pause();
        }
    }

    // ===== 暂停键处理(正常模式下有效)=====
    if(g_state == STATE_NORMAL) {
        if(g_evt.a_to) {
            g_evt.a_to = 0;
            if(timeoutA > 0) {
                timeoutA--;
                Enter_Pause(0);
            } else {
                // 无暂停次数可用:可加入蜂鸣器提示(扩展)
            }
        }
        if(g_evt.b_to) {
            g_evt.b_to = 0;
            if(timeoutB > 0) {
                timeoutB--;
                Enter_Pause(1);
            } else {
                // 提示不可用
            }
        }
    } else {
        // 暂停状态下暂停键按下可选择忽略或用于退出
        g_evt.a_to = 0;
        g_evt.b_to = 0;
    }

    // ===== 计分事件处理 =====
    if(g_state == STATE_NORMAL && !score_locked) {
        if(g_evt.a_add) { g_evt.a_add = 0; Score_Add(&scoreA); }
        if(g_evt.a_sub) { g_evt.a_sub = 0; Score_Sub(&scoreA); }
        if(g_evt.b_add) { g_evt.b_add = 0; Score_Add(&scoreB); }
        if(g_evt.b_sub) { g_evt.b_sub = 0; Score_Sub(&scoreB); }
    } else {
        // 暂停或锁定时:计分按键失效,直接清事件
        g_evt.a_add = 0;
        g_evt.a_sub = 0;
        g_evt.b_add = 0;
        g_evt.b_sub = 0;
    }

    Update_DisplayBuffer();
}

6.7 主函数与任务调度

c 复制代码
void main(void)
{
    // 初始化
    scoreA = 0;
    scoreB = 0;
    timeoutA = INIT_TIMEOUT;
    timeoutB = INIT_TIMEOUT;
    g_state = STATE_NORMAL;
    Clear_Events();
    Update_DisplayBuffer();

    Timer0_Init();

    while(1)
    {
        // 每10ms扫描按键(简单实现:轮询tick)
        static u16 last_scan = 0;
        if((tick_ms - last_scan) >= 10) {
            last_scan = tick_ms;
            KeyScan_10ms_Simple();
        }

        // 处理事件
        Process_Events();

        // 其他扩展任务:蜂鸣器、通信、计时等
    }
}

7、系统关键设计要点与可靠性分析

7.1 暂停屏蔽计分按键的可靠实现

本系统核心亮点之一是暂停状态下计分按键失效。实现时必须注意:

(1)屏蔽发生在事件处理层,而不是按键扫描层,避免按键状态卡死导致恢复后误触发。

(2)进入暂停时清空计分事件,避免刚按下计分键同时触发暂停造成比分变化。

(3)退出暂停后加入短暂锁定,防止按键连按导致恢复瞬间计分。

7.2 按键去抖与误触防护

去抖是计分系统准确性的基础。建议:

  • 采用10ms扫描与30ms确认
  • 按下触发一次事件,按住不连发(如需连发可另设计长按重复机制)
  • 按键硬件端可加入RC滤波,提升抗干扰能力

7.3 显示稳定性与亮度

动态扫描显示必须保证刷新频率,建议:

  • 每1ms扫描一位,6位数码管则整屏刷新约166Hz,亮度稳定无闪烁
  • 若亮度不足,可调整点亮时间、降低扫描频率或使用位选驱动三极管提高电流
  • 段码输出需匹配共阴/共阳,避免显示异常

7.4 暂停次数边界控制

暂停次数管理必须严格:

  • 初始为6
  • 只能减少到0,不允许负数
  • 0时不允许进入暂停(或允许进入但不扣减,依据规则;更严格的是不允许进入并提示)
    该逻辑保证比赛规则一致性,避免争议。

7.5 可扩展功能建议(工程提升方向)

虽然题目仅要求计分与暂停管理,但系统可以自然扩展:

(1)加入比赛计时与24秒计时(篮球)

(2)加入节次/局数显示

(3)加入蜂鸣器裁判哨音模式

(4)加入无线遥控或蓝牙控制

(5)加入串口/无线通信与上位机记录

(6)加入掉电记忆(EEPROM保存比分与暂停次数)

这些扩展可使系统更接近实际比赛计分设备。

8、总结

本设计实现了一套基于单片机的球类比赛专用计分与暂停管理系统,能够通过按键实现双方独立加分与减分操作,并将比分实时显示在LED数码管上;同时为每队提供6次暂停机会并分别显示剩余次数,实现比赛暂停资源的自动管理。系统采用状态机思想实现暂停模式控制,在暂停状态下对计分按键进行软件屏蔽,使加分、减分按键失效,有效防止暂停期间误操作造成比分错误。通过定时器驱动动态扫描显示与按键去抖识别,系统具备良好的稳定性与可靠性,同时硬件结构简单、成本低、易于扩展,适用于学校比赛、小型赛事、训练场以及便携式计分牌等多种应用场景。

相关推荐
羊羊小栈10 小时前
基于YOLO和多模态大语言模型的智能电梯安全监控预警系统(vue+flask+AI算法)
人工智能·yolo·语言模型·毕业设计·创业创新·大作业
Y1rong10 小时前
STM32之时钟
stm32·单片机·嵌入式硬件
yuanmenghao10 小时前
自动驾驶中间件iceoryx - 同步与通知机制(二)
开发语言·单片机·中间件·自动驾驶·信息与通信
斌蔚司李11 小时前
Windows 电源高级选项
windows·stm32·单片机
钿驰科技11 小时前
TC-BL2840驱动板在3D打印美甲仪无刷电机的应用
单片机·嵌入式硬件
llilian_1611 小时前
相位差测量仪 高精度相位计相位差测量仪的应用 相位计
大数据·人工智能·功能测试·单片机
A-花开堪折12 小时前
Qemu-NUC980(十一):SPI Controller
linux·arm开发·驱动开发·嵌入式硬件
博晶网络12 小时前
MR400D工业级4G路由器:TCP/IP与UDP协议,解锁工业物联网高效传输新范式‌
网络·单片机·嵌入式硬件
叁散18 小时前
实验项目1 RFID 标签实验
单片机·嵌入式硬件