基于STM32的无线抢答器设计

简介: 基于STM32的无线抢答器以“无线信号传输-抢答优先级判断-声光结果反馈-多终端协同”为核心,实现多人抢答场景下的快速响应、公平判罚与实时显示,支持3-8个选手终端、1个主机(裁判端),无线传输距离≥10米,响应延迟≤50ms,适用于知识竞赛、课堂互动、企业团建等场景。

一、系统概述与核心功能

1. 系统定位

基于STM32的无线抢答器以“无线信号传输-抢答优先级判断-声光结果反馈-多终端协同”为核心,实现多人抢答场景下的快速响应、公平判罚与实时显示,支持3-8个选手终端、1个主机(裁判端),无线传输距离≥10米,响应延迟≤50ms,适用于知识竞赛、课堂互动、企业团建等场景。

2. 核心功能模块

模块 功能描述
无线传输 选手终端→主机:抢答信号(含终端编号);主机→终端:抢答结果(成功/失败)
抢答判断 主机接收多终端信号,按信号到达顺序判定优先级(先到先得),支持“犯规检测”(提前抢答)
结果显示 主机LCD显示抢答成功选手编号、倒计时(可选),终端LED指示自身状态(待机/抢答中/成功)
声光反馈 抢答成功:主机蜂鸣器鸣响+LED闪烁;犯规:短促蜂鸣+红灯提示
终端控制 选手按键抢答,终端本地显示“已抢答”状态,支持复位(裁判端控制)
低功耗设计 待机时终端关闭无线模块,主机进入低功耗模式(仅保留无线接收)

二、硬件设计方案

1. 核心硬件选型

模块 型号 关键参数 接口方式
主控MCU STM32F103C8T6 72MHz Cortex-M3,64KB Flash,20KB RAM,3个UART,2个SPI,支持外部中断 核心控制器(主机/终端共用)
无线模块 NRF24L01+ 2.4GHz ISM频段,最大传输速率2Mbps,多发一收(1主多从),传输距离10-20米 SPI(SCK/MISO/MOSI/CS/CE)
显示模块 LCD1602(主机) 16×2字符型LCD,HD44780控制器,5V供电,支持自定义字符 并行接口(GPIO模拟)
输入模块 轻触按键(终端) 6×6mm贴片按键,寿命10万次,终端每人1个(编号1-N) GPIO(外部中断)
声光模块 有源蜂鸣器+LED 蜂鸣器(5V,85dB),LED(红/绿双色),终端用绿色(待机)、红色(抢答成功) GPIO(PB0-PB1)
电源模块 5V/2A适配器+AMS1117 输入220V AC,输出5V/2A(主机),3.3V给STM32/NRF24L01(终端用锂电池3.7V) 供电一体化

2. 系统架构与硬件连接

2.1 主机(裁判端)硬件设计

  • 核心电路:STM32F103C8T6最小系统(8MHz晶振+复位电路)+ NRF24L01+(SPI接口:SCK=PA5,MISO=PA6,MOSI=PA7,CS=PA4,CE=PA3)+ LCD1602(RS=PB10,RW=PB11,E=PB12,D4-D7=PB13-PB16)+ 蜂鸣器(PB0)+ 状态LED(PB1,红/绿双色)。
  • 功能:接收终端抢答信号→判断优先级→显示结果→声光反馈。

2.2 终端(选手端)硬件设计

  • 核心电路:STM32F103C8T6最小系统(简化版,无晶振用内部RC)+ NRF24L01+(SPI接口:SCK=PA5,MISO=PA6,MOSI=PA7,CS=PA4,CE=PA3)+ 抢答按键(PA0,外部中断)+ 状态LED(PB0,绿色待机/红色抢答成功)+ 复位按键(PB1)。
  • 功能:按键触发→发送抢答信号(含终端编号)→本地LED指示状态。

三、软件设计与核心代码

1. 系统架构(主机/终端双模式)

  • 主机模式:初始化NRF24L01+为接收模式(PRX),循环检测RX FIFO,解析数据包(终端编号+抢答时间戳),记录首个有效信号,更新LCD显示并触发声光反馈。
  • 终端模式:初始化NRF24L01+为发送模式(PTX),按键按下时(外部中断)发送数据包(含终端编号+当前时间戳),本地LED变红提示“已抢答”。

2. 核心代码实现(基于HAL库)

2.1 NRF24L01+驱动(主机/终端共用,nrf24l01.c

#include "nrf24l01.h"
#include "spi.h"
#include "gpio.h"

// NRF24L01+寄存器地址
#define CONFIG      0x00
#define EN_AA       0x01
#define EN_RXADDR   0x02
#define SETUP_AW    0x03
#define SETUP_RETR  0x04
#define RF_CH       0x05
#define RF_SETUP    0x06
#define STATUS      0x07
#define RX_ADDR_P0  0x0A
#define TX_ADDR     0x10
#define RX_PW_P0    0x11
#define FIFO_STATUS 0x17

// 全局变量
uint8_t tx_addr[5] = {
   0x34,0x43,0x10,0x10,0x01};  // 主机接收地址(终端发送目标)
uint8_t rx_addr[5] = {
   0x34,0x43,0x10,0x10,0x01};  // 终端接收地址(主机发送目标)

// NRF24L01+初始化(主机:PRX模式;终端:PTX模式)
void NRF24L01_Init(uint8_t mode) {
   
  HAL_GPIO_WritePin(NRF_CE_GPIO_Port, NRF_CE_Pin, GPIO_PIN_RESET);  // CE=0,待机模式
  NRF24L01_WriteReg(CONFIG, 0x0F);  // 使能CRC(2字节),上电,PTX模式(默认)
  if (mode == MODE_PRX) {
     // 主机:PRX模式
    NRF24L01_WriteReg(CONFIG, 0x0F | (1<<0));  // PRX模式(PWR_UP=1,PRIM_RX=1)
    NRF24L01_WriteBuf(RX_ADDR_P0, rx_addr, 5);  // 设置接收地址
    NRF24L01_WriteReg(RX_PW_P0, 32);  // 接收数据长度32字节
    NRF24L01_WriteReg(EN_RXADDR, 0x01);  // 使能P0通道
  } else {
     // 终端:PTX模式
    NRF24L01_WriteBuf(TX_ADDR, tx_addr, 5);  // 设置发送地址
    NRF24L01_WriteBuf(RX_ADDR_P0, rx_addr, 5);  // 设置接收地址(主机反馈用)
    NRF24L01_WriteReg(EN_AA, 0x01);  // 使能自动应答(P0通道)
  }
  NRF24L01_WriteReg(RF_CH, 40);  // 设置频道40(2.440GHz)
  NRF24L01_WriteReg(RF_SETUP, 0x07);  // 发射功率0dBm,传输速率2Mbps
  NRF24L01_WriteReg(SETUP_RETR, 0x1A);  // 自动重发10次,间隔500us
  HAL_GPIO_WritePin(NRF_CE_GPIO_Port, NRF_CE_Pin, GPIO_PIN_SET);  // CE=1,启动
}

// 发送数据(终端用)
void NRF24L01_SendData(uint8_t *data, uint8_t len) {
   
  HAL_GPIO_WritePin(NRF_CE_GPIO_Port, NRF_CE_Pin, GPIO_PIN_RESET);
  NRF24L01_WriteReg(CONFIG, 0x0E);  // PTX模式,PWR_UP=1,PRIM_RX=0
  NRF24L01_WriteBuf(0xA0, data, len);  // 写入TX FIFO
  HAL_GPIO_WritePin(NRF_CE_GPIO_Port, NRF_CE_Pin, GPIO_PIN_SET);  // 启动发送
  while (!(NRF24L01_ReadReg(STATUS) & (1<<5)));  // 等待发送完成(TX_DS=1)
  NRF24L01_WriteReg(STATUS, 0x20);  // 清除TX_DS标志
}

// 接收数据(主机用)
uint8_t NRF24L01_ReceiveData(uint8_t *data) {
   
  if (NRF24L01_ReadReg(STATUS) & (1<<6)) {
     // RX_DR=1,接收完成
    NRF24L01_ReadBuf(0x61, data, 32);  // 读取RX FIFO
    NRF24L01_WriteReg(STATUS, 0x40);  // 清除RX_DR标志
    return 1;  // 接收成功
  }
  return 0;  // 无数据
}

2.2 主机主程序(抢答判断与显示,main_host.c

#include "stm32f1xx_hal.h"
#include "nrf24l01.h"
#include "lcd1602.h"
#include "buzzer.h"

// 抢答数据包结构(32字节)
typedef struct {
   
  uint8_t dev_id;      // 终端编号(1-8)
  uint32_t timestamp;  // 抢答时间戳(ms,基于SysTick)
  uint8_t reserved[27];// 保留字段
} BidData_t;

BidData_t first_bid = {
   0};  // 首个有效抢答数据
uint8_t bid_success = 0;    // 抢答成功标志(0:无,1:成功,2:犯规)

int main(void) {
   
  HAL_Init();
  SystemClock_Config();  // 72MHz
  MX_GPIO_Init();        // 初始化GPIO(LCD、蜂鸣器、LED)
  MX_SPI1_Init();        // 初始化SPI1(NRF24L01+)
  LCD1602_Init();        // 初始化LCD1602
  Buzzer_Init();         // 初始化蜂鸣器
  NRF24L01_Init(MODE_PRX);  // 主机:PRX模式

  LCD1602_ShowString(0, 0, "Waiting...", 16);  // 初始显示“等待抢答”

  while (1) {
   
    uint8_t rx_buf[32];
    if (NRF24L01_ReceiveData(rx_buf)) {
     // 接收终端数据
      BidData_t *bid = (BidData_t *)rx_buf;

      if (!bid_success) {
     // 首次抢答
        first_bid = *bid;
        bid_success = 1;
        LCD1602_ShowString(0, 0, "Winner: ", 16);
        LCD1602_ShowChar(8, 0, '0' + bid->dev_id, 16);  // 显示终端编号
        Buzzer_Beep(1000);  // 长鸣1秒(成功)
        HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET);  // 绿灯亮
      } else {
     // 二次抢答(犯规)
        bid_success = 2;
        LCD1602_ShowString(0, 1, "Foul! Dev:", 16);
        LCD1602_ShowChar(10, 1, '0' + bid->dev_id, 16);
        Buzzer_Beep(200);  // 短鸣0.2秒(犯规)
        HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_SET);  // 红灯亮
      }
    }

    // 裁判复位(按键PA1)
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET) {
   
      bid_success = 0;
      first_bid.dev_id = 0;
      LCD1602_ShowString(0, 0, "Waiting...    ", 16);
      LCD1602_ShowString(0, 1, "            ", 16);
      Buzzer_Off();
      HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET);
      HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_RESET);
      HAL_Delay(200);  // 消抖
    }

    HAL_Delay(10);  // 10ms轮询一次
  }
}

2.3 终端主程序(抢答发送,main_terminal.c

#include "stm32f1xx_hal.h"
#include "nrf24l01.h"
#include "led.h"

// 终端编号(1-8,通过拨码开关或代码定义)
#define DEV_ID 1  

// 抢答数据包
BidData_t bid_data = {
   DEV_ID, 0, {
   0}};

int main(void) {
   
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();  // 初始化GPIO(按键、LED、NRF24L01+)
  MX_SPI1_Init();
  NRF24L01_Init(MODE_PTX);  // 终端:PTX模式
  LED_Init();  // 初始化LED(绿色待机,红色抢答成功)
  LED_Green_On();  // 初始绿灯(待机)

  // 按键中断配置(PA0,下降沿触发)
  GPIO_InitTypeDef GPIO_InitStruct = {
   0};
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);

  while (1) {
   
    // 低功耗待机(仅保留中断)
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
  }
}

// 按键中断服务函数(发送抢答信号)
void EXTI0_IRQHandler(void) {
   
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {
   
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
    if (LED_GetState() != RED) {
     // 未抢答过
      bid_data.timestamp = HAL_GetTick();  // 记录当前时间戳
      NRF24L01_SendData((uint8_t *)&bid_data, sizeof(bid_data));  // 发送数据
      LED_Red_On();  // 红灯亮(已抢答)
      LED_Green_Off();
    }
  }
}

参考代码 基于STM32的无线抢答器设计 www.youwenfan.com/contentalh/133735.html

四、关键技术与优化

1. 无线传输可靠性

  • 抗干扰设计:NRF24L01+工作在2.4GHz ISM频段,通过RF_CH设置频道(如40),避开Wi-Fi(2.4GHz)干扰;启用自动重发(SETUP_RETR=0x1A,10次重发)。
  • 数据校验:数据包含dev_idtimestamp,主机通过timestamp判断信号到达顺序(精确到1ms),避免多终端同时发送的冲突。

2. 抢答优先级判断

  • 先到先得逻辑:主机维护first_bid变量,仅记录首个有效信号,后续信号判定为“犯规”。
  • 防误触设计:终端按键需长按50ms(软件消抖)才发送信号,避免误碰触发。

3. 低功耗优化

  • 终端待机:无抢答时,STM32进入SLEEP模式,关闭NRF24L01+电源(通过MOS管控制VCC),仅保留按键中断唤醒。
  • 主机低功耗:无信号时,NRF24L01+进入接收待机模式(功耗<1mA),STM32通过HAL_PWR_EnterSLEEPMode降低功耗。

五、系统调试与扩展

1. 调试步骤

阶段 操作 工具
硬件调试 测量NRF24L01+供电(3.3V),示波器检查SPI时序 万用表、示波器(SCK/MOSI)
无线测试 终端发送“test”数据,主机用串口打印接收内容 串口调试助手(SSCOM)
抢答逻辑 2个终端同时按键,观察主机是否只记录首个 逻辑分析仪(NRF24L01+信号)
声光反馈 抢答成功后,检查蜂鸣器频率(1kHz)和LED状态 示波器(蜂鸣器驱动信号)

2. 扩展功能

  • 倒计时显示:主机增加DS1302实时时钟,支持设置抢答倒计时(如30秒),LCD显示剩余时间。
  • 多轮抢答:主机记录每轮胜者,支持“重新开始”按钮,自动清空历史数据。
  • 无线扩展:增加蓝牙模块(HC-05),手机APP显示抢答结果、导出数据。

六、总结

基于STM32的无线抢答器通过NRF24L01+无线传输实现多终端与主机通信,时间戳优先级判断确保公平性,声光反馈+LCD显示提升交互体验,硬件成本约80元/套(含3个终端+1个主机),软件可扩展性强,适合作为嵌入式通信、实时系统设计的实践项目。

相关文章
|
21天前
|
人工智能 数据可视化 安全
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
本文详解如何用阿里云Lighthouse一键部署OpenClaw,结合飞书CLI等工具,让AI真正“动手”——自动群发、生成科研日报、整理知识库。核心理念:未来软件应为AI而生,CLI即AI的“手脚”,实现高效、安全、可控的智能自动化。
34907 57
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
|
15天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
本文介绍了Claude Code终端AI助手的使用指南,主要内容包括:1)常用命令如版本查看、项目启动和更新;2)三种工作模式切换及界面说明;3)核心功能指令速查表,包含初始化、压缩对话、清除历史等操作;4)详细解析了/init、/help、/clear、/compact、/memory等关键命令的使用场景和语法。文章通过丰富的界面截图和场景示例,帮助开发者快速掌握如何通过命令行和交互界面高效使用Claude Code进行项目开发,特别强调了CLAUDE.md文件作为项目知识库的核心作用。
14362 44
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
|
3天前
|
缓存 人工智能 自然语言处理
我对比了8个Claude API中转站,踩了不少坑,总结给你
本文是个人开发者耗时1周实测的8大Claude中转平台横向评测,聚焦Claude Code真实体验:以加权均价(¥/M token)、内部汇率、缓存支持、模型真实性及稳定性为核心指标。
|
10天前
|
人工智能 JavaScript Ubuntu
低成本搭建AIP自动化写作系统:Hermes保姆级使用教程,长文和逐步实操贴图
我带着怀疑的态度,深度使用了几天,聚焦微信公众号AIP自动化写作场景,写出来的几篇文章,几乎没有什么修改,至少合乎我本人的意愿,而且排版风格,也越来越完善,同样是起码过得了我自己这一关。 这个其实OpenClaw早可以实现了,但是目前我觉得最大的区别是,Hermes会自主总结提炼,并更新你的写作技能。 相信就冲这一点,就值得一试。 这篇帖子主要就Hermes部署使用,作一个非常详细的介绍,几乎一步一贴图。 关于Hermes,无论你赞成哪种声音,我希望都是你自己动手行动过,发自内心的选择!
2838 28
|
1月前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
45828 160
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
6天前
|
弹性计算 人工智能 自然语言处理
阿里云Qwen3.6全新开源,三步完成专有版部署!
Qwen3.6是阿里云全新MoE架构大模型系列,稀疏激活显著降低推理成本,兼顾顶尖性能与高性价比;支持多规格、FP8量化、原生Agent及100+语言,开箱即用。
|
8天前
|
人工智能 弹性计算 安全
Hermes Agent是什么?怎么部署?超详细实操教程
Hermes Agent 是 Nous Research 于2026年2月开源的自进化AI智能体,支持跨会话持久记忆、自动提炼可复用技能、多平台接入与200+模型切换,真正实现“越用越懂你”。MIT协议,部署灵活,隐私可控。
2175 5