电赛井字棋无视觉方案:STM32按键矩阵与LED点阵实现
对于大一新生来说电赛的井字棋题目是一个很好的入门项目它综合了硬件控制、逻辑判断和状态管理。题目要求实现一个无视觉方案的井字棋对弈系统这意味着不能使用摄像头等视觉传感器来识别棋盘状态而是需要通过其他传感器如按键、触摸传感器、磁感应等来获取落子位置并通过点阵、LED灯阵或液晶屏来显示棋盘。无视觉方案的核心在于如何可靠地检测玩家的落子动作以及如何清晰地向玩家反馈当前棋盘状态。下面将围绕1到6问的实现提供一个完整的方案涵盖硬件选型、电路设计、核心逻辑、状态机和调试要点。1. 理解题目要求和核心挑战井字棋是一个3x3的棋盘两名玩家轮流在空格放置自己的棋子通常用X和O表示先连成一条直线横、竖、斜者获胜。如果棋盘填满仍未分出胜负则为平局。无视觉方案需要解决几个关键问题落子检测如何知道玩家在哪个位置落子。棋盘显示如何让玩家和裁判看清当前棋盘状态。游戏逻辑如何判断胜负、处理平局、管理游戏流程开始、轮流落子、结束、重置。人机交互除了基本的落子和显示可能还需要有开始按钮、重置按钮、胜负提示如LED灯、蜂鸣器等。对于大一新生建议从最基础的方案入手先实现功能再考虑优化。2. 硬件方案设计按键矩阵与LED点阵一个简单可靠的方案是使用按键矩阵作为输入LED点阵作为输出。2.1 硬件选型清单类别器件说明数量参考主控MCUSTM32F103C8T6 (核心板)资源丰富资料多性价比高1输入器件轻触按键用于9个棋格位置输入9独立按键用于开始/重置等功能1-2输出显示8x8 LED点阵屏 (带MAX7219驱动)可显示3x3棋盘驱动简单1状态指示LED灯红绿LED指示当前玩家、胜负状态2-3声音提示有源蜂鸣器落子提示、胜负提示1其他电阻、杜邦线、面包板/PCB10kΩ上拉电阻220Ω限流电阻若干注意如果题目对成本或功耗有特殊要求可以选用更简单的MCU如STC8系列、ATmega328P和更简单的显示方案如9个LED灯直接表示棋盘但点阵屏方案显示效果更直观专业。2.2 系统连接示意图[按键矩阵] ---- [MCU GPIO] ---- [LED点阵屏 (SPI)] [开始按键] ---- [MCU GPIO] ---- [状态LED] [重置按键] ---- [MCU GPIO] ---- [蜂鸣器]按键连接最简单的做法是9个棋格按键直接连接到MCU的9个GPIO口并配置为上拉输入。当按键按下时GPIO读到低电平。这种接法软件简单但占用IO口较多。如果IO口紧张可以排成3x3的矩阵只需要6个IO口但扫描程序稍复杂。LED点阵屏连接带MAX7219驱动的点阵屏通常通过SPI接口DIN, CLK, CS与MCU连接只需要3个IO口大大节省了资源。MAX7219芯片内部负责扫描显示MCU只需发送显示数据即可。3. 软件逻辑设计与实现软件是项目的核心需要清晰地管理游戏状态。3.1 定义关键数据结构和变量首先在代码开头定义核心的变量和数据结构。// 定义棋盘状态0为空1为玩家1(X)2为玩家2(O) uint8_t board[3][3] {0}; // 定义当前轮到哪位玩家落子 (1 或 2) uint8_t currentPlayer 1; // 定义游戏状态机 typedef enum { GAME_STATE_IDLE, // 空闲等待开始 GAME_STATE_PLAYING, // 对弈中 GAME_STATE_WIN, // 有玩家获胜 GAME_STATE_DRAW // 平局 } GameState_t; GameState_t gameState GAME_STATE_IDLE; // 按键引脚定义以STM32 HAL库为例假设使用9个独立GPIO #define KEY_START_PIN GPIO_PIN_0 #define KEY_START_PORT GPIOA // ... 定义其他9个棋格按键的PIN和PORT3.2 主循环与状态机主程序的核心是一个状态机根据不同的gameState执行不同的操作。int main(void) { // 硬件初始化 HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI1_Init(); // 初始化SPI用于点阵屏 LEDMatrix_Init(); // 初始化点阵屏 Buzzer_Beep(100); // 开机提示音 while (1) { switch (gameState) { case GAME_STATE_IDLE: idle_state_handler(); break; case GAME_STATE_PLAYING: playing_state_handler(); break; case GAME_STATE_WIN: case GAME_STATE_DRAW: game_end_state_handler(); break; } HAL_Delay(50); // 简单的延时避免过于频繁扫描 } }3.3 关键函数实现3.3.1 空闲状态 (GAME_STATE_IDLE)等待玩家按下开始按钮。void idle_state_handler(void) { // 在点阵屏上显示欢迎动画或提示Press Start LEDMatrix_ShowMessage(START); if (HAL_GPIO_ReadPin(KEY_START_PORT, KEY_START_PIN) GPIO_PIN_RESET) { HAL_Delay(20); // 简单消抖 if (HAL_GPIO_ReadPin(KEY_START_PORT, KEY_START_PIN) GPIO_PIN_RESET) { // 确认按键按下初始化游戏 game_init(); gameState GAME_STATE_PLAYING; Buzzer_Beep(50); } while (HAL_GPIO_ReadPin(KEY_START_PORT, KEY_START_PIN) GPIO_PIN_RESET); // 等待按键释放 } } void game_init(void) { // 清空棋盘 for (int i 0; i 3; i) { for (int j 0; j 3; j) { board[i][j] 0; } } // 随机或指定先手玩家 currentPlayer 1; // 更新显示 update_display(); }3.3.2 对弈状态 (GAME_STATE_PLAYING)这是最核心的状态循环扫描9个棋格按键。void playing_state_handler(void) { // 扫描9个按键 for (int row 0; row 3; row) { for (int col 0; col 3; col) { // 获取对应按键的GPIO状态假设有函数get_key_state if (get_key_state(row, col) KEY_PRESSED) { // 处理落子 process_move(row, col); // 处理一次按键后退出扫描避免连续落子 return; } } } } void process_move(int row, int col) { // 检查该位置是否为空 if (board[row][col] ! 0) { // 位置已被占用可以给个提示音或闪烁提示 Buzzer_Beep(20); return; } // 落子有效 board[row][col] currentPlayer; Buzzer_Beep(50); // 落子音效 // 检查胜负 if (check_win(currentPlayer)) { gameState GAME_STATE_WIN; // 闪烁获胜方棋子或显示WIN indicate_winner(currentPlayer); return; } // 检查平局 if (check_draw()) { gameState GAME_STATE_DRAW; // 显示平局提示 indicate_draw(); return; } // 游戏继续切换玩家 currentPlayer (currentPlayer 1) ? 2 : 1; // 更新棋盘显示可以用不同亮度或符号区分玩家 update_display(); }3.3.3 胜负判断函数 (check_win)这是经典的逻辑判断检查8条线3横、3竖、2斜。uint8_t check_win(uint8_t player) { // 检查行 for (int i 0; i 3; i) { if (board[i][0] player board[i][1] player board[i][2] player) { return 1; } } // 检查列 for (int j 0; j 3; j) { if (board[0][j] player board[1][j] player board[2][j] player) { return 1; } } // 检查对角线 if (board[0][0] player board[1][1] player board[2][2] player) { return 1; } if (board[0][2] player board[1][1] player board[2][0] player) { return 1; } return 0; } uint8_t check_draw(void) { for (int i 0; i 3; i) { for (int j 0; j 3; j) { if (board[i][j] 0) { return 0; // 还有空位不是平局 } } } return 1; // 棋盘已满平局 }3.3.4 显示更新函数 (update_display)将内存中的board数组映射到LED点阵屏的显示缓冲区。void update_display(void) { uint8_t displayBuffer[8] {0}; // 8x8点阵的显示缓冲区每字节代表一行 // 遍历3x3棋盘在8x8点阵上画出3x3的格子 // 例如可以用左上角的3x3区域来显示每个棋格占2x2个点 for (int i 0; i 3; i) { for (int j 0; j 3; j) { if (board[i][j] 1) { // 玩家1显示X // 在对应位置画X例如在(i*2, j*2)为中心的2x2区域 draw_x(displayBuffer, i*2, j*2); } else if (board[i][j] 2) { // 玩家2显示O draw_o(displayBuffer, i*2, j*2); } // 为空则什么都不画 } } // 还可以画上棋盘网格线增强可读性 draw_grid(displayBuffer); // 将缓冲区数据发送到点阵屏 LEDMatrix_SendBuffer(displayBuffer); } // 简单的画X函数示例在指定坐标画一个2x2的X void draw_x(uint8_t buf[8], int startRow, int startCol) { buf[startRow] | (1 (7 - startCol)) | (1 (7 - (startCol1))); buf[startRow1] | (1 (7 - startCol)) | (1 (7 - (startCol1))); // 这是一个非常简单的X实际可以画得更复杂美观 }4. 进阶优化与功能扩展实现基本功能后可以考虑以下优化来提升完成度和用户体验以应对电赛的评分要求。4.1 增加人机对战模式题目要求是双人对战但增加一个简单AI作为可选模式是很好的亮点。// 简单的AI寻找获胜机会否则随机落子 void ai_make_move(void) { // 1. 检查AI自己是否能一步获胜 for (int i 0; i 3; i) { for (int j 0; j 3; j) { if (board[i][j] 0) { board[i][j] currentPlayer; // 模拟落子 if (check_win(currentPlayer)) { // 就是这一步了 return; // 棋盘已经修改 } board[i][j] 0; // 撤销模拟 } } } // 2. 检查是否需要阻挡玩家获胜 uint8_t humanPlayer (currentPlayer 1) ? 2 : 1; for (int i 0; i 3; i) { for (int j 0; j 3; j) { if (board[i][j] 0) { board[i][j] humanPlayer; // 模拟玩家落子 if (check_win(humanPlayer)) { board[i][j] currentPlayer; // 实际落下AI的棋子进行阻挡 return; } board[i][j] 0; // 撤销模拟 } } } // 3. 如果中心空着优先占中心 if (board[1][1] 0) { board[1][1] currentPlayer; return; } // 4. 随机选择一个空位落子 int emptyCells[9][2]; int count 0; for (int i 0; i 3; i) { for (int j 0; j 3; j) { if (board[i][j] 0) { emptyCells[count][0] i; emptyCells[count][1] j; count; } } } if (count 0) { int choice rand() % count; board[emptyCells[choice][0]][emptyCells[choice][1]] currentPlayer; } }在playing_state_handler中如果当前是AI回合则调用ai_make_move然后直接进行胜负判断和切换玩家。4.2 完善显示与交互当前玩家提示用不同颜色的LED灯或点阵屏上的特定位置指示当前轮到谁。落子动画落子时让对应的棋子图案有一个短暂的闪烁或放大效果。胜负高亮当有玩家获胜时让连成一条线的三个棋子闪烁高亮。音效多样化为落子、获胜、平局、非法操作设置不同的音调或节奏。4.3 软件抗干扰处理按键消抖上面的代码使用了简单的延时消抖。更可靠的方法是使用状态机或定时器进行软件消抖。防止按键长按在等待按键释放的循环中增加超时判断避免程序卡死。// 改进的按键检测示例状态机消抖 typedef enum {KEY_IDLE, KEY_DEBOUNCE, KEY_PRESSED, KEY_RELEASE} KeyState_t; KeyState_t key_check(GPIO_TypeDef* Port, uint16_t Pin, KeyState_t currentState) { switch (currentState) { case KEY_IDLE: if (HAL_GPIO_ReadPin(Port, Pin) GPIO_PIN_RESET) { currentState KEY_DEBOUNCE; } break; case KEY_DEBOUNCE: HAL_Delay(10); if (HAL_GPIO_ReadPin(Port, Pin) GPIO_PIN_RESET) { currentState KEY_PRESSED; } else { currentState KEY_IDLE; } break; case KEY_PRESSED: if (HAL_GPIO_ReadPin(Port, Pin) GPIO_PIN_SET) { currentState KEY_RELEASE; } break; case KEY_RELEASE: HAL_Delay(10); if (HAL_GPIO_ReadPin(Port, Pin) GPIO_PIN_SET) { currentState KEY_IDLE; } else { currentState KEY_PRESSED; } break; } return currentState; }5. 常见问题与调试要点在实现过程中大一新生最容易遇到以下问题问题现象可能原因检查与解决思路按键无反应1. GPIO模式配置错误应为上拉输入2. 硬件连接虚焊或断路3. 消抖逻辑过于严格或错误1. 用万用表测量按键按下前后引脚电平变化。2. 写一个简单的测试程序只检测一个按键并点亮一个LED。点阵屏不显示或乱码1. SPI时序或模式不匹配2. MAX7219初始化命令错误3. 数据发送顺序MSB/LSB错误1. 查阅MAX7219数据手册确认初始化序列。2. 先尝试发送固定的简单图案如全亮、第一行亮来测试。游戏逻辑混乱如连续落子1. 按键扫描和处理逻辑有漏洞未处理好按键释放2. 状态机切换条件不清晰1. 在按键处理函数中加入while循环等待按键释放。2. 使用调试器或串口打印当前状态和按键值进行逻辑分析。胜负判断错误1.check_win函数逻辑错误2. 棋盘数组board的索引使用错误行列混淆1. 在平局、各种获胜情况下手动设置board数组单步调试check_win函数。程序运行不稳定1. 缺少看门狗2. 中断冲突3. 堆栈溢出1. 开启独立看门狗IWDG。2. 检查是否有不必要的中断或中断服务函数执行时间过长。调试建议分模块调试先让按键和LED灯正常工作再调试点阵屏显示最后整合游戏逻辑。善用串口打印使用printf通过串口输出变量值、函数执行状态这是最有效的调试手段之一。使用逻辑分析仪如果条件允许用逻辑分析仪检查SPI信号可以快速定位点阵屏的通信问题。6. 项目总结与扩展方向通过这个项目你能够掌握嵌入式系统开发的基本流程需求分析、硬件选型、电路搭建、软件模块化设计、状态机编程、调试排错。无视觉方案的核心是构建一个可靠的人机交互闭环。完成基础要求后可以考虑以下扩展来提升项目竞争力更复杂的AI实现极小化极大算法Minimax带Alpha-Beta剪枝使AI不可战胜。多种显示模式增加比分记录、历史对局回顾等功能。无线通信通过蓝牙或Wi-Fi实现两个独立设备的联机对弈。低功耗设计在空闲状态进入低功耗模式通过按键中断唤醒。这个项目很好地融合了硬件和软件是电子设计竞赛中控制类题目的典型代表。把基础功能做稳定、做流畅是取得好成绩的关键。

相关新闻

嵌入式ISP编程实战:寄存器访问模型与帧间操作详解

嵌入式ISP编程实战:寄存器访问模型与帧间操作详解

1. Camera ISP编程模型核心概念解析 在嵌入式视觉系统开发中,图像信号处理器(ISP)扮演着将原始传感器数据转化为可用图像的关键角色。它本质上是一个高度可配置的硬件流水线,而编程的核心,就是通过读写一系列硬件寄存器…

2026/8/11 19:21:01 阅读更多 →
OpenAI实时语音API与Asterisk SIP集成实战指南

OpenAI实时语音API与Asterisk SIP集成实战指南

1. 项目概述:这不是一个“调用API”的玩具,而是一套可落地的语音交互基础设施 你有没有遇到过这样的场景:客服系统永远在说“请按1转人工”,电话接通后却要等三分钟;或者企业想给老客户加个语音回访功能,结…

2026/8/11 20:09:01 阅读更多 →
USB技术演进与转串口开发实战指南

USB技术演进与转串口开发实战指南

1. USB技术基础与协议解析USB(Universal Serial Bus)作为现代计算机最常用的外设连接标准,其技术演进已经深刻影响了我们的数字生活。从1996年的USB 1.0到最新的USB4 2.0,传输速率从1.5Mbps提升至80Gbps,这种指数级增长…

2026/8/8 7:38:18 阅读更多 →

最新新闻

AGI基准测试框架:部署指南与模型评估实践

AGI基准测试框架:部署指南与模型评估实践

这次我们来看一个近期在技术圈引发讨论的项目:Eric Mitchell 宣布发布 AGI。这个名字听起来极具冲击力,但它的核心并非一个颠覆性的通用人工智能,而是一个旨在探索和评估 AI 模型在复杂、开放式任务中表现的基准测试框架。简单来说&#xff0…

2026/8/11 20:08:17 阅读更多 →
ComfyUI-Inspyrenet-Rembg核心功能全解析:批量处理、蒙版输出与性能优化

ComfyUI-Inspyrenet-Rembg核心功能全解析:批量处理、蒙版输出与性能优化

ComfyUI-Inspyrenet-Rembg核心功能全解析:批量处理、蒙版输出与性能优化 【免费下载链接】ComfyUI-Inspyrenet-Rembg ComfyUI node for background removal, implementing InSPyreNet the best method up to date 项目地址: https://gitcode.com/gh_mirrors/co/Co…

2026/8/11 20:08:17 阅读更多 →
同样做短视频营销,为什么你的同行客源不断?

同样做短视频营销,为什么你的同行客源不断?

当下,各类商家、品牌都在布局短视频拓客,但行业两极分化十分明显:一部分从业者依靠短视频稳定获取线索、持续沉淀新客;还有大量商家耗费大量时间运营,视频播放忽高忽低,真正有转化意向的咨询少之又少。抛开…

2026/8/11 20:08:17 阅读更多 →
你的外贸网站适合做SEO吗?先看这4个硬性条件

你的外贸网站适合做SEO吗?先看这4个硬性条件

带外贸团队这些年,我接过不少同事和同行的问题:“我们也想做SEO,但不知道网站适不适合。”我的回答一直很直接——不是所有网站都适合马上做SEO。有些网站先做SEO是锦上添花,有些先做是浪费时间。先搞清楚这4个条件,再…

2026/8/11 20:08:17 阅读更多 →
5分钟上手GitHub Linguist:开发者必备的代码语言检测工具

5分钟上手GitHub Linguist:开发者必备的代码语言检测工具

5分钟上手GitHub Linguist:开发者必备的代码语言检测工具 【免费下载链接】linguist Language Savant. If your repositorys language is being reported incorrectly, send us a pull request! 项目地址: https://gitcode.com/gh_mirrors/linguist3/linguist …

2026/8/11 20:08:17 阅读更多 →
如何借助AI获客系统实现潜在客户精准触达?

如何借助AI获客系统实现潜在客户精准触达?

如何借助AI获客系统实现潜在客户精准触达?当下很多企业在布局线上获客的过程中,常常遇到受众匹配度低、营销投入转化率差、潜在客户难以精准触达的难题,亟需更高效的获客工具打破困局。汇投流平台的核心是自研的“AI驱动的互联网获客系统”&a…

2026/8/11 20:07:17 阅读更多 →

日新闻

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南 【免费下载链接】video2x A machine learning-based video super resolution and frame interpolation framework. Est. Hack the Valley II, 2018. 项目地址: https://gitcode.com/GitHub_Trending/vi/v…

2026/8/11 0:00:02 阅读更多 →
前后端分离项目中控制台与接口工具数据差异排查指南

前后端分离项目中控制台与接口工具数据差异排查指南

1. 问题现象解析:控制台与Apifox的数据差异 最近在调试一个前后端分离项目时,遇到了一个典型问题:后端服务在本地开发环境控制台能正常输出查询数据,但通过Apifox测试时却返回空结果。这种"控制台有数据,接口工具…

2026/8/11 0:00:03 阅读更多 →
AI编程实战:从Claude Code踩坑到游戏开发入门

AI编程实战:从Claude Code踩坑到游戏开发入门

1. 从“AI能帮我做游戏”到“AI让我重新学编程”最近身边不少朋友,尤其是一些非技术背景、但对游戏开发有浓厚兴趣的朋友,都在问我同一个问题:“听说现在用Claude Code这种AI编程工具,小白也能做游戏了,是真的吗&#…

2026/8/11 0:00:03 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/11 1:08:05 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/11 1:08:05 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/11 1:08:05 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/11 17:09:45 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/11 1:08:06 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/11 17:09:45 阅读更多 →