วันจันทร์ที่ 16 ธันวาคม พ.ศ. 2556

ตัวอย่างผลงาน สรุปผลการทำโครงงาน และ อุปสรรค

            Software ของเราก็เสร็จเป็นที่เรียบร้อย ไหนๆผลงานเราจะออกมาเป็นยังไงกันนะ ไปดูกันเลยยย!!!











เป็นอย่างไรกันบ้างคะ สนุกใช่ไหมคะ แต่ยังไม่จบเพียงเท่านี้ เรามาดูบทสรุปของโครงงานนี้กันดีกว่า


สรุปผลการทำโครงงาน

          การทำโครงงานนี้ "Building the snake game using metrix LED with the Arduino" ทางผู้จัดทำได้ศึกษาการต่อวงจรเบื้องต้น ของการต่อ shift register และ decoder และในการเขียนโปรแกรม Arduino เพิ่มเติมจากการเรียนในคาบเรียน CPE111ซึ่งเป็นการนำความรู้ที่ได้รับมาประยุกต์ใช้ในการทำโครงงานที่เราสนใจ เป็นการนำความรู้มาต่อยอด และศึกษาความรู้เพิ่มเติม เพื่อใช้ในการควบคุมการเดินและทิศทาง ของงูด้วยโปรแกรม Arduino โดยผ่านวงจรของ shift register และ decoder  ซึ่งถือเป็นประโยชน์อย่างยิ่ง นอกจากเราจะได้รับความรู้ใหม่เพิ่มเติมแล้ว เรายังรู้วิธีพัฒนา เติมเต็มความรู้ของเรา ว่าเราจะหาข้อมูลได้จากที่ไหน รู้จักการค้นคว้าหาความรู้ด้วยตนเอง เป็นการปรับเปลี่ยนพฤติกรรมการเรียนในทางที่ดีขึ้น  


ปัญหาและอุปสรรคในการโครงงาน
-     อุปกรณ์บางอย่างมีปัญหาเช่น shift register
-     การบัดกรีไม่ชำนาญมากนักจึงทำให้บัดกรีแล้วมีจุดชำรุดอยู่บ้าง ส่งผลให้อุปกรณ์จริงชำรุดไปด้วย   
-     เนื่องจากได้บอร์ด Dot Matrix LED ที่สำเร็จมาจากรุ่นพี่ แต่ pin ในแต่ละช่องไม่ได้เรียงไปตามหลอด LED ตามลำดับ เมื่อทำการเชื่อม shift register และ decoder จึงทำให้ เกิดความยุ่งยากในการบัดกรีสายไฟเพราะสายไฟนั้นจะโยงสลับกันหมด
-     บอร์ด Dot Matrix LED มีปัญหาเนื่องจาก hardware ชำรุดเพราะมีการหยิบใช้งานอาจรุนแรงกับชิ้นงาน เกินไป


ท้ายที่สุดนี้ขอขอบคุณทุกๆท่านที่เข้ามาอ่านบล๊อกนี้นะคะ พวกเราหวังว่าทุกๆท่าน จะได้รับความรู้ ความสนุกสนานเพลิดเพลินติดไม้ติดมือกันไปบ้าง ^^


"Building the snake game using metrix LED with the Arduino"

วันอาทิตย์ที่ 15 ธันวาคม พ.ศ. 2556

ขั้นตอนการเขียนโปรแกรมเพื่อควบคุมการทำงานของเกมส์งู ด้วย Arduino

           ในส่วนของ 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;
}











วันพฤหัสบดีที่ 12 ธันวาคม พ.ศ. 2556

              การต่อบอร์ดควบคุม

       การต่อวงจร ส่วนของ Shift register และ Decoder เพื่อที่จะต่อเข้ากับ Microcontroller (Arduino) และ Pin ของ Dot Matrix LED ซึ่ง Pin ในแต่ละช่อง ไม่ได้เรียงไปตามช่องของ Dot Matrix LED ทั้งแนวตั้ง และแนวนอน (เป็น Pin ของ Dot Matrix LED สำเร็จที่รุ่นพี่ทำไว้ดังนั้นการทำวงจรเพิ่มเติม จึงต้องมีการเรียงช่อง Pin ใหม่ เพื่อให้ไฟเรียงตามลำดับ  


       การเชื่อม Shift register  (74HC595)

     - Pin 1-16 จะเชื่อมเข้ากับ Q0-Q7 ของ shift register โดยที่ Pin 1-8 จะเชื่อมเข้ากับ shift register ตัวแรก ที่ต่อ DS เข้า Arduino  Pin 9-16 จะเชื่อมเข้ากับ shift register ตัวที่สอง 
    - Q7' ตัวแรกเชื่อมกับ DS ตัวที่สอง
    - Vcc และ MR ของทั้งสองตัว ต่อเข้าไฟ 5V
    - STCP เชื่อมกับ STCP เข้า Arduino
    - SHCP เชื่อมกับ SHCP เข้า Arduino
    - OE เชื่อมกับ OE ลงกราวด์
    - GND ต่อลงกราวด์


      การเชื่อม decoder (74HC138)

    - Pin 1-16 จะเชื่อมเข้ากับ Y0 - Y7 ของ Decoder โดยที่ Pin 1-8 จะเชื่อมเข้ากับ decoder ตัวแรก ที่ต่อ  E1  เชื่อม กับ E3 ของ decoder ตัวที่สอง เข้า Arduino  Pin 9-16 จะเชื่อมเข้ากับ decoder ตัวที่สอง
    -  E2 ของ decoder ตัวแรก ต่อลงกราวด์
    -  E3 ของ decoder ตัวแรก ต่อเข้าไฟ 5V
    -  E1 และ E2 ของ decoder ตัวที่สอง ต่อลงกราวด์
    - A0 เชื่อม A0  เข้า Arduino
    - A1 เชื่อม A1 เข้า Arduino
    - A2 เชื่อม A2  เข้า Arduino
    - Vcc ต่อเข้าไฟ 5V
    - GND ต่อลงกราวด์
   

บอร์ดของจริงที่เชื่อมเสร็จเรียบร้อยแล้ว





ภาพรวมการต่อวงจรควบคุม

                 บอร์ดควบคุม (บอร์ด shift register,decoder) จะถูกต่อเข้า 2 ส่วน คือ Arduino โดยเชื่อมเข้า  ในแต่ละ Pin mode ของ Arduino  และ บอร์ด Dot Matrix LED โดยใช้สายแพเป็นตัวเชื่อม 







วันพุธที่ 27 พฤศจิกายน พ.ศ. 2556

อุปกรณ์ที่ใช้ในการสร้างเกมงู

อุปกรณ์หลัก
1. Microcontroller (Arduino)
                เป็นเหมือนตัวกลางในการรับข้อมูลจากโปแกรม Arduino  และการส่งข้อมูลเข้าจากปุ่มควบคุม 


2. Shift register 74HC595
        จะมีข้อมูลเข้าแบบอนุกรม ออกแบบขนาน เพื่อการควบคุมหลอด LED ทั้งหมด 16 หลอด

3. Decoder  74HC138
        เป็นวงจรการถอดรหัส ทำหน้าที่เปลี่ยนรหัส Binary ที่ input จำนวน N บิต ให้เป็นสาย output ที่จำนวน M สาย


4. Power supply
              เป็นเหมือนไฟเลี้ยง จะจ่ายไฟ 5V ให้กับวงจร เพื่อการทำงานของวงจร

5. บอร์ดไข่ปลา
        เพื่อเป็นฐานของการทำวงจรเพิ่มเติม

6. LED 16x16
        เป็นแบบ Dot Matrix LED 16x16


7. Control button
        เป็นปุ่มที่ใช้ควบคุมทิศทางของตัวงูในเกม ก็จะมี ขึ้น ลง ซ้าย ขวา 

8. Socket IC
        เป็นขาที่ใช้เสียบกับ IC เพื่อป้องกันการชำรุดของ IC


อุปกรณ์ย่อย


1. สายไฟ 

2. อุปกรณ์บัดกรี


3. สายแพ และ pin ที่ใช้เสียบสายแพร


        หลังจากอุปกรณ์ครบแล้ว ก็ลงมือบัดกรีงานในส่วนของแผงวงจร Shift register และ decoder ! เฮ้



       
ติดตามดูวิธีการทำ Hardware ต่อได้ใน blog ถัดๆไปนะคะ