FEATURED · 精选文章

基于STM32的五子棋对战平台:从LCD显示到AI联机的完整实现

发布时间 / 2026/9/9 1:35:55
来源 / 创域科博编辑部
栏目 / 资讯中心
基于STM32的五子棋对战平台:从LCD显示到AI联机的完整实现 简介面向STM32开发者和嵌入式游戏爱好者这是一套基于STM32F4原子探索者开发板的五子棋对战平台完整工程代码模块划分清晰覆盖LCD显示、触摸控制、棋局逻辑、人机AI与音量调节等环节。功能上支持触摸下子、人机对战、人人对战、悔棋、帮助与音量开关适合学习状态机设计、图形界面交互和简易博弈算法的读者也可参考移植到其他STM32平台。压缩包共274个文件大小5.44MB以C/H源码为主配合Keil工程文件uvprojx/uvoptx、编译中间文件o/crf以及烧录调试文件axf/hex/map/lst与PNG图片、说明文档既可直接打开工程编译烧录也可按需查看核心代码或界面预览。目前已有2166人学习下载尤其适合做课程设计、毕业设计或嵌入式小游戏入门参考。 做STM32项目最怕的不是外设复杂而是逻辑一多界面、按键、通信全都挤在一起互相打架。我最近把基于STM32的五子棋对战平台从零到一完整搭了一遍从LCD画棋盘、按键移动光标到三种玩法切换和AI计算踩过的坑能写满一整页。这篇文章就顺着项目实现顺序把硬件选型、五子棋逻辑、工程搭建、联机协议和实际调试过程记下来给准备做课设、毕设或者单纯想在自己板子上跑棋类游戏的朋友一个可以直接参考的完整方案。1. 项目定位STM32上到底能做什么样的五子棋1.1 三种对战模式一个平台很多人听到“基于STM32的五子棋对战平台”第一反应就是“在LCD上画个棋盘点一下落子不就行了”。但真正动手会发现如果只做同屏双人下棋那难度其实有限而“平台”两个字意味着玩法要成体系。我在这套项目里最终整合了三种对战模式第一种是同屏双人模式两个玩家共用一块触摸屏或按键光标轮流在同一台设备上落子第二种是人机对战模式设备内置一个基于评估函数和搜索算法的AI玩家执黑先行AI执白后手第三种是联机对战模式两台STM32通过串口连接各自的屏幕显示同一盘棋落子数据实时同步。从硬件职责上看三种模式共用同一套棋盘逻辑、同一套LCD绘制代码差异只在输入源和落子事件来源。所以在写代码之前我先把整体模块分成三层底层驱动负责LCD、按键、串口和Flash存储中间层负责棋盘规则和AI计算最上层只管理菜单、模式切换和事件分发。这样后面加新玩法时不需要重写界面和棋盘只要在上层加一个分支就能接入省掉了大量重复工作。1.2 硬件选型和资源分配主控我选了STM32F103RCT6原因很直接256KB Flash、48KB RAM72MHz主频带FSMC、多路USART和SPI驱动TFTLCD、无线模块都够用而且资料多、成本低网上随便一搜就能找到成熟的参考设计。LCD用的是2.8寸320x240的TFT屏接口走FSMC屏幕直接映射到内存地址刷屏速度比SPI模拟方式快了不止一个量级。输入部分初期用四个独立按键模拟方向键和确认键后期换成了带触摸的电阻屏。再看资源分配FSMC占用了GPIO的复用地址USART1留给串口联机USART2接调试日志SPI1预留挂NRF24L01无线模块。整个项目跑下来Flash占用大概60%左右RAM因为棋盘和缓存数组只用了不到20KB还有余量做后续扩展。如果条件允许强烈建议选带FSMC的芯片否则用SPI刷屏时哪怕只是局部刷新也会对AI计算和通信响应造成明显影响。2. 核心逻辑棋盘、胜负判定与人机AI2.1 棋盘数据结构与五连检测棋盘数据结构其实没有太多可发挥空间就是15x15的二维数组用uint8_t board[15][15]存储0表示空1表示黑棋2表示白棋。落子之前先检查坐标是否在边界内再检查目标位置是否为空写入数组后立即调用胜负检测函数。胜负检测是整个棋类项目的基石我一开始图省事直接全盘扫描遍历225个点、每个点查4个方向也能出结果但代码丑、逻辑乱还浪费了宝贵的MCU时间。后来改成只从当前落子点出发检查横、竖、两个对角线共4个方向每个方向分别向正负两侧数同色连续棋子的数量加起来大于等于5就判胜。这样每次检测只需要很小的计算量而且顺手还能拿到当前点的连子信息给后面AI的评估函数复用一举两得。#define BOARD_SIZE 15 uint8_t board[BOARD_SIZE][BOARD_SIZE]; int check_win(int row, int col, uint8_t player) { int dirs[4][2] {{0,1},{1,0},{1,1},{1,-1}}; for (int d 0; d 4; d) { int cnt 1; for (int i 1; ; i) { int nr row dirs[d][0] * i; int nc col dirs[d][1] * i; if (nr 0 || nr BOARD_SIZE || nc 0 || nc BOARD_SIZE || board[nr][nc] ! player) break; cnt; } for (int i 1; ; i) { int nr row - dirs[d][0] * i; int nc col - dirs[d][1] * i; if (nr 0 || nr BOARD_SIZE || nc 0 || nc BOARD_SIZE || board[nr][nc] ! player) break; cnt; } if (cnt 5) return 1; } return 0; }这个函数在STM32上执行一次只需要几微秒即使每步调用多次也不会有性能压力。但真正吃性能的是AI搜索所以把检测逻辑做干净对后续优化非常关键。2.2 评估函数与Alpha-Beta搜索人机对战的AI是很多人最关心的部分。STM32算力有限不可能跑深度学习网络所以要靠传统博弈搜索。我采用的是评估函数加带Alpha-Beta剪枝的极小化极大搜索搜索深度设在2到4层之间。深度为2时每步大约几十毫秒深度为4时最坏情况可能到一两秒需要配合剪枝和着法排序才能流畅运行。评估函数是AI的“棋感”对棋盘上每个空白点模拟落子后计算它在四个方向上的连子形状然后按形状给分。我用的分数表大概是成五给100000分活四给10000分冲四给5000分活三给2000分眠三给500分活二给200分眠二给50分。攻击分看我落在这里能形成多少威胁防守分看对方落在这里能形成多少威胁最终分数取攻击分和防守分中的较大值再乘一个系数。这样AI既会主动进攻又会在必要时防守而不是只朝一个方向猛冲。实际调试时发现纯评估函数有个问题AI经常在对方已经形成双活三时才想起来防守已经晚了。所以我加了一个强制应手逻辑如果棋盘上已经存在活三或冲四级别的威胁AI不再做完整搜索而是优先处理最危险的位置。这个策略虽然牺牲了一点棋力但响应速度非常快玩家会感觉AI“知道堵你”游戏体验反而更好。对小资源MCU来说用规则补足搜索深度是一个很实用的折中方案。2.3 双机联机协议从握手到落子联机模式比想象中复杂最大的难点不是串口收发而是如何保证两台设备上的棋盘状态始终一致。我定义的帧格式是帧头0xAA 0x55命令字1字节数据长度1字节数据若干字节校验1字节。命令字包括握手请求、握手应答、落子通知、悔棋请求、认输和重置棋盘。落子通知的数据只有两个字节就是X和Y坐标校验采用累加和简单但够用。接收端用状态机逐字节解析帧头匹配成功后进入长度接收再接收数据体和校验校验通过才执行命令。如果没有状态机直接在串口中断里拼接Buffer很容易在连续发两帧时把第二帧的帧头混进第一帧的数据里导致整包数据错乱。握手时主机发送0x01从机收到后回复0x02并同步棋盘之后每下一步都带上相同的帧头如果一方断开另一方就进入等待重连状态。这套协议我用串口助手模拟连续对打了一小时115200波特率下没有丢帧。这里还要注意“时序”问题。STM32上如果只有一套主循环联机模式下发送落子数据时必须等通信完成界面不能立即刷新到自己的棋盘上否则两台设备的显示会不一致。我把一次完整的落子流程定义为玩家落子、本地显示、发送数据到对端、等待ACK、才进入下一轮。虽然会有轻微延迟但换来的是可靠的同步体验。3. 工程实现显示、按键与通信模块3.1 新工程搭建标准库还是HAL动手第一步是搭工程。我用的标准库原因不是HAL不好而是这个项目要频繁操作FSMC、中断和寄存器级别的配置标准库的文档和现成例程更多遇到问题很容易找到参考。用CubeMX生成HAL工程也能做但要注意HAL库很多函数内部带有超时机制在通信或LCD刷屏这种高频调用场景下Timeout处理不好会拖慢整体响应。不管用哪个库时钟树必须确认。我板子上外部晶振是8MHz通过PLL倍频到72MHzLCD的FSMC时序也要根据屏幕手册配置读写周期太长会明显拖慢刷屏太短又可能出现花屏。关于工程结构我把代码按app、game、drv三层分组drv管LCD、按键、串口驱动game管棋盘逻辑和AIapp管菜单和模式切换。这样在Keil里用分组管理后期加功能不会把main.c写成一个几千行的巨型文件。另外现在用VSCode开发STM32也成了不少人的选择EIDE插件配合arm-none-eabi-gcc和CMake确实比Keil更现代化但调试仍然离不开ST-Link配套的调试器。如果你刚开始做这个项目我建议先老老实实用Keil 标准库跑通等整体框架稳定后再考虑迁移工具链否则编译环境和调试问题会分散太多精力。3.2 LCD增量刷新别把时间耗在清屏上五子棋界面如果每下一步都全屏重绘一次F103虽然能跑但能明显看到闪烁和延迟。我采用的方案是棋盘背景只在初始化时绘制一次之后每次落子只画一个实心圆、更新焦点框、刷新状态栏文字。这样单步绘制时间从几十毫秒降到了几毫秒玩家操作手感完全不同。要注意LCD控制器内部的GRAM和MCU这边的显存不是一回事。用ILI9341这类屏幕时你先设置窗口坐标再向对应区域写入像素数据它会自动更新内部GRAM所以局部画圆并不需要重刷整个屏幕。焦点框的实现则用“先擦除旧框再绘制新框”的方式擦除就是用背景色在旧框位置画一个矩形。颜色选择上棋盘线条用深棕色黑棋用黑色加白边白棋用暖白色加灰边对比度和层次感都会好很多。如果觉得局部刷新还是不够快可以把LCD的写数据改成DMA传输。FSMC方式下先算出要写窗口的像素数组长度然后启动DMA搬运CPU可以在传输期间继续处理AI和按键逻辑。实测下来普通局部刷新加DMA之后整个界面流畅度接近商品级的掌机体验。3.3 按键消抖与光标移动按键扫描我放在定时器中断里每10ms扫描一次GPIO连续两次读到相同电平才确认有效这是最基础的消抖。但很多人会忽略重复触发问题按一下方向键光标连跳三格就是因为没有做“按下并释放才触发一次”的边沿判断。正确做法是记录上一次按键状态只在状态由“未按下”变为“按下”时执行一次移动命令如果要支持长按连续移动可以额外判断按下时长超过500ms后每150ms触发一次。光标移动时要限制在棋盘范围内同时维护一个焦点坐标变量确认键按下时在焦点位置落子并调用胜负检测。这里有个小经验在落子处理函数里加一个input_enabled标志AI计算或通信过程中禁止按键操作否则玩家快速连按会导致AI还在搜索棋就已经落下了数据直接乱套。按键电路设计上也别太随意。独立按键最好用外部上拉电阻接到GPIO或者干脆用内部上拉然后在按键另一端接GND。如果用了触摸屏方案XPT2046的ADC会有轻微漂移需要在初始化时做两点校准和多点平均不然点击位置总差一两个像素玩家会明显觉得“点不准”。4. 调试实录从连不上芯片到棋盘卡顿4.1 仿真器连接失败的排查顺序做STM32项目最劝退的时刻就是点击下载仿真Keil弹出一句error: no stm32 target found! if your product embedsdebug authentication, pl...。我在这个项目里遇到三次连不上第一次是ST-Link的SWDIO和SWCLK被FSMC引脚复用了FSMC配置代码跑起来后直接占用了调试口第二次是目标板供电不足ST-Link给板子供电带不动LCD芯片还没完全启动第三次是BOOT0跳线意外拉高芯片进入了ISP模式调试接口完全无响应。排查顺序我建议固定下来先量板子供电确认目标芯片电压稳定再查BOOT0是否为低电平ST-Link是否被系统识别如果确认正常按着复位键再点下载同时在调试器设置里把连接模式改成Reset under Cortex-M如果还不行把BOOT0拉高用串口ISP的全擦除功能清空Flash再用ST-Link重新连接。这个顺序能覆盖绝大多数“目标找不到”的情况比反复插拔USB线高效得多。4.2 AI落子慢问题不一定在算法有段时间AI每步要卡两三秒我以为是搜索深度太高把深度从4降到2还是慢。后来用示波器量一个GPIO翻转周期才发现瓶颈根本不在算法而在LCD绘制的延时函数。工程里很多地方用了循环变量实现的delay_ms它在AI计算间隙被调用把整条流水线堵住了AI再快也快不起来。解决办法是把所有频繁场景下的延时改成非阻塞方式或者减少阻塞延时的调用次数。LCD刷屏改DMA后AI计算时不需要等屏幕绘完界面更新放到计算完成后再一次性执行。这样调整后深度为3的搜索加AI落子绘制整步响应稳定在500ms以内已经非常接近上手游棋牌应用的感觉。调试嵌入式项目时性能问题不要只盯着算法复杂度IO、延时、外设时钟这些“环境因素”往往才是真凶。4.3 串口联机收不到数据的定位思路双机联机调试时遇到最诡异的问题单一台设备用串口助手收发都正常但两台设备直连后经常收不到落子数据。检查发现是共地问题——两个开发板各自用USB供电地线没有连到一起TTL电平的参考地不同信号自然对不上。把两个板子的GND连起来之后问题立刻消失。另一个坑是波特率误差。两个板子如果都用内部时钟或者外部晶振精度不足长期运行会产生漂移偶尔出现乱码。解决方案是改用外部8MHz晶振并把USART波特率设在115200以下给误差留出余量。协议层也要做超时重发发送方发出落子通知后2秒内没收到ACK就自动重发上一帧最多重发3次。我在实际测试中把两台设备放桌上跑了一整局联机对战总共一百来手只出过一次重发重发后数据也对齐了。这说明只要协议层做好状态机、校验和超时重传串口联机完全能达到可玩的稳定度。最后再分享一个小经验如果你也想在自己板子上复刻这个项目先别急着加无线通信用有线串口把联机流程跑通再去折腾NRF24L01或ESP8266。无线模块会把问题复杂度翻倍而串口模式下所有协议问题都更容易复现和定位。这个项目给我最大的体会是嵌入式做棋类游戏真正花时间的不是五子棋规则本身而是如何在资源有限的MCU上把显示、输入、通信和AI算法协调好。先把增量刷新、状态机和事件分发这三件事做好后面加什么模式都会顺很多。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻