아두이노 우노 R4 LED 매트릭스

이 튜토리얼은 외부 LED 매트릭스 디스플레이 모듈과 함께 Arduno UNO R4를 사용하는 방법을 안내합니다. 자세히 살펴보면, 우리는 배울 것입니다:

그러면 16x8 또는 64x8 LED 매트릭스와 같은 다른 LED 매트릭스를 위해 코드를 간단히 수정할 수 있습니다.

아두이노 우노 R4 LED 매트릭스

Arduino R4의 온보드 LED 매트릭스 사용 방법을 배우고 싶다면, 아두이노 우노 R4 - 내장 LED 매트릭스를 참조하세요.

준비물

1×Arduino UNO R4 WiFi or Arduino UNO R4 Minima
1×(또는) DIYables STEM V4 IoT, Compatible with Arduino Uno R4 WiFi 쿠팡 | 아마존
1×USB 케이블 타입-A to 타입-C (USB-A PC용) 쿠팡 | 아마존
1×USB 케이블 타입-C to 타입-C (USB-C PC용) 아마존
1×FC-16 LED Matrix 32x8 쿠팡 | 아마존
1×FC-16 LED Matrix 8x8 쿠팡 | 아마존
1×점퍼케이블 쿠팡 | 아마존
1×DC 커넥터 전원 연결 잭 플러그 소켓 쿠팡 | 아마존
1×5V Power Adapter for Arduino UNO R4 아마존
1×(추천) 아두이노 우노 R4용 스크루 터미널 블록 쉴드 쿠팡 | 아마존
1×(추천) Sensors/Servo Expansion Shield for Arduino UNO R4 쿠팡 | 아마존
1×(추천) 아두이노 우노 R4용 브레드보드 쉴드 쿠팡 | 아마존
1×(추천) 아두이노 우노 R4용 케이스 쿠팡 | 아마존
1×(추천) 아두이노 우노 R4용 전원 분배기 쿠팡 | 아마존
1×(추천) 아두이노 우노용 프로토타이핑 베이스 플레이트 & 브레드보드 키트 아마존
공개: 이 포스팅 에 제공된 일부 링크는 아마존 제휴 링크입니다. 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
Arduino Uno R4 WiFi Compatible Boards

LED 매트릭스에 관하여

LED 매트릭스 디스플레이

다양한 종류의 LED 매트릭스가 존재합니다. MAX7219 기반 LED 매트릭스는 Arduino UNO R4와 함께 일반적으로 사용됩니다. 이 LED 매트릭스는 여러 가지 기능을 포함합니다:

  • LED 매트릭스의 기본 구성 요소는 블록이라고 합니다.
  • 각 블록은 8x8의 LED 격자를 포함하며, 총 64개의 LED로 구성되고 MAX7219 칩에 의해 제어됩니다.
  • 블록에는 일반 모듈과 FC-16 모듈 두 가지 주요 유형이 있습니다.
  • LED 매트릭스는 하나의 블록만 가질 수도 있고, 여러 블록을 체인처럼 연결하여 확장할 수도 있습니다.
  • 이미 여러 블록이 연결된 LED 매트릭스를 구매할 수 있으며, 예로 4블록 또는 8블록 구성이 있습니다.
  • 또는 개별 블록을 구매하여 필요한 크기의 LED 매트릭스를 직접 만들 수도 있습니다.
  • Arduino UNO R4 프로그램에서는 사용 중인 LED 매트릭스의 크기를 지정해야 합니다.

핀아웃

LED 매트릭스 핀아웃

LED 매트릭스는 하나 이상의 블록으로 구성됩니다. 각 블록에는 두 개의 핀 세트가 있습니다.

  • 입력 핀 그룹:
    • VCC: 이것을 5V에 연결합니다.
    • GND: 이것을 GND에 연결합니다.
    • DIN: 이것은 데이터 핀입니다. 아두이노 UNO R4의 SPI MOSI 핀에 연결합니다.
    • CS: 칩 셀렉트. 아두이노 UNO R4의 디지털 핀 중 하나에 연결합니다.
    • CLK: 클럭 핀. 아두이노 UNO R4의 SPI CLK 핀에 연결합니다.
  • 출력 핀 그룹:
    • VCC: 이것을 다음 모듈의 VCC에 연결합니다.
    • GND: 이것을 다음 모듈의 GND에 연결합니다.
    • DOUT: 데이터 출력. 다음 모듈의 DIN 핀에 연결합니다.
    • CS: 이것을 다음 모듈의 CS에 연결합니다.
    • CLK: 이것을 다음 모듈의 CLK에 연결합니다.

선연결

LED 매트릭스가 하나의 블록으로만 구성된 경우:

  • 입력 핀 그룹을 Arduino UNO R4에 연결하세요.
  • 출력 핀 그룹은 연결하지 마세요.
아두이노 우노 R4 8x8 LED 매트릭스 fc-16 연결도

이 이미지는 Fritzing을 사용하여 만들어졌습니다. 이미지를 확대하려면 클릭하세요.

아두이노 우노 R4 8x8 LED 행렬 일반 배선도

이 이미지는 Fritzing을 사용하여 만들어졌습니다. 이미지를 확대하려면 클릭하세요.

LED 매트릭스가 이미 여러 블록으로 조립된 상태로 제공되는 경우:

  • 입력 핀 그룹을 Arduino UNO R4에 연결하십시오.
  • 출력 핀 그룹은 연결하지 않은 상태로 두십시오.
아두이노 우노 R4 LED 매트릭스 디스플레이 배선도

이 이미지는 Fritzing을 사용하여 만들어졌습니다. 이미지를 확대하려면 클릭하세요.

LED 매트릭스를 여러 부품으로 조립하는 경우:

  • 첫 번째 블록의 입력 핀 그룹을 Arduino UNO R4에 연결합니다.
  • 각 블록의 출력 핀 그룹을 다음 블록의 입력 핀 그룹에 연결합니다.
  • 마지막 블록의 출력 핀 그룹은 연결하지 않은 상태로 둡니다.
아두이노 우노 R4 32x8 LED 매트릭스 배선 fc-16 도표

이 이미지는 Fritzing을 사용하여 만들어졌습니다. 이미지를 확대하려면 클릭하세요.

아르두이노 uno r4 32x8 LED 매트릭스 배선 일반 다이어그램

이 이미지는 Fritzing을 사용하여 만들어졌습니다. 이미지를 확대하려면 클릭하세요.

Arduino Uno R4와 기타 부품에 전원을 공급하는 가장 효과적인 방법을 확인하시려면, 아래 링크를 참조하세요: 아두이노 우노 R4 전원 공급 방법.

디스플레이는 최대 밝기에서 최대 1암페어의 많은 전력을 사용합니다.

  • Arduino UNO R4의 5V 핀을 전원 공급용으로 사용하지 마세요.
  • 대신 외부 5V 전원 공급 장치를 연결하세요. Arduino UNO R4와 LED 매트릭스는 동일한 5V 어댑터로 전원을 공급받을 수 있습니다.

Arduino UNO R4는 SPI 핀을 사용하여 LED 매트릭스에 연결됩니다.

  • 아두이노 UNO R4에서 핀 13(SCK)과 11(MOSI)을 사용하세요. 다른 아두이노 UNO R4 보드를 사용하는 경우, 동일한 SPI 핀에 대한 공식 가이드를 참조하세요.
  • 핀 3(CS)에는 다른 핀을 사용할 수 있습니다.

LED 매트릭스 프로그래밍 방법

LED 매트릭스를 제어하는 것은 어려울 수 있습니다. 다행히도, 이 작업을 간단하게 만들어주는 라이브러리들이 있습니다. 다음은 Arduino UNO R4를 프로그래밍하여 LED 매트릭스를 제어하는 단계입니다.

  • 라이브러리 포함:
#include <MD_Parola.h> #include <MD_MAX72xx.h>
  • 사용 중인 하드웨어 유형을 선택하세요: GENERIC_HW 또는 FC16_HW.
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
  • LED 블록이 얼마나 사용되는지 확인하십시오. 예를 들어, 4-in-1 LED 매트릭스에는 4개의 블록이 포함되어 있습니다.
#define MAX_DEVICES 4
  • LED 매트릭스의 CS 핀에 연결된 핀을 설정합니다. 예를 들어, D9 핀을 사용하세요.
#define CS_PIN 9
  • LED 매트릭스 디스플레이용 MD_Parola 클래스의 새 버전을 만드세요.
MD_Parola ledMatrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
  • Setup() 함수에서 코드를 설정하세요.
void setup() { ledMatrix.begin(); // LED 매트릭스 초기화 ledMatrix.setIntensity(0); // 디스플레이 밝기 설정 (범위 0-15) ledMatrix.displayClear(); // 디스플레이 화면 지우기 }
  • 텍스트, 숫자 및 애니메이션 효과 표시: 다음 부분을 참조하십시오.

Arduino UNO R4 - LED 매트릭스 코드

제공된 코드는 네 개의 블록을 가진 32x8 FC-16 LED 매트릭스 디스플레이용입니다. 그러나 8x8, 16x8, 64x8 등 다른 크기로 수정할 수 있습니다.

/* * 이 아두이노 우노 R4 코드는 newbiely.kr 에서 개발되었습니다 * 이 아두이노 우노 R4 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-uno-r4/arduino-uno-r4-led-matrix */ #include <MD_Parola.h> #include <MD_MAX72xx.h> #define HARDWARE_TYPE MD_MAX72XX::FC16_HW #define MAX_DEVICES 4 // 4 blocks #define CS_PIN 9 // The Arduino UNO R4 pin connected to the CS pin of LED matrix // create an instance of the MD_Parola class MD_Parola ledMatrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); void setup() { ledMatrix.begin(); // initialize the object ledMatrix.setIntensity(15); // set the brightness of the LED matrix display (from 0 to 15) ledMatrix.displayClear(); // clear LED matrix display } void loop() { ledMatrix.setTextAlignment(PA_LEFT); ledMatrix.print("Left"); // display text delay(2000); ledMatrix.setTextAlignment(PA_CENTER); ledMatrix.print("Center"); // display text delay(2000); ledMatrix.setTextAlignment(PA_RIGHT); ledMatrix.print("Right"); // display text delay(2000); ledMatrix.setTextAlignment(PA_CENTER); ledMatrix.setInvert(true); ledMatrix.print("Invert"); // display text inverted delay(2000); ledMatrix.setInvert(false); ledMatrix.print(1234); // display number delay(2000); }

자세한 사용 방법

다음 지침을 단계별로 따르십시오:

  • Arduino Uno R4 WiFi/Minima를 처음 사용하는 경우, Arduino IDE에서 아두이노 우노 R4 - 소프트웨어 설치에 대한 튜토리얼을 참조하세요.
  • 제공된 다이어그램에 따라 Arduino Uno R4 보드를 LED 매트릭스에 연결합니다.
  • USB 케이블을 사용하여 Arduino Uno R4 보드를 컴퓨터에 연결합니다.
  • 컴퓨터에서 Arduino IDE를 실행합니다.
  • 적절한 Arduino Uno R4 보드 (예: Arduino Uno R4 WiFi)와 COM 포트를 선택합니다.
  • Arduino IDE에서 왼쪽 사이드바에 있는 Libraries 아이콘을 클릭합니다.
  • "MD_Parola"를 검색하여 MD_Parola 라이브러리를 찾습니다.
  • Install 버튼을 클릭합니다.
아두이노 우노 R4 md_parola 라이브러리
  • MD_MAX72XX 라이브러리를 설치해야 합니다. Install All 버튼을 클릭하세요.
아두이노 우노 R4 md_max72xx 라이브러리
  • 위의 코드를 복사하여 Arduino IDE로 엽니다.
  • Arduino IDE에서 Upload 버튼을 클릭하여 코드를 Arduino UNO R4에 업로드합니다.
  • LED 매트릭스의 디스플레이를 확인합니다.

Arduino UNO R4 LED 매트릭스 코드 – 스크롤링 텍스트

LED 매트릭스 디스플레이에 긴 메시지를 보여줘야 하는데 화면에 맞지 않을 경우, 스크롤링 텍스트 효과를 사용할 수 있습니다.

이 Arduino UNO R4 코드는 LED 매트릭스 디스플레이에 메시지를 스크롤하는 방법을 보여줍니다.

/* * 이 아두이노 우노 R4 코드는 newbiely.kr 에서 개발되었습니다 * 이 아두이노 우노 R4 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-uno-r4/arduino-uno-r4-led-matrix */ #include <MD_Parola.h> #include <MD_MAX72xx.h> #define HARDWARE_TYPE MD_MAX72XX::FC16_HW #define MAX_DEVICES 4 // 4 blocks #define CS_PIN 9 // The Arduino UNO R4 pin connected to the CS pin of LED matrix // create an instance of the MD_Parola class MD_Parola ledMatrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); void setup() { ledMatrix.begin(); // initialize the object ledMatrix.setIntensity(15); // set the brightness of the LED matrix display (from 0 to 15) ledMatrix.displayClear(); // clear led matrix display ledMatrix.displayScroll("Hello, DIYables", PA_CENTER, PA_SCROLL_LEFT, 100); } void loop() { if (ledMatrix.displayAnimate()) { ledMatrix.displayReset(); } }

더 많은 텍스트 효과를 보려면 MD_Parola 라이브러리 참조를 방문하세요.

동영상

비디오 제작은 시간이 많이 걸리는 작업입니다. 비디오 튜토리얼이 학습에 도움이 되었다면, YouTube 채널 을 구독하여 알려 주시기 바랍니다. 비디오에 대한 높은 수요가 있다면, 비디오를 만들기 위해 노력하겠습니다.

아래 동영상 데모는 아래 코드를 사용합니다:

/* * 이 아두이노 우노 R4 코드는 newbiely.kr 에서 개발되었습니다 * 이 아두이노 우노 R4 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-uno-r4/arduino-uno-r4-led-matrix */ #include <MD_MAX72xx.h> #include <SPI.h> // ============================================================ // MAX7219 // ============================================================ #define HARDWARE_TYPE MD_MAX72XX::FC16_HW #define MAX_DEVICES 4 #define CS_PIN 9 MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); // ============================================================ // BUTTONS // ============================================================ #define BTN_LEFT 2 #define BTN_RIGHT 3 #define BTN_ROTATE 4 #define BUZZER_PIN 6 // ============================================================ // GAME BOARD // ============================================================ #define BOARD_W 8 #define BOARD_H 32 bool board[BOARD_H][BOARD_W]; // ============================================================ // TIMING // ============================================================ unsigned long lastFallTime = 0; const unsigned long NORMAL_FALL = 700; const unsigned long SOFT_DROP_FALL = 80; #define LONG_PRESS_TIME 400 // ============================================================ // SCORE // ============================================================ unsigned long score = 0; unsigned int lines = 0; unsigned int level = 1; unsigned long highScore = 0; // ============================================================ // GAME STATE // ============================================================ bool gameOver = false; bool gameStarted = false; // ============================================================ // TETROMINO DEFINITIONS // ============================================================ struct Point { int x; int y; }; struct Tetromino { Point block[4]; uint8_t color; }; Tetromino pieces[7] = { // I { {{0,0}, {1,0}, {2,0}, {3,0}}, 0 }, // O { {{0,0}, {1,0}, {0,1}, {1,1}}, 1 }, // T { {{1,0}, {0,1}, {1,1}, {2,1}}, 2 }, // L { {{0,0}, {0,1}, {0,2}, {1,2}}, 3 }, // J { {{1,0}, {1,1}, {1,2}, {0,2}}, 4 }, // S { {{1,0}, {2,0}, {0,1}, {1,1}}, 5 }, // Z { {{0,0}, {1,0}, {1,1}, {2,1}}, 6 } }; // ============================================================ // CURRENT PIECE // ============================================================ int currentPiece; int currentX; int currentY; int rotationState = 0; // ============================================================ // BUTTON STATE // ============================================================ bool lastLeftState = HIGH; bool lastRightState = HIGH; bool lastRotateState = HIGH; unsigned long rotatePressTime = 0; bool softDrop = false; bool rotateHandled = false; // ============================================================ // DISPLAY COORDINATE MAPPING // ============================================================ void setPixel(int x, int y, bool state) { if (x < 0 || x >= BOARD_W || y < 0 || y >= BOARD_H) { return; } // Reverse vertical direction int physicalColumn = (BOARD_H - 1) - y; int physicalRow = x; mx.setPoint( physicalRow, physicalColumn, state ); } // ============================================================ // CLEAR DISPLAY // ============================================================ void clearDisplay() { mx.clear(); } // ============================================================ // DRAW BOARD // ============================================================ void drawBoard() { clearDisplay(); // Draw fixed blocks for (int y = 0; y < BOARD_H; y++) { for (int x = 0; x < BOARD_W; x++) { if (board[y][x]) { setPixel( x, y, true ); } } } // Draw falling piece drawCurrentPiece(); } // ============================================================ // GET ROTATED BLOCK POSITION // ============================================================ Point getRotatedPoint( Point p, int rotation ) { Point r; switch (rotation % 4) { case 0: r.x = p.x; r.y = p.y; break; case 1: r.x = -p.y; r.y = p.x; break; case 2: r.x = -p.x; r.y = -p.y; break; case 3: r.x = p.y; r.y = -p.x; break; } return r; } // ============================================================ // CHECK COLLISION // ============================================================ bool checkCollision( int pieceX, int pieceY, int rotation ) { for (int i = 0; i < 4; i++) { Point p = getRotatedPoint( pieces[currentPiece].block[i], rotation ); int x = pieceX + p.x; int y = pieceY + p.y; // Left / Right wall if (x < 0 || x >= BOARD_W) { return true; } // Bottom if (y >= BOARD_H) { return true; } // Existing block if (y >= 0 && board[y][x]) { return true; } } return false; } // ============================================================ // DRAW CURRENT PIECE // ============================================================ void drawCurrentPiece() { for (int i = 0; i < 4; i++) { Point p = getRotatedPoint( pieces[currentPiece].block[i], rotationState ); int x = currentX + p.x; int y = currentY + p.y; if (x >= 0 && x < BOARD_W && y >= 0 && y < BOARD_H) { setPixel( x, y, true ); } } } // ============================================================ // RANDOM PIECE // ============================================================ void spawnPiece() { currentPiece = random(0, 7); rotationState = 0; currentX = 3; currentY = 0; // I piece if (currentPiece == 0) { currentX = 2; } // Game over if piece cannot spawn if (checkCollision( currentX, currentY, rotationState)) { gameOver = true; if (score > highScore) { highScore = score; } soundGameOver(); } } // ============================================================ // LOCK PIECE // ============================================================ void lockPiece() { for (int i = 0; i < 4; i++) { Point p = getRotatedPoint( pieces[currentPiece].block[i], rotationState ); int x = currentX + p.x; int y = currentY + p.y; if (x >= 0 && x < BOARD_W && y >= 0 && y < BOARD_H) { board[y][x] = true; } } soundLock(); // Check completed lines clearLines(); // New piece spawnPiece(); lastFallTime = millis(); } // ============================================================ // CLEAR LINES // ============================================================ void clearLines() { int cleared = 0; for (int y = BOARD_H - 1; y >= 0; y--) { bool full = true; for (int x = 0; x < BOARD_W; x++) { if (!board[y][x]) { full = false; break; } } if (full) { cleared++; // Move rows down for (int yy = y; yy > 0; yy--) { for (int x = 0; x < BOARD_W; x++) { board[yy][x] = board[yy - 1][x]; } } // Clear top row for (int x = 0; x < BOARD_W; x++) { board[0][x] = false; } // Check same row again y++; } } // Scoring if (cleared > 0) { lines += cleared; switch (cleared) { case 1: score += 100 * level; break; case 2: score += 300 * level; break; case 3: score += 500 * level; break; case 4: score += 800 * level; break; } // Increase level every 10 lines level = (lines / 10) + 1; soundLineClear(cleared); } } // ============================================================ // MOVE LEFT // ============================================================ void moveLeft() { if (gameOver) { return; } if (!checkCollision( currentX - 1, currentY, rotationState)) { currentX--; drawBoard(); soundLeft(); } } // ============================================================ // MOVE RIGHT // ============================================================ void moveRight() { if (gameOver) { return; } if (!checkCollision( currentX + 1, currentY, rotationState)) { currentX++; drawBoard(); soundRight(); } } // ============================================================ // ROTATE // ============================================================ void rotatePiece() { if (gameOver) { return; } int newRotation = (rotationState + 1) % 4; // Normal rotation if (!checkCollision( currentX, currentY, newRotation)) { rotationState = newRotation; drawBoard(); return; } // Wall kick LEFT if (!checkCollision( currentX - 1, currentY, newRotation)) { currentX--; rotationState = newRotation; drawBoard(); return; } // Wall kick RIGHT if (!checkCollision( currentX + 1, currentY, newRotation)) { currentX++; rotationState = newRotation; drawBoard(); return; } } // ============================================================ // MOVE DOWN // ============================================================ bool moveDown() { if (gameOver) { return false; } if (!checkCollision( currentX, currentY + 1, rotationState)) { currentY++; return true; } // Cannot move further lockPiece(); return false; } // ============================================================ // SOFT DROP // ============================================================ void handleSoftDrop() { if (gameOver) { return; } static unsigned long lastSoftDrop = 0; if (millis() - lastSoftDrop >= SOFT_DROP_FALL) { lastSoftDrop = millis(); if (moveDown()) { score += 1; } drawBoard(); } } // ============================================================ // NORMAL FALL // ============================================================ void handleNormalFall() { if (gameOver) { return; } unsigned long fallSpeed; fallSpeed = NORMAL_FALL - ((level - 1) * 50); if (fallSpeed < 100) { fallSpeed = 100; } if (millis() - lastFallTime >= fallSpeed) { lastFallTime = millis(); moveDown(); drawBoard(); } } // ============================================================ // BUTTON HANDLING // ============================================================ void handleButtons() { bool leftState = digitalRead(BTN_LEFT); bool rightState = digitalRead(BTN_RIGHT); bool rotateState = digitalRead(BTN_ROTATE); // ========================================================== // LEFT // ========================================================== if (leftState == LOW && lastLeftState == HIGH) { moveLeft(); } // ========================================================== // RIGHT // ========================================================== if (rightState == LOW && lastRightState == HIGH) { moveRight(); } // ========================================================== // ROTATE BUTTON PRESSED // ========================================================== if (rotateState == LOW && lastRotateState == HIGH) { rotatePressTime = millis(); rotateHandled = false; } // ========================================================== // ROTATE BUTTON HELD // ========================================================== if (rotateState == LOW) { if (!rotateHandled && millis() - rotatePressTime >= LONG_PRESS_TIME) { rotateHandled = true; softDrop = true; } } // ========================================================== // ROTATE BUTTON RELEASED // ========================================================== if (rotateState == HIGH && lastRotateState == LOW) { unsigned long pressDuration = millis() - rotatePressTime; // Short press = ROTATE if (pressDuration < LONG_PRESS_TIME && !rotateHandled) { rotatePiece(); soundRotate(); } // Stop soft drop softDrop = false; } lastLeftState = leftState; lastRightState = rightState; lastRotateState = rotateState; } // ============================================================ // START MUSIC // ============================================================ // // Arcade-style startup melody. // // Không dùng tone liên tục. // Mỗi nốt kết thúc trước khi nốt tiếp theo bắt đầu. // ============================================================ void playStartMusic() { clearDisplay(); // ---------------------------------------------------------- // Intro LED sweep // ---------------------------------------------------------- for (int y = 0; y < BOARD_H; y++) { for (int x = 0; x < BOARD_W; x++) { setPixel( x, y, true ); } // Melody notes during sweep if (y == 0) { tone(BUZZER_PIN, 523, 100); } if (y == 4) { tone(BUZZER_PIN, 659, 100); } if (y == 8) { tone(BUZZER_PIN, 784, 100); } if (y == 12) { tone(BUZZER_PIN, 1047, 150); } if (y == 18) { tone(BUZZER_PIN, 784, 100); } if (y == 22) { tone(BUZZER_PIN, 1047, 100); } if (y == 26) { tone(BUZZER_PIN, 1319, 180); } delay(18); } delay(100); clearDisplay(); // ---------------------------------------------------------- // READY melody // ---------------------------------------------------------- tone(BUZZER_PIN, 784, 120); delay(150); tone(BUZZER_PIN, 988, 120); delay(150); tone(BUZZER_PIN, 1175, 120); delay(150); tone(BUZZER_PIN, 1568, 250); delay(300); clearDisplay(); noTone(BUZZER_PIN); } // ============================================================ // LEFT SOUND // ============================================================ void soundLeft() { tone( BUZZER_PIN, 650, 70 ); } // ============================================================ // RIGHT SOUND // ============================================================ void soundRight() { tone( BUZZER_PIN, 850, 70 ); } // ============================================================ // ROTATE SOUND // ============================================================ void soundLock() { tone(BUZZER_PIN, 450, 120); delay(130); tone(BUZZER_PIN, 300, 100); } // ============================================================ // ROTATE SOUND // ============================================================ void soundRotate() { tone( BUZZER_PIN, 1200, 100 ); } // ============================================================ // LINE CLEAR SOUND // ============================================================ void soundLineClear(int count) { if (count == 1) { tone( BUZZER_PIN, 1000, 120 ); delay(150); tone( BUZZER_PIN, 1400, 160 ); } else if (count == 2) { tone( BUZZER_PIN, 1000, 100 ); delay(120); tone( BUZZER_PIN, 1300, 100 ); delay(120); tone( BUZZER_PIN, 1700, 180 ); } else { tone( BUZZER_PIN, 1200, 100 ); delay(120); tone( BUZZER_PIN, 1500, 100 ); delay(120); tone( BUZZER_PIN, 1800, 100 ); delay(120); tone( BUZZER_PIN, 2200, 250 ); } } // ============================================================ // GAME OVER SOUND // ============================================================ void soundGameOver() { tone( BUZZER_PIN, 700, 180 ); delay(210); tone( BUZZER_PIN, 500, 180 ); delay(210); tone( BUZZER_PIN, 350, 220 ); delay(250); tone( BUZZER_PIN, 220, 450 ); delay(500); noTone(BUZZER_PIN); } // ============================================================ // GAME OVER ANIMATION // ============================================================ void gameOverAnimation() { for (int i = 0; i < 4; i++) { drawBoard(); delay(250); clearDisplay(); delay(250); } } // ============================================================ // RESET GAME // ============================================================ void resetGame() { for (int y = 0; y < BOARD_H; y++) { for (int x = 0; x < BOARD_W; x++) { board[y][x] = false; } } score = 0; lines = 0; level = 1; gameOver = false; spawnPiece(); lastFallTime = millis(); drawBoard(); } // ============================================================ // SETUP // ============================================================ void setup() { Serial.begin(115200); // Buttons pinMode( BTN_LEFT, INPUT_PULLUP ); pinMode( BTN_RIGHT, INPUT_PULLUP ); pinMode( BTN_ROTATE, INPUT_PULLUP ); // Buzzer pinMode( BUZZER_PIN, OUTPUT ); // MAX7219 mx.begin(); mx.control( MD_MAX72XX::INTENSITY, 5 ); mx.control( MD_MAX72XX::UPDATE, true ); mx.clear(); // Random seed randomSeed( analogRead(A0) ); // ========================================================== // START MUSIC // ========================================================== playStartMusic(); // ========================================================== // START GAME // ========================================================== resetGame(); gameStarted = true; } // ============================================================ // MAIN LOOP // ============================================================ void loop() { if (!gameStarted) { return; } // ========================================================== // GAME OVER // ========================================================== if (gameOver) { gameOverAnimation(); delay(500); // Restart resetGame(); return; } // ========================================================== // INPUT // ========================================================== handleButtons(); // ========================================================== // SOFT DROP // ========================================================== if (softDrop) { handleSoftDrop(); } else { handleNormalFall(); } }