DIY Arduino LCD 프로젝트: 저항, 푸시버튼, 16x2 디스플레이로 축구 게임 만들기
부품 및 소모품
저항 10k옴
2
LCD 대비용 1개, 버튼용 1개. 중요: 풀다운 구성으로 사용하세요 (매뉴얼의 풀업 구성 아님).
저항 1k옴
1
LCD 대비용.
SparkFun 푸시버튼 스위치 12mm
1
Adafruit 표준 LCD - 16x2 흰색/파란색
1
Arduino UNO
1
점퍼 와이어 (범용)
1
프로젝트 소개
배경
더 큰 프로젝트의 일부였으나 지연되어 오래된 Arduino 키트로 무언가 해보기로 했습니다. LCD 화면은 처음 써봤습니다. 핀을 직접 납땜했는데(첫 납땜 연습), 온라인 매뉴얼의 코드를 복사해 업로드하니 텍스트가 좌우로 움직이는 것만 나왔습니다. 그때 LiquidCrystal 라이브러리를 알게 되었고, 숫자 "0"이 화면 튕기게 하는 코드를 짜보니 재밌었습니다. 더 복잡한 게임을 만들고 싶어 검색해 보니 Arduino LCD 게임이 3개뿐이었고 그중 2개만 작동했습니다. 코드가 너무 복잡해 이해하기 어려워 직접 간단한 게임을 만들기로 했습니다.
설정 방법
아래 회로도처럼 LCD 핀을 Arduino에 연결하세요.
10k 가변저항으로 대비를 조절해 원하는 값으로 맞춘 후, 멀티미터로 핀간 저항을 측정해 적절한 저항(1k와 10k를 직렬 연결)을 LCD의 VO 핀에 사용했습니다.
브레드보드에 푸시버튼을 놓고 입력선을 Arduino 8번 핀에 연결하세요. 코드를 업로드하면 준비 완료입니다.
주의: 버튼 저항은 회로도처럼 풀다운 모드로 사용하세요.
게임 방법
당신은 공을 가진 축구 선수입니다. 수비수들이 다가오면 버튼을 눌러 피하세요.
인트로 후 버튼을 누르면 시작합니다. 수비수가 충분히 가까이 오면 버튼을 눌러 점프하세요. 다음 수비수는 더 빠른 속도로 다가오며, 총 10명의 수비수를 피하면 됩니다.
PS: 처음엔 "0"을 플레이어, "1"을 장애물로 썼는데 2018 FIFA 월드컵 기간이고 메시 팬이라 테마를 바꿨습니다. 플레이어와 수비수 글리프는 온라인 생성기(https://omerk.github.io/lcdchargen/ )로 만들었습니다.
코드
lcd_1.ino (Arduino)
/* Dodge the defs!!
* Created by: Shreyas R P
* Created on: 21-06-2018
* E-mail: shreyasrp888@gmail.com
* 16x2 LCD와 버튼으로 하는 간단한 게임.
* 개선 사항이 있으면 크레딧에 추가해 주세요.
* GPL v3 라이선스 적용. */
#include <LiquidCrystal.h>
const int btn = 8; // 버튼 입력 핀
// 표시할 텍스트
char* introText[] = {"Dodge the defs!!", "Created on:", "Hit the button..."};
// 변수 선언
int game = 0;
int buttonPress = 0;
int buttonState = 0;
int obstaclePos;
int obsDelay;
int score = 0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
int lastButtonState = LOW;
// 그래픽: 커스텀 문자 (8x8 픽셀)
byte runnin1[8] = { 0b01100, 0b01100, 0b00000, 0b11100, 0b01110, 0b01100, 0b11110, 0b00011 };
byte runnin2[8] = { 0b00110, 0b00110, 0b00000, 0b00111, 0b01110, 0b00110, 0b01110, 0b00101 };
byte jump[8] = { 0b00100, 0b01100, 0b11100, 0b01110, 0b01100, 0b11111, 0b00000, 0b00001 };
byte def1[8] = { 0b00100, 0b00110, 0b00111, 0b01110, 0b00110, 0b01111, 0b01000, 0b00000 };
byte def2[8] = { 0b00100, 0b00110, 0b00111, 0b01110, 0b00110, 0b00110, 0b00110, 0b00010 };
byte slide[8] = { 0b00000, 0b00000, 0b00011, 0b00011, 0b00000, 0b01111, 0b11111, 0b00000 };
LiquidCrystal lcd(4, 6, 10, 11, 12, 13);
void setup() {
Serial.begin(9600);
pinMode(btn, INPUT);
lcd.begin(16, 2);
lcd.createChar(0, runnin1);
lcd.createChar(1, runnin2);
lcd.createChar(2, jump);
lcd.createChar(3, def1);
lcd.createChar(4, def2);
lcd.createChar(5, slide);
buttonState = digitalRead(btn);
}
void loop() {
intro();
while (game == 1) ballActive();
endGame();
}
void intro() {
score = 0;
lcd.clear();
lcd.print(introText[0]);
lcd.setCursor(7, 1);
lcd.print("By SRP888");
delay(2000);
lcd.clear();
lcd.print(introText[1]);
lcd.setCursor(0, 1);
lcd.print("21-06-2018");
delay(2000);
lcd.clear();
while (button() != 1) {
lcd.setCursor(0, 0);
lcd.print(introText[2]);
delay(100);
}
if (button() == 1) game = 1;
}
void reset() {
if (obstaclePos % 2 == 0) {
lcd.clear();
lcd.setCursor(0, 1);
lcd.write(byte(0));
} else {
lcd.clear();
lcd.setCursor(0, 1);
lcd.write(1);
}
}
void ballActive() {
obsDelay = 200;
obstaclePos = 15;
while (game == 1) {
reset();
if (button() == 1) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(2); // 점프
obstacle(obstaclePos);
delay(400);
lcd.clear();
lcd.setCursor(0, 1);
lcd.write(1); // 착지
obstacle(obstaclePos);
} else {
if (obstaclePos != 0) {
reset();
obstacle(obstaclePos);
} else {
game = 0;
break;
}
}
obstaclePos--;
if (obstaclePos < 0) {
obsDelay -= 20;
obstaclePos = 15;
score++;
}
if (obsDelay == 0) game = 0;
delay(obsDelay);
}
}
int button() {
int reading = digitalRead(btn);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
buttonState = reading;
if (buttonState == HIGH) {
lastButtonState = reading;
return 1;
}
}
lastButtonState = reading;
return 0;
}
void obstacle(int i) {
if (obstaclePos % 2 == 0 && obstaclePos > 2) {
lcd.setCursor(i, 1);
lcd.write(3);
} else if (obstaclePos % 2 != 0 && obstaclePos > 2) {
lcd.setCursor(i, 1);
lcd.write(4);
} else {
lcd.setCursor(i, 1);
lcd.write(5);
}
}
void endGame() {
if (score == 10) {
lcd.clear();
lcd.print("Congratulations!");
lcd.setCursor(0, 1);
lcd.print("You beat 'em all");
delay(3000);
} else if (score < 3) {
lcd.clear();
lcd.print("You suck");
lcd.setCursor(0, 1);
lcd.print("Score: ");
lcd.print(score);
delay(3000);
} else if (score < 6) {
lcd.clear();
lcd.print("Not bad!");
lcd.setCursor(0, 1);
lcd.print("Score: ");
lcd.print(score);
delay(3000);
} else {
lcd.clear();
lcd.print("Great!");
lcd.setCursor(0, 1);
lcd.print("Score: ");
lcd.print(score);
delay(3000);
}
}
회로도