Arduino游戏机实战:从零打造锤子剪刀布交互设备 📅 2026/7/29 8:53:10 1. 项目缘起为什么是“锤子剪刀布”游戏机几年前我在一所中学的创客社团做指导老师发现一个挺有意思的现象很多孩子对编程和硬件有好奇心但传统的“点亮LED灯”或者“让舵机转一下”这类入门项目对他们来说吸引力正在快速衰减。他们需要的是一个有明确目标、有完整交互、并且能“秀”出来的作品。正好那段时间几个学生课间在玩“锤子剪刀布”我就想能不能把这个简单的游戏变成一个看得见摸得着的实体机器这就是“锤子剪刀布”游戏机项目的起点。它不是一个复杂的工业产品而是一个绝佳的STEAM教育载体。你看“锤子剪刀布”规则人尽皆知胜负逻辑简单石头赢剪刀剪刀赢布布赢石头这完美解决了项目定义中的“核心玩法”问题学生不用在游戏规则上耗费精力。但要把这个逻辑用硬件实现并做出一个酷炫的交互外壳就需要串联起多个知识点Arduino负责“大脑”逻辑判断与输入输出OLED屏幕作为“脸面”显示结果与动画3D打印打造“身体”定制化外壳与结构。这正好覆盖了编程、电子电路和三维设计三大块而且最终成品是一个可以两人对战、有声光反馈的“玩具”成就感直接拉满。这个项目特别适合作为中学生Arduino课程的期中或期末综合实践。它用到的核心元器件不多成本可控但涉及的知识链完整。从用SketchUp或类似软件画一个放得下所有零件的外壳到用Arduino IDE编写代码处理按钮输入、驱动OLED显示、控制胜负逻辑再到最后把3D打印的零件和电路板组装起来调试成功。整个过程学生能清晰地看到自己写的每一行代码、画的每一根线条如何一步步变成一个可以实际运行、可以和朋友一起玩的设备。这种从虚拟到实体的创造过程正是创客教育的精髓所在。2. 核心器件选型与功能拆解做一个游戏机我们得先想清楚它需要哪些“器官”以及为什么选这些“器官”。盲目堆砌高级器件只会增加成本和复杂度对于教学项目够用、稳定、易得是关键。2.1 大脑Arduino Uno R3——经久不衰的起点主控板我们选择Arduino Uno R3。这是几乎所有创客入门的第一块板子没有之一。选择它理由很充分第一资源极其丰富。无论中文社区还是英文论坛你遇到的几乎所有基础问题都能找到现成的解决方案和代码示例。第二引脚功能清晰。14个数字IO口6个模拟输入口对于本项目两个按钮输入、一个OLED输出、几个LED和蜂鸣器绰绰有余而且引脚排列规整方便学生理解和插线。第三供电和驱动简单。一根USB线就能完成供电和程序下载对教学环境极其友好。有些朋友可能会问用更便宜的Arduino Nano或者功能更强的ESP32行不行当然可以。但作为面向中学生的课程Uno的板载USB芯片和标准布局能最大程度减少在“连接电脑”这个第一步上遇到的奇葩问题。Nano需要额外的USB转TTL模块ESP32的引脚定义和库支持相对复杂一些。我们的首要目标是让学生快速建立“编程-上传-运行”的正向反馈Uno是最稳妥的选择。等这个项目做熟了再迁移到其他板子上会是非常好的进阶练习。2.2 眼睛0.96寸OLED显示屏I2C接口——信息展示的核心显示部分我强烈推荐使用0.96寸的OLED屏幕并且一定要选I2C接口的版本。为什么是OLED而不是LCD首先OLED是自发光对比度高显示黑色时像素点完全不亮在显示我们画的像素风锤子、剪刀、布图案时效果会非常锐利、有科技感。其次它功耗低视角广。最重要的是I2C接口只需要占用主控板的两个IO口SDA和SCL就能完成所有通信极大地简化了接线。四根线VCC, GND, SDA, SCL就能搞定这对初学者来说太友好了。市面上常见的OLED驱动芯片是SSD1306对应的Adafruit SSD1306和U8g2库都非常成熟。在这个项目里我们会用到它做三件事1. 显示待机界面和操作提示2. 显示倒计时动画增加游戏紧张感3. 同时显示玩家A和玩家B的选择图案并公布胜负结果。一个清晰的视觉反馈是游戏体验不可或缺的一环。2.3 筋骨3D打印外壳——从概念到实体的桥梁外壳是整个项目的“颜值担当”和“结构工程师”。它需要容纳Arduino主板、OLED屏幕、按钮、电池盒等所有部件并预留出按钮孔、屏幕窗、USB接口等位置。设计工具上SketchUp是个不错的选择它界面相对直观学习曲线平缓适合中学生快速上手基本的三维建模。当然如果学校有条件使用Fusion 360或Onshape这类更专业的参数化设计软件会更好它们对后续的修改和调整更有利。设计外壳时要特别注意几个尺寸第一OLED屏幕的精确外形尺寸和安装孔位第二按钮的直径和高度通常选用12mm或16mm的轻触开关第三Arduino Uno的板子尺寸和引脚位置。我的经验是先在纸上画一个简单的布局草图确定各个元件的大概位置和朝向然后再到软件里精确建模。外壳可以设计成上下盖结构用螺丝固定方便后期调试和维修。打印材料选择普通的PLA即可坚固且易于打印。2.4 感官与反馈按钮、LED与蜂鸣器输入按钮。我们需要两个按钮分别给两位玩家使用。选择最常见的6x6mm或12x12mm四脚轻触开关即可。接线时要注意需要接一个上拉电阻通常10K欧姆到VCC或者直接使用Arduino内部的上拉电阻通过代码设置pinMode(pin, INPUT_PULLUP)以确保按钮未按下时引脚状态是稳定的高电平按下时变为低电平。这是避免信号抖动和误判的关键。输出LED与蜂鸣器。为了增加游戏氛围我们可以增加几个LED和一个小型无源蜂鸣器。例如可以设置三个LED分别对应“赢”、“输”、“平局”三种结果蜂鸣器则播放不同的简短音效。LED需要串联一个220欧姆的限流电阻。蜂鸣器可以直接接在数字引脚上通过tone()函数播放音调。这些声光反馈能立刻让项目变得生动起来。3. 电路连接与“Proto Shield”的妙用对于初学者尤其是中学生最头疼的往往不是写代码而是那一堆乱七八糟的杜邦线和面包板。线路复杂容易接触不良作品看起来也很“实验”不够结实。这里我要强力推荐一个神器Proto Shield原型扩展板。Proto Shield是一块可以直接插在Arduino Uno上的PCB空板上面有和Uno引脚一一对应的焊盘和排母。我们的策略是将所有外围器件OLED、按钮、LED、蜂鸣器先永久性地焊接在这块Proto Shield上。这样做有巨大好处可靠性飞跃焊接连接远比插接牢固彻底杜绝了接触不良和线头松脱的问题。整洁美观所有线路都藏在板子下面或用排线规整连接最终作品内部非常清爽。易于集成整个“大脑”模块Arduino Uno Proto Shield可以作为一个整体轻松地安装进3D打印的外壳里只需要考虑固定孔位即可。教学意义让学生经历从面包板原型到焊接成品的完整流程这是电子制作从“实验”走向“产品”的关键一步。具体的接线图示意图如下但核心是规划好Proto Shield上的布局Arduino Uno Proto Shield 接线规划 - OLED (I2C): VCC - 5V, GND - GND, SDA - A4, SCL - A5。 - 玩家A按钮: 一脚接数字引脚2另一脚接GND配合内部上拉。 - 玩家B按钮: 一脚接数字引脚3另一脚接GND。 - 胜利LED绿: 长脚通过220Ω电阻接数字引脚4短脚接GND。 - 失败LED红: 长脚通过220Ω电阻接数字引脚5短脚接GND。 - 平局LED黄: 长脚通过220Ω电阻接数字引脚6短脚接GND。 - 蜂鸣器: 正极接数字引脚7负极接GND。注意实际焊接前务必先在面包板上完整测试所有功能确认代码和硬件都没问题。焊接是一门需要练习的技能对于中学生建议使用尖头烙铁配合助焊剂和吸锡带并在老师指导下进行。4. 游戏逻辑与代码实现详解有了硬件基础我们来看看软件部分也就是游戏的核心逻辑。代码我们将用Arduino IDE编写整个程序可以分成几个清晰的模块。4.1 状态机让程序逻辑清晰起来对于这种交互式项目我习惯使用“状态机”的思维来设计。简单说就是游戏在任何时刻都处于一个明确的状态不同状态下程序对输入的反应和显示的内容都不同。这能让代码结构非常清晰避免一堆if-else嵌套带来的混乱。我们可以定义以下几个状态enum GameState { STATE_IDLE, // 空闲等待状态显示欢迎语 STATE_COUNTDOWN, // 倒计时状态显示3-2-1动画 STATE_INPUT, // 等待玩家按键输入状态 STATE_SHOW_RESULT // 显示结果状态 }; GameState currentState STATE_IDLE;程序的主循环loop()就围绕着currentState变量展开用一个switch-case结构来处理不同状态下的任务。4.2 核心函数胜负判断与随机生成游戏的核心逻辑是一个简单的比较函数。我们给锤子、剪刀、布分别赋值比如012。#define ROCK 0 #define SCISSORS 1 #define PAPER 2 // 判断胜负返回结果0-平局1-玩家A赢2-玩家B赢 int judge(int choiceA, int choiceB) { if (choiceA choiceB) { return 0; // 平局 } if ((choiceA ROCK choiceB SCISSORS) || (choiceA SCISSORS choiceB PAPER) || (choiceA PAPER choiceB ROCK)) { return 1; // A赢 } return 2; // 否则B赢 }为了让单人也能玩或者增加趣味性我们可以加入一个“电脑玩家”。用random(min, max)函数即可生成一个随机选择。int getComputerChoice() { return random(0, 3); // 生成0,1,2之间的随机数 }注意需要在setup()函数里用randomSeed(analogRead(A0))来读取一个未连接的模拟引脚噪声作为随机种子这样每次的随机序列才会不同。4.3 OLED动画与界面绘制使用U8g2库来驱动OLED会非常方便。它支持丰富的绘图函数和字体。在STATE_COUNTDOWN状态我们可以实现一个简单的数字倒计时动画// 在倒计时状态 u8g2.clearBuffer(); u8g2.setFont(u8g2_font_logisoso32_tf); // 设置大字体 u8g2.setCursor(40, 40); u8g2.print(countdownNumber); // 显示 3, 2, 1 u8g2.sendBuffer(); delay(1000); // 等待1秒 countdownNumber--;在STATE_SHOW_RESULT状态则需要同时绘制两个玩家的选择图标。我们可以事先用取模软件如PCtoLCD2002将锤子、剪刀、布的简单图标转换成位图数组存储在程序中然后根据选择调用drawXBMP()函数显示。4.4 主循环逻辑与控制流一个典型的主循环结构如下void loop() { switch (currentState) { case STATE_IDLE: // 显示“Press Button to Start” if (按钮A或B被按下) { currentState STATE_COUNTDOWN; countdownNumber 3; } break; case STATE_COUNTDOWN: // 执行倒计时动画 if (倒计时结束) { currentState STATE_INPUT; // 如果是单人模式在此生成电脑的选择 } break; case STATE_INPUT: // 显示“请出拳”提示 // 等待两个玩家都做出选择或单人模式下玩家做出选择 if (输入完成) { currentState STATE_SHOW_RESULT; } break; case STATE_SHOW_RESULT: // 显示双方选择图案和胜负结果 // 控制对应的LED和蜂鸣器 delay(3000); // 结果显示3秒 currentState STATE_IDLE; // 重置游戏 break; } }这种结构化的编程方式非常有利于学生理解事件驱动的程序是如何运行的。5. 3D外壳设计实战与打印要点电路和代码都搞定后我们需要给它们一个“家”。3D设计是很多学生的难点但也是从想法到实物最关键的一跃。5.1 从测量到建模SketchUp基础操作首先精确测量。用游标卡尺测量所有关键元件的尺寸Arduino Uno的长宽高含USB口和电源插座的突起、OLED屏幕的板子尺寸和显示区域位置、按钮的直径和高度、蜂鸣器的直径、电池盒的尺寸等。把这些数据记在笔记本上。打开SketchUp第一步是设置单位毫米。然后从一个长方体开始这个长方体就是外壳的主体。根据你规划的内部布局确定外壳的大致内腔尺寸。比如我习惯将Arduino主板放在底部Proto Shield竖着插在上面OLED屏幕则位于外壳正面。那么外壳的宽度至少要大于Arduino的宽度约53mm高度要大于“Arduino高度Proto Shield上元件高度”深度要能容纳OLED屏幕的厚度。使用“推/拉”工具来开孔。给OLED屏幕开一个显示窗口这个窗口最好比屏幕显示区域稍大一点但比整个屏幕板子小这样屏幕可以从内部卡住。按钮孔的开孔直径要比按钮柄的直径略小比如小0.2mm这样按钮按下去才会有紧实感不会晃动。USB口和电源开关处也要开出相应的槽口。5.2 结构设计分体、卡扣与螺丝柱为了方便组装和维修外壳通常设计成上下盖。上下盖的接合方式有两种常见选择螺丝固定和卡扣固定。对于教学项目我推荐螺丝固定虽然没那么“高级”但更可靠也让学生练习了钻孔和拧螺丝。在设计时就要在上下盖的四个角设计好螺丝柱。螺丝柱是内部凸起的圆柱中间有孔用于穿过螺丝。螺丝柱的外径要足够大通常大于6mm以确保有足够的强度不会在拧螺丝时破裂。上下盖的定位可以通过设计定位柱和定位孔来解决。在下盖上设计几个小圆柱在上盖对应位置设计几个孔组装时先对准插上再上螺丝这样就不会错位。实操心得在设计螺丝柱时一定要在软件里为螺丝通常是M3螺丝和螺母预留空间。螺丝孔的内径建议在2.8mm-3.0mm这样M3螺丝可以轻松拧入自攻。如果你打算嵌入螺母那么设计一个六边形的凹槽来固定螺母会非常专业。5.3 切片与打印避免失败的细节模型设计好后导出为STL格式用Cura、PrusaSlicer等切片软件进行切片。打印设置直接影响成品质量层高0.2mm是个平衡了精度和速度的好选择。填充密度15%-20%足够外壳本身就有一定强度。支撑如果模型有悬空部分比如螺丝柱的顶部必须生成支撑。记得在切片预览里仔细检查。打印方向尽量让外壳的大面作为底面打印。这样打印出来的外壳底面非常平整而且侧面Z轴方向的强度最高。避免将螺丝柱的轴线方向作为打印的Z轴那样螺丝柱的层间结合力弱容易在受力时开裂。耗材PLA是最佳选择它打印温度低不易翘边无异味非常适合教室环境。打印完成后小心地去除支撑然后用小锉刀或砂纸打磨一下按钮孔和屏幕窗口的边缘使其光滑不划手。6. 总装、调试与项目升华最后一步是把所有部分组装起来并解决最后1%的问题。6.1 分步组装流程硬件集成将OLED屏幕、按钮、LED、蜂鸣器按照之前的规划焊接在Proto Shield上。焊接完成后务必先不要插到Arduino上用万用表通断档检查是否有短路特别是VCC和GND之间。功能测试将Proto Shield插到Arduino Uno上连接USB线到电脑上传一个最简单的测试程序例如分别测试每个按钮按下时串口输出、每个LED点亮、OLED显示测试图案、蜂鸣器发声确保所有硬件功能正常。外壳预装将焊接好的“核心板”ArduinoShield尝试放入下壳看看是否顺畅螺丝孔位是否对齐。将按钮帽、OLED屏幕通常用一点热熔胶或螺丝固定安装到外壳上。最终总装将核心板正式固定到下壳可以用螺丝或尼龙柱连接好电池盒如果需要便携。然后盖上上盖拧紧所有螺丝。整机测试装好后再次上电进行完整的游戏流程测试。6.2 常见问题与调试技巧问题一按钮不灵敏或连击。这通常是消抖没做好。除了在硬件上可以加一个小电容0.1uF并联在按钮两端在软件上必须做消抖处理。最简单的办法是在检测到按钮按下后延时20-50毫秒再读取一次引脚状态如果仍然是按下状态才认为是有效按键。if (digitalRead(buttonPin) LOW) { // 假设按下为低电平 delay(50); // 延时消抖 if (digitalRead(buttonPin) LOW) { // 确认按键 } }问题二OLED不显示。首先检查接线VCC, GND, SDA, SCL是否正确且牢固。其次检查代码中OLED的I2C地址是否正确。最常见的地是0x3C但也有可能是0x3D。可以用一个I2C扫描程序来确认地址。最后确认初始化代码u8g2.begin()是否成功执行。问题三3D打印件螺丝孔拧裂。这是打印强度问题。除了前面提到的打印方向可以在切片软件中增加螺丝孔周围的圈数壁厚。或者在组装时先用一个比螺丝细一点的钻头如2.5mm轻轻扩一下孔再拧入螺丝会顺畅很多。问题四程序运行一段时间后死机。检查代码中是否有内存泄漏比如在循环中不断创建String对象或者是否有中断服务程序ISR处理时间过长。对于中学生项目尽量避免使用复杂的中断用主循环查询按钮状态通常就足够了。6.3 项目扩展与思考这个基础版本完成后它就像一个开放的积木平台可以引导学生进行无数有趣的扩展难度升级改为“蜥蜴史波克”扩展版来自《生活大爆炸》增加两种手势逻辑判断矩阵会更大对编程是很好的锻炼。功能升级加入WS2812 RGB LED灯环根据胜负显示炫彩光效。或者加入一个MP3播放模块播放更酷的音效甚至语音。联机对战用两个ESP32主板替换Uno利用Wi-Fi或蓝牙功能实现两台游戏机之间的无线对战。这立刻将项目提升到了物联网和无线通信的层面。数据统计加入一个SD卡模块记录每一局的对战结果和胜负历史然后通过OLED回看统计数据。从一个简单的“锤子剪刀布”想法出发到完成一个集3D设计、电子焊接、单片机编程于一体的实体作品这个过程中学生收获的绝不仅仅是几个孤立的知识点。他们学会了如何将一个复杂问题分解成硬件、软件、结构等多个子问题如何查找资料、调试错误、迭代改进更重要的是他们亲手创造了一个能带来快乐的实物。这种综合性的实践能力和创造力的培养正是这个项目最大的价值所在。当学生们围着自己做的游戏机争相挑战时那种眼神里的光就是对我们课程设计最好的肯定。