亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

Arduino 记忆力挑战游戏 (Simon 复刻版) 制作教程

零部件清单

组件 数量 规格/备注
Arduino Uno R3 1 主控
LED (红/绿/蓝/黄) 各 1 共 4 色,直插 3mm/5mm
330Ω 电阻 4 LED 限流
10kΩ 电阻 4 按键下拉
轻触开关 (6x6mm) 4 对应 4 个 LED
无源蜂鸣器 1 接 D5,可选
全尺寸面包板、杜邦线 1 套 搭建电路

电路原理

每个「按键+LED」共用一个 Arduino 引脚,通过切换引脚模式实现双向复用:

电路拓扑 (每通道相同):

Arduino Pin (D2/D13/D10/D8)
    │
    ├─[330Ω]─┬─[LED]─┐
    │        │       │
    │       GND     GND
    │
    ├─[10kΩ]─┐
    │        │
    └─[Button]─VCC (按下接通)

蜂鸣器接 D5 (PWM),一端接 GND,另一端接引脚,用 analogWrite() 产生方波发声。

游戏规则

  1. 上电后 3 秒延时,全灯慢闪 5 次 (500ms 间隔) → 游戏开始
  2. 系统随机点亮 1 个 LED (伴随蜂鸣),玩家须在 2 秒内按下对应按键
  3. 每轮成功,序列长度 +1,系统完整播放新序列,玩家重复
  4. 按错键、超时 (2秒)、按键顺序错误 → 判负,全灯快闪 50ms × 5
  5. 失败后回放最后正确序列 (可数分数),再慢闪 5 次进入下一局
  6. 最高分挑战:作者记录 22 级

核心代码逻辑解析

关键变量


#define PLAYER_WAIT_TIME 2000  // 玩家响应超时 (ms)
byte sequence[100];            // 存储随机序列 (引脚号)
byte curLen = 0;               // 当前序列长度
byte inputCount = 0;           // 本轮已正确输入数
byte expRd = 0;                // 期望的按键引脚
bool btnDwn = false;           // 按键按下标志 (防重复触发)
bool wait = false;             // true=玩家回合, false=系统回合
bool resetFlag = false;        // 判负标志
byte pins[] = {2, 13, 10, 8};  // 4通道引脚 (按键+LED共用)
byte noPins = 4;               // 通道数

主循环状态机


void loop() {
  if (!wait) {  // ====== 系统回合 ======
    setPinDirection(OUTPUT);
    randomSeed(analogRead(A0));
    sequence[curLen] = pins[random(0, noPins)]; // 新增随机步
    curLen++;
    playSequence();   // 顺序播放整个序列
    beep(50);
    wait = true;      // 切换到玩家回合
    inputTime = millis();
    inputCount = 0;
  }
  else {        // ====== 玩家回合 ======
    setPinDirection(INPUT);
    if (millis() - inputTime > PLAYER_WAIT_TIME) { DoLoseProcess(); return; }

    if (!btnDwn) {
      expRd = sequence[inputCount];  // 当前期望按键
      // 检测错误按键
      for (int i=0; i

辅助函数

  • setPinDirection(dir):批量设置 4 通道 INPUT/OUTPUT
  • writeAllPins(val):全灯同步亮/灭
  • flash(freq):全灯闪烁 (系统回合慢闪/判负快闪)
  • playSequence():遍历 sequence[0..curLen-1] 依次点亮对应 LED 500ms/间隔 250ms
  • beep(freq):蜂鸣器短鸣
  • Reset():重置所有变量 + 慢闪 5 次
  • DoLoseProcess():快闪 → 延时 → 回放序列 → 延时 → Reset()

扩展玩法

1. 调整难度

修改 #define PLAYER_WAIT_TIME 2000 为 1000 (更难) 或 3000 (更易)。

2. 增加第 5/6 个通道

  1. 硬件:复制一套「按键+LED+330Ω+10kΩ」接到空闲引脚 (避开 D0/D1 串口)
  2. 代码修改:
    byte noPins = 5;
    byte pins[] = {2, 13, 10, 8, 6};  // 新增 D6
    

3. 添加 LCD 显示分数/关卡

接 I2C LCD1602,在 DoLoseProcess() 显示 curLen - 1 作为最终分数。

4. 便携化制作

  • PCB 设计:将面包板电路做成定制板,集成电池座、电源开关
  • 外壳:3D 打印手持盒,预留按键帽、LED 透光柱
  • 电源:1 节 18650 + TP4056 充电 + 5V 升压

常见问题

现象 原因 解决
某 LED 不亮 / 按键无响应 杜邦线接触不良 / 引脚定义错 / LED 极性反 用万用表测通断;对调同色 LED 排查;核对 pins[] 数组
上电即死循环/无法上传新代码 无 delay(3000) 导致 setup 立即跑逻辑占用串口 保留 setup() 首行 delay(3000);紧急时按住 Reset 再插 USB 上传空草图
蜂鸣器无声/太吵 无源蜂鸣器需 PWM 驱动 / 无限流电阻 确认 analogWrite(soundPin, 2) (占空比极低);串联 100Ω 降音量
随机序列不随机 randomSeed() 熵源固定 用 analogRead(A0) 悬空引脚噪声作种子

完整代码 (可直接复制上传)


#define PLAYER_WAIT_TIME 2000
byte sequence[100];
byte curLen = 0;
byte inputCount = 0;
byte lastInput = 0;
byte expRd = 0;
bool btnDwn = false;
bool wait = false;
bool resetFlag = false;
byte soundPin = 5;
byte noPins = 4;
byte pins[] = {2, 13, 10, 8};
long inputTime = 0;

void setup() {
  delay(3000);
  Serial.begin(9600);
  Reset();
}

void setPinDirection(byte dir) {
  for (byte i = 0; i < noPins; i++) pinMode(pins[i], dir);
}

void writeAllPins(byte val) {
  for (byte i = 0; i < noPins; i++) digitalWrite(pins[i], val);
}

void beep(byte freq) {
  analogWrite(soundPin, 2); delay(freq);
  analogWrite(soundPin, 0); delay(freq);
}

void flash(short freq) {
  setPinDirection(OUTPUT);
  for (int i = 0; i < 5; i++) {
    writeAllPins(HIGH); beep(50); delay(freq);
    writeAllPins(LOW); delay(freq);
  }
}

void Reset() {
  flash(500);
  curLen = 0; inputCount = 0; lastInput = 0; expRd = 0;
  btnDwn = false; wait = false; resetFlag = false;
}

void Lose() { flash(50); }

void playSequence() {
  for (int i = 0; i < curLen; i++) {
    digitalWrite(sequence[i], HIGH); delay(500);
    digitalWrite(sequence[i], LOW); delay(250);
  }
}

void DoLoseProcess() {
  Lose(); delay(1000);
  playSequence(); delay(1000);
  Reset();
}

void loop() {
  if (!wait) {
    setPinDirection(OUTPUT);
    randomSeed(analogRead(A0));
    sequence[curLen] = pins[random(0, noPins)];
    curLen++;
    playSequence();
    beep(50);
    wait = true;
    inputTime = millis();
  } else {
    setPinDirection(INPUT);
    if (millis() - inputTime > PLAYER_WAIT_TIME) { DoLoseProcess(); return; }

    if (!btnDwn) {
      expRd = sequence[inputCount];
      for (int i = 0; i < noPins; i++) {
        if (pins[i] == expRd) continue;
        if (digitalRead(pins[i]) == HIGH) {
          lastInput = pins[i];
          resetFlag = true; btnDwn = true;
        }
      }
    }

    if (digitalRead(expRd) == HIGH && !btnDwn) {
      inputTime = millis();
      inputCount++;
      btnDwn = true;
    } else {
      if (btnDwn && digitalRead(lastInput) == LOW) {
        btnDwn = false;
        delay(20);
        if (resetFlag) DoLoseProcess();
        else if (inputCount == curLen) {
          wait = false; inputCount = 0; delay(1500);
        }
      }
    }
  }
}

原理图下载

simonsays.fzz (Fritzing 格式,可导出 PCB/面包板视图)

这是一个经典的 Arduino 入门进阶项目,涵盖了状态机、随机数、非阻塞定时、引脚复用、去抖动等核心编程技巧。做成便携版送给孩子或朋友,是极佳的电子 DIY 礼物。更高级的乐高迷你版可参考文末 Instructables 链接。

制造工艺

  1. 用 Arduino 打造绚丽显示器 Ambilight 系统
  2. Arduino Nano 与 MPU-6050 构建实时陀螺仪游戏
  3. 互动陀螺仪 LED 显示:NeoPixel Ring + Arduino Pro Mini
  4. 用 Arduino UNO 和 OLED 显示屏制作经典 Pong 游戏:分步教程
  5. DIY Arduino USB 游戏手柄 — 自制高性能游戏手柄
  6. Arduino 触控打砖块:在 2.4 英寸 TFT LCD 上重现经典街机
  7. Pixie:基于 Arduino Pro Mini 的 NeoPixel 智能腕表 - 极简 DIY LED 时钟
  8. Pixel Chaser:Arduino Nano 单键 NeoPixel 追逐小游戏
  9. Arduino 自动化 Chrome 恐龙游戏 - LDR 光敏电阻 + Python 实现全自动跳跃
  10. 便携式远程监控摄像头机器人系统
  11. 智能手语手套:柔性传感器 + 加速度计 + 蓝牙将手势转文字/语音
  12. Arduino 合成乐音:从零实现 88 键钢琴全音域