산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

브레드보드에서 PCB로: 사이먼 세이즈 게임 만들기 – 1부

부품 및 소모품

부품수량비고
아두이노 UNO1
납땜리스 브레드보드 풀사이즈1
LED (범용)4녹색, 빨강, 노랑, 파랑
SparkFun 푸시버튼 스위치 12mm4LED 색상과 매칭
부저1
점퍼 와이어12
저항 10kΩ4버튼 풀업용 (내부 풀업 사용 시 선택사항)
저항 330Ω4LED 전류 제한용
USB-A to B 케이블1

앱 및 온라인 서비스

프로젝트 소개

소개

모두 아시는 고전 '사이먼 세이즈' 게임입니다. 불이 켜지는 순서를 보고 해당 버튼을 눌러 따라하는 게임이죠. 해크스터 라이브에서 '업버터(Upverter)'라는 PCB 설계 툴을 시연했는데, 이 프로젝트는 PCB로 전환하기에 재미있고 간단한 예제입니다. 아래는 하드웨어와 코드를 포함한 기본 게임 제작 과정입니다.

이 프로젝트 시리즈는 총 3부로 구성됩니다.

이 시리즈에서 배울 것

소프트웨어

아두이노 IDE가 없다면 여기에서 OS에 맞는 최신 버전을 다운로드하세요.

하드웨어 설정

스파크펀의 인벤터 키트 예제를 참고해 약간 수정했습니다. 아래 프리칭 다이어그램을 확인하세요.

브레드보드에서 PCB로: 사이먼 세이즈 게임 만들기 – 1부
브레드보드에서 PCB로: 사이먼 세이즈 게임 만들기 – 1부

코드

이 게임의 재미는 다양한 변형이 가능하다는 점입니다. 위에서 언급했듯 스파크펀 예제를 하드웨어 기초로 삼고 코드는 직접 작성했습니다. 직접 코딩이 부담스럽다면 아래 제 코드를 쓰거나, 스파크펀 예제 코드를 약간 수정해 쓰거나, 하드웨어 설정과 호환되는 다른 사이먼 세이즈 코드를 찾아보셔도 됩니다.

코드에 상세 주석과 디버깅용 시리얼 프린트를 넣어 게임 실행 중 시리얼 모니터에서 상황을 확인할 수 있습니다. 아래 영상에서 실제 작동 모습을 확인하세요!

사이먼 세이즈 게임 영상

참고: 영상에서는 연속 5회 성공 시 승리하도록 설정했습니다. 난이도 조절을 위해 이 숫자를 변경할 수 있지만, 영상 길이를 위해 5로 설정했습니다.

이제 브레드보드를 PCB로 전환할 준비가 됐습니다! 브레드보드에서 PCB로 2부 - 업버터로 PCB 설계하기에서 방법을 배워보세요.

코드

사이먼 세이즈 아두이노 코드 (Arduino)
int ledArray[] = {12, 9, 5, 2};   // ledArray[0]=녹색, [1]=빨강, [2]=노랑, [3]=파랑
int buttonArray[] = {13, 10, 6, 3}; // buttonArray[0]=녹색, [1]=빨강, [2]=노랑, [3]=파랑
int pinCount = 4;
int buzzer = 8;
int ledState = 0;
int gameState = 0;
#define NUMBERTOWIN 5 // 승리 조건: 연속 성공 횟수 (변경 가능)
int gameValues[NUMBERTOWIN];
int roundNum = 0;
unsigned long previousMillis = 0;
unsigned long interval1 = 500;

void setLed(int ledNum);
void displayClue(int roundNum);
boolean waitForInput(int buttonNum);

void setup() {
  Serial.begin(9600);
  Serial.println("setup");
  for (int Pin = 0; Pin < pinCount; Pin++) {
    pinMode(ledArray[Pin], OUTPUT);
  }
  for (int Pin = 0; Pin < pinCount; Pin++) {
    pinMode(buttonArray[Pin], INPUT_PULLUP); // 내부 풀업 사용 (코드 작성 후 10k 외부 저항 추가함, 코드 수정 불필요)
  }
  randomSeed(analogRead(0)); // 아날로그 노이즈로 랜덤 시드 생성
}

void loop() {
  if (gameState == 0) {
    int button0 = digitalRead(buttonArray[0]);
    int button1 = digitalRead(buttonArray[1]);
    int button2 = digitalRead(buttonArray[2]);
    int button3 = digitalRead(buttonArray[3]);
    // 버튼 미눌림 시(풀업이므로 모두 HIGH) 프리게임 모드
    if (button0 && button1 && button2 && button3) {
      pre_game();
    } else { // 버튼 눌림 시 게임 시작
      Serial.println("button Pressed");
      setLed(-1); // 모든 LED 끄기
      roundNum = 0;
      delay(1000);
      gameState = 1;
    }
  }
  if (gameState == 1) gamePlay();
  if (gameState == 2) { // 승리
    delay(500);
    winning_sound();
    winDisplay(); winDisplay(); winDisplay();
    loseDisplay();
    Serial.println("winDisplay");
    delay(1000);
    gameState = 0;
  }
  if (gameState == 3) { // 패배
    delay(500);
    losing_sound();
    loseDisplay(); loseDisplay(); loseDisplay();
    Serial.println("loseDisplay");
    delay(1000);
    gameState = 0;
  }
}

void pre_game() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval1) {
    if (ledState == 0) { Serial.println("pre green"); setLed(0); ledState = 1; }
    else if (ledState == 1) { Serial.println("pre red"); setLed(1); ledState = 2; }
    else if (ledState == 2) { Serial.println("pre yellow"); setLed(2); ledState = 3; }
    else if (ledState == 3) { Serial.println("pre blue"); setLed(3); ledState = 0; }
    previousMillis = currentMillis;
  }
}

void gamePlay() {
  Serial.println("gamePlay");
  for (int i = 0; i < NUMBERTOWIN; i++) {
    gameValues[i] = floor(random(0, 4));
    Serial.println(gameValues[i], DEC);
  }
  Serial.print("Starting Round "); Serial.println(roundNum, DEC);
  for (int r = 0; r < NUMBERTOWIN; r++) {
    displayClue(roundNum);
    for (int i = 0; i <= roundNum; i++) {
      Serial.print("Waiting for input "); Serial.print(i+1, DEC);
      Serial.print(" of "); Serial.print(roundNum+1, DEC); Serial.println("");
      if (waitForInput(gameValues[i])) {
        if (i == roundNum) {
          Serial.println("Correct");
          if (roundNum == NUMBERTOWIN - 1) {
            Serial.println("You Win!");
            gameState = 2;
            return;
          } else {
            Serial.println("Continue");
          }
        }
      } else {
        Serial.println("You Lose!");
        gameState = 3;
        return;
      }
    }
    roundNum++;
    delay(1000);
  }
}

void setLed(int ledNum) {
  if (ledNum < 0) {
    for (int i = 0; i < pinCount; i++) digitalWrite(ledArray[i], LOW);
  } else {
    for (int i = 0; i < pinCount; i++) {
      digitalWrite(ledArray[i], (i == ledNum) ? HIGH : LOW);
    }
  }
}

void displayClue(int roundNum) {
  setLed(-1);
  for (int i = 0; i <= roundNum; i++) {
    setLed(gameValues[i]);
    delay(750);
    setLed(-1);
    delay(250);
  }
}

boolean waitForInput(int buttonNum) {
  while (true) {
    int button0 = digitalRead(buttonArray[0]);
    int button1 = digitalRead(buttonArray[1]);
    int button2 = digitalRead(buttonArray[2]);
    int button3 = digitalRead(buttonArray[3]);
    if (!button0 || !button1 || !button2 || !button3) { // 버튼 눌림 감지 (풀업이므로 LOW)
      delay(250); // 디바운싱
      if (buttonNum == 0) { digitalWrite(ledArray[0], HIGH); delay(250); digitalWrite(ledArray[0], LOW); }
      else if (buttonNum == 1) { digitalWrite(ledArray[1], HIGH); delay(250); digitalWrite(ledArray[1], LOW); }
      else if (buttonNum == 2) { digitalWrite(ledArray[2], HIGH); delay(250); digitalWrite(ledArray[2], LOW); }
      else if (buttonNum == 3) { digitalWrite(ledArray[3], HIGH); delay(250); digitalWrite(ledArray[3], LOW); }
      if (buttonNum == 0 && button0 == 0) { Serial.println("0 Pressed"); return true; }
      else if (buttonNum == 1 && button1 == 0) { Serial.println("1 Pressed"); return true; }
      else if (buttonNum == 2 && button2 == 0) { Serial.println("2 Pressed"); return true; }
      else if (buttonNum == 3 && button3 == 0) { Serial.println("3 Pressed"); return true; }
      else { return false; }
    }
  }
}

void winDisplay() {
  digitalWrite(ledArray[0], HIGH); delay(75); digitalWrite(ledArray[0], LOW); delay(75);
  digitalWrite(ledArray[1], HIGH); delay(75); digitalWrite(ledArray[1], LOW); delay(75);
  digitalWrite(ledArray[2], HIGH); delay(75); digitalWrite(ledArray[2], LOW); delay(75);
  digitalWrite(ledArray[3], HIGH); delay(75); digitalWrite(ledArray[3], LOW); delay(75);
  digitalWrite(ledArray[2], HIGH); delay(75); digitalWrite(ledArray[2], LOW); delay(75);
  digitalWrite(ledArray[1], HIGH); delay(75); digitalWrite(ledArray[1], LOW); delay(75);
  digitalWrite(ledArray[0], HIGH); delay(75); digitalWrite(ledArray[0], LOW); delay(75);
}

void winning_sound() {
  Serial.println("buzzer1");
  tone(buzzer, 294, 250); delay(200);
  tone(buzzer, 294, 250); delay(200);
  tone(buzzer, 294, 250); delay(200);
  tone(buzzer, 392, 500); delay(500);
  Serial.println("second 392");
  tone(buzzer, 392, 250); delay(200);
  tone(buzzer, 440, 250); delay(200);
  tone(buzzer, 392, 250); delay(200);
  tone(buzzer, 440, 250); delay(200);
  tone(buzzer, 494, 500);
}

void loseDisplay() {
  digitalWrite(ledArray[0], HIGH); digitalWrite(ledArray[1], HIGH);
  digitalWrite(ledArray[2], HIGH); digitalWrite(ledArray[3], HIGH);
  delay(200);
  digitalWrite(ledArray[0], LOW); digitalWrite(ledArray[1], LOW);
  digitalWrite(ledArray[2], LOW); digitalWrite(ledArray[3], LOW);
  delay(200);
}

void losing_sound() {
  Serial.println("losing_sound");
  tone(buzzer, 98, 250); delay(250);
  tone(buzzer, 93, 250); delay(250);
  tone(buzzer, 87, 250); delay(250);
}

회로도

simon_says_fritzing_Yb8EdKPqD4.fzz

제조공정

  1. 아두이노 나노와 MPU-6050으로 실시간 자이로스코프 게임 만들기
  2. 아두이노 디지털 주사위: LCD 기반 랜덤 넘버 제너레이터 만들기
  3. 아두이노 나노로 37개 LED 룰렛 게임 만들기
  4. DIY 아두이노 USB 게임 컨트롤러 - 나만의 고성능 게임패드 만들기
  5. 아두이노 조이스틱 인터랙티브 게임 - LED 피드백으로 방향 감지
  6. 휴대용 거리 감지기: HC-SR04, 18650 배터리, 3D 프린트 케이스의 아두이노 나노 DIY 키트
  7. 픽셀 체이서: 아두이노 나노로 만든 인터랙티브 원탭 LED 게임
  8. 구리 도금 프로젝트: 아두이노 우노로 만드는 스마트 전기분해 시스템
  9. 소규모 작업장을 위한 항공우주 제조 실무 가이드
  10. 4층 PCB 제조 완전 가이드: 단계별 공정 상세 설명