ในส่วนของ Software ที่ใช้เขียนโปรแกรมในการควบคุม Dot
Metrix LED ด้วย microcontroller ซึ่งเราเลือกใช้
Arduino เป็นตัวควบคุม ก่อนอื่นเราก็ควรออกแบบการทำงานของโปรแกรมของเรากันก่อน
ซึ่งขั้นตอนของเราก็ได้แสดงไว้ใน Flowchart ด้านล่าง ดังนี้
การออกแบบโปรแกรมควบคุมบน Arduino
Flowchart โปรแกรมทั้งหมด
หลังจากที่เราออกแบบโปรแกรมเรียบร้อยแล้ว เราก็มาเริ่มลงมือเขียนโปรแกรมตามขั้นตอนด้านบน
โดยใช้ความรู้ เรื่องการเขียนโปรแกรม arduino ที่มีลักษณะการเขียนและตรรกะคล้ายๆกับการเขียนภาษาซี
แต่อาจจะมีบางฟังก์ชันที่แตกต่างกัน เช่น การใช้ digitalWrite ,
digitalRead , ramdomSeed เป็นต้น หากใครที่ยังไม่มีความรู้พื้นฐาน และมีความสนใจ ก็ลองไปศึกษาเพิ่มเติมกันดูนะคะ ^^
ตัวอย่างโปรแกรมเกมงู สามารถนำไปลองเล่นกันได้นะคะ
// Shift Register Pin
const int latchPin = 8; // STCP
const int clockPin = 12; // SHCP
const int dataPin = 11; // DS
// Button Pin
const int leftButton = 6;
const int rightButton = 7;
const int upButton = 9;
const int downButton = 10;
const int delayTime = 1; // in uS
const int shiftTime = 1; // in uS
unsigned long displayUpdateTime;
unsigned long foodTime;
unsigned long foodDelay;
const unsigned long displayRefreshPeriod = 60;
const unsigned long minimumFoodDelay = 900;
const unsigned long maximumFoodDelay = 4000;
typedef struct
{
int x;
int y;
} POINT_T;
POINT_T p[256];
int headPos=2;
int tailPos=0;
// Current Direction N, S, E, W
char headDirection = 'E';
unsigned short data[16] = {
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111};
unsigned short food[16] = {
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111};
unsigned short three[16] = {
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111100000011111,
0b1111101111111111,
0b1111101111111111,
0b1111101111111111,
0b1111100000011111,
0b1111101111111111,
0b1111101111111111,
0b1111101111111111,
0b1111100000011111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111};
unsigned short two[16] = {
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111110000011111,
0b1111111111011111,
0b1111111111011111,
0b1111111111011111,
0b1111110000011111,
0b1111110111111111,
0b1111110111111111,
0b1111110111111111,
0b1111110000011111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111};
unsigned short one[16] = {
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111000000011111,
0b1111111011111111,
0b1111111011111111,
0b1111111011111111,
0b1111111011111111,
0b1111111011111111,
0b1111111011011111,
0b1111111010111111,
0b1111111001111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111};
unsigned short gameover[16]={
0b0110100011011000,
0b0110111011011010,
0b0110111010101010,
0b00001000010101010,
0b1110111010101010,
0b00001111001110010,
0b0110111001110010,
0b0000100001110000,
0b0000111001100000,
0b1100111001100110,
0b1100111001100110,
0b0000101000000010,
0b1100101001101110,
0b1100010001101110,
0b1100010001100110,
0b0000111000000000};
void setup()
{
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(2, OUTPUT); // A0
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT); // A3
pinMode(leftButton, INPUT);
pinMode(rightButton, INPUT);
pinMode(upButton, INPUT);
pinMode(downButton, INPUT);
digitalWrite(leftButton, HIGH);
digitalWrite(rightButton, HIGH);
digitalWrite(upButton, HIGH);
digitalWrite(downButton, HIGH);
p[2].x=9;
p[2].y=10;
p[1].x=8;
p[1].y=10;
p[0].x=7;
p[0].y=10;
randomSeed(analogRead(0));
foodDelay = random(minimumFoodDelay, maximumFoodDelay);
displayUpdateTime = millis();
foodTime = millis();
unsigned long tmp = millis();
while(millis() - tmp < 1000)
{
showDisplay(three);
}
tmp = millis();
while(millis() - tmp < 1000)
{
showDisplay(two);
}
tmp = millis();
while(millis() - tmp < 1000)
{
showDisplay(one);
}
Serial.begin(9600);
}
void loop()
{
unsigned long newTime = millis();
// Update direction
if (headDirection == 'N' || headDirection == 'S')
{
if (digitalRead(leftButton) == LOW)
headDirection = 'W';
if (digitalRead(rightButton) == LOW)
headDirection = 'E';
}
else if (headDirection == 'E' || headDirection == 'W')
{
if (digitalRead(upButton) == LOW)
headDirection = 'N';
if (digitalRead(downButton) == LOW)
headDirection = 'S';
}
// Clear display buffer
for (int i=0; i<16; i++)
{
data[i] = 0xFFFF;
}
// Update snake position
int prevHead = headPos;
if (newTime - displayUpdateTime > displayRefreshPeriod)
{
headPos++;
if (headPos == 256)
headPos = 0;
tailPos++;
if (tailPos == 256)
tailPos = 0;
if (headDirection == 'N')
{
p[headPos].x = p[prevHead].x;
p[headPos].y = p[prevHead].y + 1;
if (p[headPos].y == 16)
p[headPos].y = 0;
}
else if (headDirection == 'S')
{
p[headPos].x = p[prevHead].x;
p[headPos].y = p[prevHead].y - 1;
if (p[headPos].y == -1)
p[headPos].y = 15;
}
else if (headDirection == 'E')
{
p[headPos].x = p[prevHead].x + 1;
p[headPos].y = p[prevHead].y;
if (p[headPos].x == 16)
p[headPos].x = 0;
}
else if (headDirection == 'W')
{
p[headPos].x = p[prevHead].x - 1;
p[headPos].y = p[prevHead].y;
if (p[headPos].x == -1)
p[headPos].x = 15;
}
displayUpdateTime = newTime;
}
for (int i=headPos-1; i>=tailPos; i--)
{
if (i < 0)
i = 255;
if (p[i].x == p[headPos].x && p[i].y == p[headPos].y)
while (1)
{
showDisplay(gameover);
}
}
// Check if snake hit food
//Serial.print(~food[p[headPos].y]);
//Serial.print(" ");
//Serial.print((1 << p[headPos].x));
//Serial.print(" ");
//Serial.println(~food[p[headPos].y] & (0x0001 << p[headPos].x));
if ((~food[p[headPos].y] & (0x0001 << p[headPos].x)) != 0)
{
tailPos--;
if (tailPos < 0)
tailPos = 15;
food[p[headPos].y] |= (1 << p[headPos].x);
}
// Gen food
if (newTime - foodTime > foodDelay)
{
int foodX;
int foodY;
do
{
foodX = random(0, 16);
foodY = random(0, 16);
}
while (isInSnake(foodX, foodY));
food[foodY] &= ~(1 << foodX);
foodTime = newTime;
foodDelay = random(minimumFoodDelay, maximumFoodDelay);
}
// Create display buffer
for(int i=headPos; i>=tailPos; i--)
{
if (i < 0)
i = 255;
data[p[i].y] &= ~(1 << p[i].x);
}
// Display
for (int i=0; i<16; i++)
{
for (int j=0; j<16; j++)
{
digitalWrite(dataPin, ((data[i] & food[i] & (1 << j)) >> j));
delayMicroseconds(shiftTime);
digitalWrite(clockPin, HIGH);
delayMicroseconds(shiftTime);
digitalWrite(clockPin, LOW);
delayMicroseconds(shiftTime);
}
digitalWrite(2, (i&0x01));
digitalWrite(3, (i&0x02) >> 1);
digitalWrite(4, (i&0x04) >> 2);
digitalWrite(5, (i&0x08) >> 3);
digitalWrite(latchPin, HIGH);
delayMicroseconds(shiftTime);
digitalWrite(latchPin, LOW);
delayMicroseconds(shiftTime);
delayMicroseconds(delayTime);
}
//dead
}
void showDisplay(unsigned short data[])
{
for (int i=0; i<16; i++)
{
for (int j=0; j<16; j++)
{
digitalWrite(dataPin, ((data[i] & (1 << j)) >> j));
delayMicroseconds(shiftTime);
digitalWrite(clockPin, HIGH);
delayMicroseconds(shiftTime);
digitalWrite(clockPin, LOW);
delayMicroseconds(shiftTime);
}
digitalWrite(2, (i&0x01));
digitalWrite(3, (i&0x02) >> 1);
digitalWrite(4, (i&0x04) >> 2);
digitalWrite(5, (i&0x08) >> 3);
digitalWrite(latchPin, HIGH);
delayMicroseconds(shiftTime);
digitalWrite(latchPin, LOW);
delayMicroseconds(shiftTime);
delayMicroseconds(delayTime);
}
}
boolean isInSnake(int foodX, int foodY)
{
for (int i=headPos; i>=tailPos; i--)
{
if (i < 0)
i = 255;
if (p[i].x == foodX && p[i].y == foodY)
return true;
}
return false;
}