news 2026/6/9 7:18:25

别再只会点灯了!用STM32做个篮球计分器,把红外遥控、OLED显示和定时器中断一次学透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再只会点灯了!用STM32做个篮球计分器,把红外遥控、OLED显示和定时器中断一次学透

STM32实战:从零打造智能篮球计分器,掌握三大核心技能

篮球比赛计分器看似简单,却蕴含了嵌入式开发的精髓。本文将带您用STM32实现一个功能完备的篮球计分系统,同时深入掌握红外遥控解码、OLED显示驱动和定时器中断三大关键技术。

1. 项目整体架构设计

一个完整的篮球计分系统需要处理多种实时任务:精确计时、比分更新、显示刷新和用户输入响应。基于STM32F103C8T6的设计方案如下:

硬件组成模块

  • 主控芯片:STM32F103C8T6(72MHz Cortex-M3内核)
  • 显示模块:0.96寸OLED(SSD1306驱动,I2C接口)
  • 输入模块:红外遥控接收器(VS1838B)
  • 辅助电路:电源管理、复位电路等

软件功能划分

// 系统任务优先级安排 typedef enum { TIMER_IRQ_PRIORITY = 0, // 定时器中断(最高优先级) REMOTE_DECODE_PRIORITY = 1, // 红外解码 DISPLAY_REFRESH_PRIORITY = 2, // 显示刷新 MAIN_LOOP_PRIORITY = 3 // 主循环任务 } TaskPriority;

关键性能指标

功能模块响应时间刷新频率资源占用
计时系统<1ms误差100Hz更新TIM3
红外解码<50ms延迟事件触发TIM4
OLED显示<5ms刷新30fpsI2C1

2. 精确计时系统实现

比赛计时是篮球计分器的核心功能,需要实现以下特性:

  • 四节比赛,每节12分钟倒计时
  • 24秒进攻时限
  • 精确到0.01秒的时间显示
  • 暂停/继续功能

2.1 定时器中断配置

使用TIM3作为主计时器,配置为向上计数模式:

void TIM3_Init(void) { TIM_TimeBaseInitTypeDef TIM_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_InitStruct.TIM_Period = 7199; // 72MHz/7200 = 10kHz TIM_InitStruct.TIM_Prescaler = 9; // 10kHz/10 = 1kHz (1ms) TIM_InitStruct.TIM_ClockDivision = 0; TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_InitStruct); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); NVIC_EnableIRQ(TIM3_IRQn); NVIC_SetPriority(TIM3_IRQn, TIMER_IRQ_PRIORITY); TIM_Cmd(TIM3, ENABLE); }

2.2 中断服务程序逻辑

在中断服务程序中实现多层次计时逻辑:

void TIM3_IRQHandler(void) { static uint16_t ms_count = 0; static uint8_t sec_count = 0; if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 0.01秒级计数 if(++ms_count >= 10) { ms_count = 0; game_time.centi_sec--; // 24秒进攻计时 if(game_state == PLAYING) { if(--attack_time.centi_sec <= 0) { attack_time.centi_sec = 0; handle_24sec_violation(); } } } // 秒级处理 if(game_time.centi_sec < 0) { game_time.centi_sec = 99; if(--game_time.seconds < 0) { game_time.seconds = 59; if(--game_time.minutes < 0) { end_period(); } } } } }

注意:中断服务程序中应尽量减少耗时操作,仅做必要的状态更新,显示刷新等耗时操作应放在主循环中。

3. 红外遥控系统集成

红外遥控提供了比物理按键更灵活的操作方式,本设计采用NEC协议解码。

3.1 红外接收硬件连接

引脚功能连接方式
PB9信号输入接VS1838B OUT
3.3V电源接VS1838B VCC
GND地线接VS1838B GND

3.2 NEC协议解码实现

使用TIM4输入捕获功能解码:

void REMOTE_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; TIM_ICInitTypeDef TIM_ICInitStruct; // GPIO配置 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStruct); // 定时器配置 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); TIM_ICInitStruct.TIM_Channel = TIM_Channel_4; TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStruct.TIM_ICFilter = 0x03; TIM_ICInit(TIM4, &TIM_ICInitStruct); // 中断配置 NVIC_EnableIRQ(TIM4_IRQn); NVIC_SetPriority(TIM4_IRQn, REMOTE_DECODE_PRIORITY); TIM_ITConfig(TIM4, TIM_IT_CC4|TIM_IT_Update, ENABLE); TIM_Cmd(TIM4, ENABLE); }

3.3 按键功能映射

将遥控器按键映射到计分器功能:

按键编码功能描述对应操作
0x45开始/暂停切换比赛状态
0x46节数+进入下一节
0x47主队+1分score_home++
0x44客队+1分score_away++
0x4024秒复位reset_attack_clock()

4. OLED显示系统优化

OLED显示需要呈现丰富的信息,同时保证刷新效率。

4.1 显示内容布局

采用分区域显示策略:

+-------------------------------+ | 主队 00 VS 00 客队 | 第1节 | +-------------------------------+ | 12:00.00 | 24 | +-------------------------------+

4.2 高效刷新策略

使用局部刷新减少数据传输量:

void update_score_display(void) { static uint16_t last_home = 0, last_away = 0; if(last_home != score_home) { OLED_ShowNum(10, 2, score_home, 2, 16, 1); last_home = score_home; } if(last_away != score_away) { OLED_ShowNum(54, 2, score_away, 2, 16, 1); last_away = score_away; } } void update_time_display(void) { static uint8_t last_min = 0, last_sec = 0; if(last_min != game_time.minutes) { OLED_ShowNum(10, 4, game_time.minutes, 2, 16, 1); last_min = game_time.minutes; } if(last_sec != game_time.seconds) { OLED_ShowNum(28, 4, game_time.seconds, 2, 16, 1); last_sec = game_time.seconds; } OLED_ShowNum(46, 4, game_time.centi_sec, 2, 16, 1); }

4.3 自定义字体集成

为增强显示效果,可以集成自定义字体:

// 16x16像素中文字模示例 const uint8_t CHINESE_FONT[][32] = { {0x00,0x40,0x00,0x44,0xFF,0xFE,0x00,0x40, // "主" 0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40, 0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40, 0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x40}, {0x00,0x00,0x1F,0xF8,0x10,0x08,0x10,0x08, // "客" 0x1F,0xF8,0x10,0x08,0x10,0x08,0x1F,0xF8, 0x00,0x00,0x3F,0xFC,0x20,0x04,0x20,0x04, 0x20,0x04,0x20,0x04,0x3F,0xFC,0x00,0x00} };

5. 系统调试与优化技巧

在实际开发过程中,以下几个调试技巧非常实用:

5.1 常见问题排查

红外接收不稳定

  1. 检查电源滤波电容(建议增加100μF电解电容)
  2. 调整接收头与遥控器的角度(最佳接收角度约±30度)
  3. 验证环境光干扰(避免强光直射接收头)

OLED显示异常

# I2C总线调试命令 $ i2cdetect -y 1 # 扫描I2C设备 $ i2cget -y 1 0x3C # 读取寄存器值

5.2 性能优化建议

  • 使用DMA传输OLED显示数据
  • 将频繁调用的函数声明为static inline
  • 启用编译优化选项(-O2或-Os)
  • 关键代码段使用__attribute__((section(".fastcode")))

5.3 扩展功能思路

  1. 无线同步:增加蓝牙模块,实现手机APP控制
  2. 数据记录:添加SD卡存储比赛历史
  3. 音效提示:集成蜂鸣器提供声音反馈
  4. 网络广播:通过WiFi模块实时传输比赛数据

在完成基础功能后,可以尝试将各个模块封装为独立的库,方便后续项目复用。例如创建timer_utils.coled_menu.c等模块化组件。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 7:18:07

AntiDupl.NET深度解析:5步精通开源图片去重工具

AntiDupl.NET深度解析&#xff1a;5步精通开源图片去重工具 【免费下载链接】AntiDupl A program to search similar and defect pictures on the disk 项目地址: https://gitcode.com/gh_mirrors/an/AntiDupl 你是否曾面对硬盘中堆积如山的重复图片感到束手无策&#x…

作者头像 李华
网站建设 2026/6/9 7:12:04

遗传算法工业落地核心:适应度设计与选择机制数学原理

1. 项目概述&#xff1a;为什么“遗传算法第二讲”比第一讲更值得你花时间重读“遗传算法第二讲”这个标题乍看平平无奇&#xff0c;像是教科书里被翻旧了的章节页码。但如果你真把它当成“进阶内容”跳过&#xff0c;或者只扫一眼伪代码就合上文档——那大概率会在三个月后的某…

作者头像 李华