Rahul Mohoto
Published © GPL3+

SnakePedia

A snake game, which is built on 8*8 LED dot matrix display with dedicated push buttons to control the movement.

BeginnerFull instructions provided10 hours5,339

Things used in this project

Hardware components

5 mm LED: Red
5 mm LED: Red
×64
Shift Register
×2
Vero Board
×1
Gravity:Digital Push Button (Yellow)
DFRobot Gravity:Digital Push Button (Yellow)
×4
ATmega328
Microchip ATmega328
It is optional to go for a micro-controller like ATMega328p, instead we can use Arduino UNO.
×1
Jumper wires (generic)
Jumper wires (generic)
×30

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Flux, Soldering
Solder Flux, Soldering
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Dot Matrix

This schematic shows how to connect 64 LEDs with shift registers and arduino to make a LED dot matrix display work

The Brain

this shows the circuit diagram of the controller board which involves micro-controller ATMega328p with dedicated push buttons.

Code

LED matrix test code

Arduino
It is used to debug and test the connection between Arduino and LED matrix. It also shows how multiplexing can be achieved using two shift registers.
byte scroll[]={
  0B11111110,
  0B11111101,
  0B11111011,
  0B11110111,
  0B11101111,
  0B11011111,
  0B10111111,
  0B01111111
  };

  byte point[]={
    0B00000001,
    0B00000010,
    0B00000100,
    0B00001000,
    0B00010000,
    0B00100000,
    0B01000000,
    0B10000000
    };

    int latchPin=11;
    int clockPin=12;
    int dataPin=9;
  
void setup() {
  // put your setup code here, to run once:
  pinMode(latchPin,OUTPUT);
  pinMode(clockPin,OUTPUT);
  pinMode(dataPin,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  for(int i=0;i<8;i++){
    for(int j=0;j<8;j++){
      digitalWrite(latchPin,LOW);
      shiftOut(dataPin,clockPin,MSBFIRST,scroll[i]);
      shiftOut(dataPin,clockPin,MSBFIRST,point[j]);
      digitalWrite(latchPin,HIGH);
      delay(100);
      }
      }
}

Full Game Code

Arduino
This is the code that runs the snake game
// SNAKE GAME on 8x8 LED matrix
// using Arduino and 2 74HC595 shift register.

// Pin connected to Pin 12 of 74HC595 (Latch)
int latchPin = 5;

// Pin connected to Pin 11 of 74HC595 (Clock)
int clockPin = 6;

// Pin connected to Pin 14 of 74HC595 (Data)
int dataPin = 7;

// Screen
byte led[8];

// button pin
int btn_up = 9;
int btn_down = 10;
int btn_left = 11;
int btn_right = 12;

// game variables
typedef struct Link {
  int x;
  int y;
  struct Link * next;
} Link;

Link * pHead = NULL;
Link * pTail = NULL;

int curDirection = 4;
int newDirection = 4;
int appleX = 5;
int appleY = 5;

unsigned long oldTimer, curTimer;

boolean dead = 0;

void setup() {
  // Seed Random Generator with noise from analog pin 0  
  randomSeed(analogRead(0));

  // set pins to output
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  
  // set button pins to input
  pinMode(btn_up, INPUT_PULLUP);
  pinMode(btn_down, INPUT_PULLUP);
  pinMode(btn_left, INPUT_PULLUP);
  pinMode(btn_right, INPUT_PULLUP);
  
  Serial.begin(9600);
  // clear screen
  clrscr();
}

void loop() {

  snakeInit();
  screenUpdate();
  oldTimer = millis();
  curTimer = millis();

  while(!dead) {
    curTimer = millis();
    
    setDirection();
    
    if(curTimer-oldTimer >= 250) {
      curDirection = newDirection;
      moveSnake(curDirection);
      screenUpdate();
      oldTimer = millis();
    }
    
    // update screen
    screenDisplay();
  }
  
  int count = 0;
  while(count<8) {
    curTimer = millis();
    if(curTimer-oldTimer >= 100) {
      led[count]=B11111111;
      oldTimer = millis();
      count++;
    }
    screenDisplay();
  }
  
  clrscr();
  
  while(1) {
    curTimer = millis();
    if(curTimer-oldTimer >= 700) {
      for(int i=0; i<8; i++) {
        led[i]=led[i];
      }
      oldTimer = millis();
    }
    screenDisplay();
  }
  
  
}

void
addHead(int x, int y)
{
  Link *temp;
  temp = (Link*) malloc (sizeof(Link));
    
  // create new head
  temp->x = x;
  temp->y = y;
  temp->next = NULL;
    
  if(pHead!=NULL)
    pHead->next = temp;
    
  // point to new head
  pHead = temp;
}


void snakeInit() {
  int x = 3;
  int y = 3;
  for (int i=0; i<2; i++, x++) {
    addHead(x,y);
    if (i == 0)
      pTail = pHead;
  }
}

void setDirection() {
  if(digitalRead(btn_up) == LOW) {
    if(curDirection!=2)
      newDirection = 1;
  }
  if(digitalRead(btn_down) == LOW) {
    if(curDirection!=1)
      newDirection = 2;
  }
  if(digitalRead(btn_left) == LOW) {
    if(curDirection!=4)
      newDirection = 3;
  }
  if(digitalRead(btn_right) == LOW) {
    if(curDirection!=3)
      newDirection = 4;
  }
}

void moveSnake(int direction)
{
  int newX = pHead->x;
  int newY = pHead->y;
  if(direction==1)
    newY--;
  if(direction==2)
    newY++;
  if(direction==3)
    newX--;
  if(direction==4)
    newX++;

  if(newX > 8)
    newX=1;
  if(newX < 1)
    newX=8;
  if(newY > 8)
    newY=1;
  if(newY < 1)
    newY=8;

  dead |= check(newX, newY);

  if(!dead) {
    if(newX==appleX && newY==appleY) {
      addHead(newX, newY);
      newApple();
    }
    else {
      Link *temp = pTail;
            
      // point to new tail
      pTail = pTail->next;
            
      // new head
      pHead->next = temp;
      pHead = temp;
            
      pHead->x = newX;
      pHead->y = newY;      
      pHead->next = NULL;
    } 
  }
}

void newApple() {
  boolean check = 0;
  Link * ptr = pTail;
  do {
    check = 0;
    appleX = random(7) + 1;
    appleY = random(7) + 1;
    Serial.println(appleX);
    while(ptr!=NULL) {
      if(appleX==(ptr->x) && appleY==(ptr->y)) {
        check = 1;
        break;
      }
      ptr = ptr->next;
    }
  } while (check == 1);
}
    
boolean check(int x, int y) {
  Link *ptr;
  ptr = pTail;
  while(ptr!=NULL)
  {
    if(x==ptr->x && y==ptr->y)
      return 1;
    ptr=ptr->next;
  }
  
  return 0;
}
  
//
// display driver
//
void screenUpdate() {
  Link * ptr;
  ptr = pTail;
  
  clrscr();
  while(ptr!=NULL) {
    led[ptr->y-1] = led[ptr->y-1] | (1<<(8-ptr->x));
    ptr = ptr->next;
  }
  
  led[appleY-1] = led[appleY-1] | (1<<(8-appleX));
}  
  
void screenDisplay() {
  byte row = B10000000;

  for (byte k = 0; k < 8; k++) {
    // Open up the latch ready to receive data
    digitalWrite(latchPin, LOW);
    
    shiftData(~row); // if use PNP transitors
    // shiftData(row);
    shiftData(led[k]);
    // Close the latch, sending the data in the registers out to the matrix
    digitalWrite(latchPin, HIGH);
    row = row >> 1;
  }
}

void clrscr()
{
  for(int i=0; i<8; i++) {
    led[i] = B00000000;
  }
}

void shiftData(byte data) {
  // Shift out 8 bits LSB first,
  // on rising edge of clock
  boolean pinState;

  //clear shift register read for sending data
  digitalWrite(dataPin, LOW);

  // for each bit in dataOut send out a bit
  for (int i=0; i<8; i++) 
  {
    //set clockPin to LOW prior to sending bit
    digitalWrite(clockPin, LOW);

    // if the value of data and (logical AND) a bitmask
    // are true, set pinState to 1 (HIGH)
    if (data & (1<<i)) 
    {
      pinState = HIGH;
    }
    else 
    {
      pinState = LOW;
    }

    //sets dataPin to HIGH or LOW depending on pinState
    digitalWrite(dataPin, pinState);

    //send bit out on rising edge of clock
    digitalWrite(clockPin, HIGH);
    digitalWrite(dataPin, LOW);
  }

  //stop shifting
  digitalWrite(clockPin, LOW);
}

Credits

Rahul Mohoto

Rahul Mohoto

9 projects • 19 followers
Hello there. Welcome to the realm of hardware and interfacing. Have been a microcontroller enthusiast since 2011.

Comments