หน้าแรก ดูโปรเจกต์ทั้งหมด
Easy

โปรเจกต์ Animation และ Gaming บน LCD

เรียนรู้วิธีการสร้าง Animation และสร้าง Game โดยใช้ Arduino และ LCD

โปรเจกต์ Animation และ Gaming บน LCD

รายการอุปกรณ์และเครื่องมือ

1x Alphanumeric LCD, 16 x 2
🛒 สั่งซื้อ

รายละเอียดและวิธีทำ

โปรเจกต์นี้มุ่งเน้นไปที่พื้นฐานของการทำแอนิเมชันโดยใช้ Arduino และ LCD ขนาด 16x2 อย่างไรก็ตาม โปรเจกต์นี้สามารถนำไปประยุกต์ใช้กับ LCD ขนาดอื่นๆ ได้เช่นกัน

เริ่มแรกเราจะเริ่มจากการต่อสาย LCD เข้ากับ Arduino จากนั้นจะลองพิมพ์ข้อความง่ายๆ ลงบน LCD แล้วจึงขยับไปสู่การทำแอนิเมชัน

การต่อสาย LCD

lcd circuit

นี่คือวงจรตามที่แสดงในแผนภาพด้านบน

LCD PIN

1:VSS: ต่อเข้ากับรางบวกของ breadboard (ต่อ 5v ของ Arduino เข้ากับรางบวกด้วย)

2:VDD: ต่อเข้ากับรางลบของ breadboard (ต่อ GND ของ Arduino เข้าที่นี่ด้วย)

3:VO (contrast): ต่อเข้ากับขา wiper ของ potentiometer (ต่อขารูปด้านข้างของ potentiometer เข้ากับรางบวกและรางลบ)

4:RS (register select): ต่อเข้ากับ Arduino pin 12

5:R/W (read-write): ต่อเข้ากับรางลบ

6:E (enable): ต่อเข้ากับ Arduino pin 11

15:A (anode): ต่อเข้ากับรางบวกผ่านตัวต้านทาน 220 ohm

16:K (cathode): ต่อเข้ากับรางลบ

เราจะยังไม่ต่อ data pin ในตอนนี้

เปิดแหล่งจ่ายไฟ และหากแถวล่างสว่างขึ้น แสดงว่า LCD ของคุณทำงานแล้ว คุณต้องทดสอบสิ่งนี้ก่อนที่จะเริ่มทำขั้นตอนอื่นๆ

หาก LCD ไม่สว่างขึ้น ให้ตรวจสอบการ soldering, การต่อสาย (wiring) อีกครั้ง และหากยังไม่สว่าง เป็นไปได้สูงว่า LCD ของคุณอาจจะเสีย ดังนั้นคุณต้องเปลี่ยนใหม่

ถ้า LCD ของคุณทำงานได้ ยอดเยี่ยมมาก! คุณเสร็จสิ้นส่วนแรกของบทช่วยสอนนี้แล้ว

หลังจากนี้ ให้เชื่อมต่อ data pins:

11:D4 (data pin 4): ต่อเข้ากับ Arduino pin 4

12:D5: ต่อเข้ากับ Arduino pin 5

13:D6: ต่อเข้ากับ Arduino pin 6

14:D7: ต่อเข้ากับ Arduino pin 7

หลังจากนั้นให้อัปโหลดโค้ดตัวอย่าง

#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,4,5,6,7);//rs,e,d4,d5,d6,d7 respectively
void setup(){
lcd.begin(16,2);
lcd.setCursor(0,1);
lcd.print("Working");
}
void loop(){
}

หลังจากอัปโหลดแล้ว หากคุณเห็นตัวอักษรมั่วๆ หรือไม่เห็นอะไรเลย ให้ตรวจสอบ contrast (หมุน potentiometer ขึ้นและลง), ตรวจสอบการบัดกรี pin (data pins ต้องไม่เชื่อมต่อกันแม้แต่นิดเดียว) และสุดท้ายตรวจสอบวงจรของคุณและบรรทัดที่ 2 ในโค้ดตัวอย่าง (ตรวจสอบให้แน่ใจว่าหมายเลข Pins ที่ระบุใน LiquidCrystal ตรงกับในวงจรของคุณ)

หากยังไม่มีอะไรเกิดขึ้น อย่าเพิ่งหมดหวัง หากคุณเห็นแถวล่างสว่างขึ้นในส่วนแรก แสดงว่าหน้าจอ LCD ของคุณปกติดี ให้ลองตรวจสอบวงจรและการบัดกรีไปเรื่อยๆ จนกว่าจะใช้งานได้

หากคุณเห็นข้อความ "Working" แสดงว่าคุณต่อสาย LCD สำเร็จและเสร็จสิ้นส่วนที่สองของบทช่วยสอนนี้แล้ว ปล่อยวงจรของคุณไว้แบบนั้น เราจะไม่ยุ่งกับมันอีก สิ่งที่เราต้องทำต่อจากนี้จะอยู่ในส่วนของ Software

คำอธิบายโค้ดในส่วนที่ 2

LiquidCrystallcd(12,11,4,5,6,7);

บรรทัดนี้เป็นการประกาศ object สำหรับ LCD พร้อมกับ interface pins ตามที่ระบุใน arguments ต่อจากนี้การติดต่อกับ LCD ทั้งหมดจะทำผ่าน object 'lcd' นี้ (โปรดทราบว่าคุณสามารถตั้งชื่อนี้เป็นอะไรก็ได้ที่คุณต้องการ แต่ต้องใช้ชื่อนั้นให้เหมือนกันตลอดทั้งโปรแกรม)

lcd.begin(16,2);

บรรทัดนี้กำหนดขนาดหน้าจอ LCD ของเราว่าเป็นแบบ 16 Columns และ 2 Rows โปรดทราบว่า LCD ของคุณอาจไม่ใช่ 16x2 ให้ปรับตัวเลขตามความเหมาะสม

lcd.setCursor(0,1);

บรรทัดนี้จะตั้งค่า cursor ไว้ที่ column แรกและ row ที่สอง (เนื่องจากการนับใน C++ เริ่มต้นด้วย 0 ไม่ใช่ 1!) โปรดทราบว่าคุณไม่สามารถมองเห็น cursor ได้ แต่ cursor มีอยู่เสมอ มันจะกำหนดจุดที่ตัวอักษรถัดไปจะปรากฏขึ้น

lcd.print("Welcome");

บรรทัดนี้จะพิมพ์ข้อความ Welcome ในตำแหน่งที่ cursor ชี้อยู่ นั่นคือ column 0 row 1

Scrolling Text (ข้อความเลื่อน)

เอาล่ะ เราพิมพ์ข้อความลงบนหน้าจอได้แล้ว แต่มันดูไม่ค่อยน่าดึงดูดนักที่จะนั่งจ้องข้อความเดิมๆ แถมยังไม่ค่อยมีประโยชน์อะไรมากนัก ดังนั้นในส่วนนี้เราจะพิมพ์ข้อความที่จะเลื่อนจากขวาไปซ้ายเหมือนกับป้ายโฆษณา เฉพาะฟังก์ชัน setup() และ loop() เท่านั้นที่จะแตกต่างออกไป ดังนั้นผมจะแสดงเฉพาะฟังก์ชันเหล่านั้น ส่วนที่เหลือยังคงเหมือนเดิม

void setup(){
lcd.begin(16,2);
}
void loop(){
int n;
char message[]="scrolling text!";
n=15;
char* ptr=message;
while(n!=-14){
lcd.clear();
lcd.setCursor(n,1);
if(n<0){
ptr++;

}
lcd.print(ptr);
n--;
delay(250);
}
}

โปรดทราบว่าเพื่อที่จะเข้าใจโค้ดนี้ คุณต้องมีความรู้เรื่อง pointers ใน C และ C++ เป็นอย่างดี เนื่องจากภาษา Arduino จริงๆ แล้วก็คือ AVR-C++ ที่ผ่านการประมวลผลมาเล็กน้อยเท่านั้น

ในฟังก์ชัน loop เรากำลังกำหนดข้อความของคุณเป็น constant string

lcd.clear() ถูกใช้เพื่อล้างหน้าจอสำหรับทุกๆ iteration (รอบการทำงาน)

จากนั้นเราตั้งค่า pointer ptr เพื่อเก็บ address ของ message ค่า pointer นี้จะถูกเพิ่มขึ้น (incremented) เพื่อให้ข้อความพอดีกับหน้าต่าง LCD แม้ว่าตัวอักษรจะเลื่อนออกไปทางด้านซ้ายแล้วก็ตาม เราทำสิ่งนี้สำหรับขอบด้านซ้าย ไม่ใช่ด้านขวา เพราะ Library LiquidCrystal สามารถจัดการขอบด้านขวาได้ (ข้อความเลื่อนออก) แต่ไม่สามารถจัดการกับ column address ที่เป็นค่าลบตามที่โปรแกรมของเราต้องการได้

จากนั้นเรามี while loop ซึ่งจะแสดงข้อความในตำแหน่งต่างๆ จากขวาไปซ้าย ทำให้เกิดภาพลวงตาว่าข้อความกำลังเคลื่อนที่ โปรดทราบว่า delay() ที่ตอนท้ายนั้นมีไว้เพื่อให้แน่ใจว่าเราสามารถอ่านข้อความได้ทัน และมันจะไม่เลื่อนจากขวาไปซ้ายด้วยความเร็วที่อ่านไม่ออก หากแอนิเมชันดูช้าหรือเร็วเกินไป คุณสามารถเปลี่ยนค่า delay ได้

Custom Characters (ตัวอักษรที่กำหนดเอง)

สำหรับการใช้งานฟังก์ชัน lcd.print() ทั้งหมด เราไม่สามารถแสดงผลรูปภาพ เช่น ไดโนเสาร์ บนหน้าจอ LCD ได้ อย่างไรก็ตาม เราสามารถทำได้โดยใช้ฟีเจอร์ของ Library LiquidCrystal ที่เรียกว่า Custom Characters

สำหรับสิ่งนี้ เราจะกำหนด byte ของข้อมูล ซึ่งประกอบด้วยเลข 1 สำหรับพิกเซลที่เปิด และ 0 สำหรับพิกเซลที่ปิด ดังนี้:

byte dino[]={
B01110,
B01110,
B01100,
B01111,
B11101,
B01010,
B01010,
B01010}

นี่คือ Custom Character ซึ่งจะแสดงรูปไดโนเสาร์บนหน้าจอ LCD คุณสามารถสร้างตัวอักษรของคุณเองได้ที่นี่: https://maxpromer.github.io/LCD-Character-Creator/

หลังจากนี้เราจำเป็นต้องแสดงผลพวกมัน อย่างไรก็ตาม ตัวอักษรเหล่านี้ไม่สามารถแสดงผลโดยใช้วิธี lcd.print ปกติได้ เราจำเป็นต้องใช้สิ่งนี้:

void setup(){
lcd.createChar(0,dino);
lcd.begin(16,2);
lcd.setCursor(0,1);
lcd.write(byte(0));
}

ด้วยโค้ดนี้ เราจะสร้าง addressable custom character จาก byte dino[] ที่เรากำหนดไว้ก่อนหน้านี้ address ของ custom character ของเราถูกกำหนดโดย Method lcd.createChar() ซึ่งกำหนดตัวอักษร 0 ให้เป็น dino[] จากนั้นเราจะอ้างอิงถึงตัวอักษรนี้ในชื่อ byte(0) ซึ่งจะส่งคืน address ของ custom character ของเรา และสุดท้ายจะพิมพ์ลงบนหน้าจอโดยใช้ Method lcd.Write()

Shooting Arrows (การยิงธนู)

โปรแกรมนี้จะสอนวิธีทำแอนิเมชันโดยใช้หน้าจอ LCD ในที่สุด โปรดอ่านอย่างละเอียด

#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,4,5,6,7);
byte arrowhead[]={
B00001,
B00011,
B00111,
B01111,
B00111,
B00011,
B00001,
B00000
}
byte arrowbody[]={
B00000,
B00000,
B00000,
B11111,
B11111,
B00000,
B00000,
B00000
}
byte
B00011,
B00111,
B01111,
B11111,
B11111,
B01111,
B00111,
B00011
}
void
lcd.createChar(0,arrowhead);
lcd.createChar(1,arrowbody);
lcd.createChar(2,arrowtail);
lcd.begin(16,2);
}
void
int
while(n!=-1){
lcd.clear();
lcd.setCursor(0,1);
lcd.write(byte(0));
lcd.write(byte(1));
lcd.write(byte(2));
n--;
delay(50);
}
}

ในที่นี้เราใช้ Custom Characters สามตัวเพื่อเลียนแบบลูกธนู ส่วนที่เหลือน่าจะคุ้นเคยสำหรับคุณแล้ว ในขณะที่รันโปรแกรมนี้บน LCD ของคุณ คุณอาจสังเกตเห็นรอยตามหลังหางธนูที่ทำให้มันดูยาวกว่าที่เป็นจริง อย่าตกใจไป มันเป็นเพียงภาพตกค้างของตำแหน่งธนูก่อนหน้าเท่านั้น

เพียงเท่านี้! คุณได้ทำแอนิเมชันชิ้นแรกด้วย Arduino และ LCD เสร็จแล้ว! ลองเล่นกับโค้ดดู และรวมสิ่งนี้เข้ากับการกดปุ่ม (button inputs) เพื่อเปลี่ยนให้เป็นเกมเต็มรูปแบบ!

LCD Game

ในที่สุดเราก็สามารถสร้างเกมได้! อย่างไรก็ตาม ในบทช่วยสอนนี้ผมจะไม่เริ่มด้วยเกมที่ซับซ้อนมากนัก แต่จะเป็นเกมง่ายๆ ที่คล้ายกับเกม Arcade ในยุคแรกๆ

เป้าหมายของเกมนี้

ก่อนที่เราจะเริ่มสร้างเกม เราต้องกำหนดเป้าหมายสำหรับการเล่นเกมก่อน

ในเกมนี้ เป้าหมายมีดังนี้:

มีฮีโร่เป็นตัวละครบน row 1 (โปรดทราบว่าแถวแรกคือ row 0 โดยปกติ) ซึ่งจะมีธนูหลายลูกยิงเข้าใส่ หากฮีโร่ถูกยิง เกมจะจบลง ฮีโร่จะต้องหลบธนูโดยการกระโดดไปที่ row 0 ซึ่งเราจะควบคุมด้วยปุ่ม (กดปุ่ม = row 0, ไม่กด = row 1) คะแนนจะเพิ่มขึ้นในแต่ละ Loop และแสดงที่มุมขวาบน

จริงๆ แล้วนี่คือส่วนขยายของแอนิเมชันยิงธนูก่อนหน้านี้ ดังนั้นผมจะรวมเฉพาะส่วนที่มีการเปลี่ยนแปลงเท่านั้น

byte man[] = {
B01110,
B01110,
B00100,
B01110,
B10101,
B00100,
B01010,
B10001
};
void setup() {
// set up the LCD's number of columns and rows:
lcd.createChar(0,arrowhead);
lcd.createChar(1,arrowbody);
lcd.createChar(2,arrowtail);
lcd.createChar(3,man);
lcd.begin(16, 2);
attachInterrupt(0,buttonin,CHANGE);
randomSeed(analogRead(A0));
// Print a message to the LCD.
//lcd.print("hello, world!");
}
int n;
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
//lcd.setCursor(0, 1);
// print the number of seconds since reset:
//lcd.print(millis() / 1000);
n=15;
int rnd;
rnd=random(15,25);
while(n!=-1){
lcd.clear();
delay(10);
drawman();
lcd.setCursor(n,1);
if(n==1){
if(level==1){
stopgame();
continue;
}
}
lcd.write(byte(0));
lcd.write(byte(1));
lcd.write(byte(2));
lcd.setCursor(10,0);
lcd.print(score);
delay(100-rnd);
n--;
score++;
if(level==0)
score--;
}
}
void drawman(){
lcd.setCursor(1,level);
lcd.write(byte(3));
}
void buttonin(){
if(digitalRead(2)==LOW){
level=0;
}
else{
level=1;
}
}
void stopgame(){
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Game over");
lcd.setCursor(10,0);
lcd.print(score);
level=1;
score=0;
n=15;
delay(3000);
return;
}

โค้ดทั้งหมดนี้ไม่ได้เกี่ยวกับ LCD เพียงอย่างเดียว แต่ทั้งหมดมีความสำคัญต่อการพัฒนาเกม

เราเริ่มด้วยการกำหนดตัวละคร man[] ซึ่งจะเก็บ byte สำหรับตัวละครคน (ฮีโร่ของเรา) จากนั้นเรามีฟังก์ชัน setup ซึ่งมีเพียงสองบรรทัดที่เปลี่ยนไป ทั้งสองบรรทัดเป็นตัวแทนของกลุ่มฟังก์ชันที่กว้างขวาง นั่นคือ Interrupts และ Random Numbers ทั้งคู่เป็นเครื่องมือที่มีประโยชน์มาก ซึ่งคุณสามารถหาข้อมูลเพิ่มเติมได้ในเว็บไซต์ arduino.cc

อันดับแรก เรามีฟังก์ชัน attachInterrupt โปรดทราบว่าคำอธิบายที่ผมจะให้นี้อาจไม่ครอบคลุมทั้งหมด แต่สรุปสั้นๆ เพื่อให้เข้าใจว่าเกิดอะไรขึ้นที่นี่

Interrupts คือฟังก์ชันที่สามารถถูกเรียกใช้เมื่อมีเหตุการณ์เกิดขึ้น ไม่ว่าโปรแกรมจะกำลังประมวลผล (execution) อยู่ที่จุดใดก็ตาม นี่เป็นข้อเท็จจริงที่สำคัญซึ่งมีประโยชน์ในการสร้างฟังก์ชันรับค่าแบบ real-time ในที่นี้เราใช้มันเพื่อให้แน่ใจว่าไม่ว่าการประมวลผลจะอยู่ที่จุดใด หากมีการกดปุ่ม เราจะดำเนินการที่เหมาะสมทันที (อย่างน้อยโปรแกรมก็จะทำเช่นนั้น)

Syntax สำหรับ attachInterrupt:

attachInterrupt(pin_number-2, function_to_call_without_parenthesis, condition_for_calling);

CHANGE คือค่า #define ที่ใช้เพื่อระบุว่า สำหรับการเปลี่ยนแปลงสถานะใดๆ ใน pin_number ข้อมูลนำเข้า ฟังก์ชันที่แนบมาจะถูกเรียกใช้

จากนั้นเรามีเรื่องของ Random Number คุณสมบัติเด่นอย่างหนึ่งที่โปรเซสเซอร์ทางกายภาพอย่าง Arduino มี แต่โปรเซสเซอร์ปกติไม่มี คือเลขสุ่มที่สร้างโดย Arduino นั้นเป็นเลขสุ่มจริงๆ เนื่องจากสัญญาณรบกวนอนาล็อก (analog noise) ที่มีอยู่ที่ pin A0 หาก pin A0 ถูกปล่อยลอยไว้ (floating หรือไม่ได้ต่อสาย) จะเป็นค่าสุ่มตามที่ฟิสิกส์ควอนตัมคาดการณ์ไว้ (โดยประมาณ)

randomSeed ใช้สำหรับตั้งค่า seed สำหรับกระบวนการสุ่ม random() เป็นฟังก์ชันที่มี Parameter คือ MIN, MAX หรือ MAX เพียงอย่างเดียวเพื่อรับเลขสุ่มตัวถัดไปในลำดับ

จากนั้นเรามีฟังก์ชัน Interrupt ที่ชื่อ buttonin() ซึ่งจะตรวจสอบว่าปุ่มถูกกด (LOW) หรือไม่กด (HIGH) และเปลี่ยน level (row) ของฮีโร่เราตามนั้น

เพียงเท่านี้ เราก็จะได้เกมที่ใช้งานได้สมบูรณ์แล้ว!!

Code

🔒 ปลดล็อก Code

สนับสนุนเพื่อรับ Source Code หรือแอปพลิเคชันสำหรับโปรเจกต์นี้

รหัสอ้างอิงโปรเจกต์: lcd-animation-and-gaming-a6984d
2450 บาท
PromptPay QR Code

ประเมิน Project

อยากได้งานคล้ายโปรเจคนี้? กดไปหน้าประเมินราคา

เอาฟอร์มยาวออกจากท้ายหน้า Project แล้ว เหลือเป็นปุ่มให้กดไปกรอกหน้าเดียว ตัวใหญ่ เว้นบรรทัดเยอะ อ่านง่ายกว่า

รีวิวจากคนใช้งานจริง

รีวิวจากลูกค้าและคนที่เคยใช้งาน

ถ้าเคยสั่งงาน เคยอ่านหน้านี้แล้วได้ประโยชน์ หรือมีข้อเสนอแนะ ฝากรีวิวไว้ได้เลย

กำลังโหลดรีวิว...