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

别再只会点灯了!用STM32做个篮球计分器,把红外遥控、OLED显示和定时器中断一次学透 STM32实战从零打造智能篮球计分器掌握三大核心技能篮球比赛计分器看似简单却蕴含了嵌入式开发的精髓。本文将带您用STM32实现一个功能完备的篮球计分系统同时深入掌握红外遥控解码、OLED显示驱动和定时器中断三大关键技术。1. 项目整体架构设计一个完整的篮球计分系统需要处理多种实时任务精确计时、比分更新、显示刷新和用户输入响应。基于STM32F103C8T6的设计方案如下硬件组成模块主控芯片STM32F103C8T672MHz Cortex-M3内核显示模块0.96寸OLEDSSD1306驱动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延迟事件触发TIM4OLED显示5ms刷新30fpsI2C12. 精确计时系统实现比赛计时是篮球计分器的核心功能需要实现以下特性四节比赛每节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 OUT3.3V电源接VS1838B VCCGND地线接VS1838B GND3.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_home0x44客队1分score_away0x4024秒复位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 常见问题排查红外接收不稳定检查电源滤波电容建议增加100μF电解电容调整接收头与遥控器的角度最佳接收角度约±30度验证环境光干扰避免强光直射接收头OLED显示异常# I2C总线调试命令 $ i2cdetect -y 1 # 扫描I2C设备 $ i2cget -y 1 0x3C # 读取寄存器值5.2 性能优化建议使用DMA传输OLED显示数据将频繁调用的函数声明为static inline启用编译优化选项-O2或-Os关键代码段使用__attribute__((section(.fastcode)))5.3 扩展功能思路无线同步增加蓝牙模块实现手机APP控制数据记录添加SD卡存储比赛历史音效提示集成蜂鸣器提供声音反馈网络广播通过WiFi模块实时传输比赛数据在完成基础功能后可以尝试将各个模块封装为独立的库方便后续项目复用。例如创建timer_utils.c、oled_menu.c等模块化组件。