Falls du dein altes Nokia Handy vermisst, kannst du dir mit Hilfe dieses Tutorials dein altes Lieblingsgame, Snake, ganz einfach mit einem Arduino nachbauen.
Snake ist den Meisten als eines der beliebtesten Handyspieler aller Zeiten bekannt und war in den 2000ern auf jedem Nokia Handy vorinstalliert. So konnten sich Millionen Jugendliche, zu denen du eventuell auch gehört hast, die Langeweile vertreiben. 2017 hat Nokia das 3310 wiederaufleben lassen und Snake wiederfuhr eine Neuauflage. Diese konnte allerdings nicht mit dem 2000 auf dem Nokia 3210 herausgekommenen Original mithalten.
Snake war jedoch nicht nur ein Handyspiel, sondern existierte schon deutlich früher. Die erste Version existierte schon 1979 und hieß „Hyper-Wurm“. Dieses Spiel lief auf dem TRS-80, einem der ersten Seriencomputern der Welt. Jetzt bist du an der Reihe das Spiel nachzubauen.
Dazu brauchst du nur ein paar Teile aus unserem Shop!
Folgende Hardware benötigst du für das Snake Arduino Projekt
- Arduino Uno, Mega oder Nano
- 8 x 8 LED Matrix 2088BS
- 2 ShiftRegister 74HC595
- 8 BC547 NPN Transistoren
- 16 Widerstände (330 Ohm bis 1000 Ohm)
- Jumper Kabel Female/Female
- Lochrasterplatine
- Lötstation
- Breadboard
- Joystick
- Arduino IDE
- Arduino Library für ShiftRegister 74HC595
Alle für dieses Projekt notwendigen Artikel landen mit einem Klick auf den Button direkt in deinem Warenkorb, sofern sie in unserem Shop verfügbar sind. Kontrolliere daher deinen Warenkorb genau!
Was ist ein Schieberegister?
Das wohl wichtigste Bauteil für dieses Projekt ist das Schieberegister 74HC595. Dieser integrierte Schaltkreis ermöglicht es uns die Ausgabekanäle der Arduino-Boards fast beliebig zu erweitern. Dies kommt uns bei diesem Projekt zugute, da wir deutlich mehr Ausgabekanäle benötigen, um die LED-Matrix anzusteuern.
Ein Schieberegister funktioniert folgendermaßen. Serielle Daten werden in parallele Daten umgewandelt. Das bedeutet, die Sequenz An-An-Aus-An-An-An-Aus-An (also 11011101) wird an das Schieberegister gesendet, welches diese Daten an seine eigenen Output-Pins (von 1 bis 8) schickt. Es schaltet also seinen Pin1 an, Pin2 auch, Pin 3 aus … und so weiter. Diese Pins bleiben in ihrem Zustand, bis über den Daten-In-Pin des Schieberegister neue Informationen ankommen.
Das Schieberegister erhält die seriell gesendeten Daten über den DS Pin. Damit es die einzelnen Daten unterscheiden kann, wird gleichzeitig über den Shift Register Clock Pin (SHCP) eine Art Herzschlag gesendet. Als letztes benötigt das 74HC595 noch eine Reset-Verbindung zum Arduino-Board. Es werden somit nur drei digitale Outputs vom Arduino genutzt.
Interessanter Weise lassen sich mehrere Schieberegister wie in einer Reihenschaltung hintereinanderschalten. Dadurch erhöht sich die Anzahl möglicher Outputs, ohne dass mehr Arduino-Pins verwendet werden müssen.
Weitere Informationen über Schieberegister kannst du dem Datenblatt entnehmen.
So baust du dir dein Arduino Snake-Game
Als allerersten Schritt musst du dir die Arduino IDE auf deinem Computer installieren. Diese findest du hier.
Leider sind nicht alle Bibliotheken standardmäßig in der Arduino IDE verfügbar, aus diesem Grund musst du dir zunächst die „SchiftRegister74HC595“ Bibliothek herunterladen und in die Arduino IDE einbinden.
Unter Linux kannst du dir die Library einfach mit dem folgenden Terminalbefehl herunterladen:
git clone https://github.com/Simsso/ShiftRegister74HC595.git
Solltest du Windows nutzen folge diesem Link. Klicke dann auf „Code“ und „Download Zip“.
Die soeben von dir heruntergeladene Bibliothek wird nun in die Arduino IDE eingebunden. Dazu folge dem folgenden Pfad: Arduino IDE> Sketch> Bibliothek einbinden> ZIP Bibliothek hinzufügen.
So bekommst du den Code auf deinen Arduino
Damit Snake auf deinem Arduino läuft musst du den folgenden C++ Code in die Arduino IDE abtippen oder kopieren.
// https://www.blog.berrybase.de/
// SNAKE GAME on 8x8 LED matrix with Arduino and 2 74HC595 shift register.
// Pin connected to Pin 12 of 74HC595 (Latch)
int latchPin = 11;
// Pin connected to Pin 11 of 74HC595 (Clock)
int clockPin = 10;
// Pin connected to Pin 14 of 74HC595 (Data)
int dataPin = 12;
// Screen
byte led[8];
////////////////////////////
int X= A0; // X Axe
int Y= A1; // Y Axe
///////////////////////////
// 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() //Pins Setup
{
pinMode(X, INPUT);
pinMode(Y, INPUT);
// set pins to output
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
// set button pins to input
Serial.begin(9600);
// clear screen
clrscr();
}
//////////////////////////
void loop() //Hauptprogramm
{
snakeInit(); //Snake Intialisierung
screenUpdate();
oldTimer = millis();
curTimer = millis();
while(!dead)
{
curTimer = millis();
setDirection();
if(curTimer-oldTimer >= 320) {
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) //Snake Kopf hinzufügen
{
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() //Snake INIT
{
int x = 3;
int y = 3;
for (int i=0; i<2; i++, x++) {
addHead(x,y);
if (i == 0)
pTail = pHead;
}
}
//////////////////////////
void setDirection() //Richtung
{
if(analogRead(Y)>600) {
if(curDirection!=2)
newDirection = 1;
}
if(analogRead(Y)<400) {
if(curDirection!=1)
newDirection = 2;
}
if(analogRead(X)>600) {
if(curDirection!=4)
newDirection = 3;
}
if(analogRead(X)<400) {
if(curDirection!=3)
newDirection = 4;
}
}
//////////////////////////
void moveSnake(int direction) //Snake Bewegung
{
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() //Neuer Apfel setzen
{
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) //Prüfen
{
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() //Screen Aktualisierung
{
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() //Show Screen
{
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() //Clear Screen
{
for(int i=0; i<8; i++) {
led[i] = B00000000;
}
}
//////////////////////////
void shiftData(byte data) //Start Schifting
{
// 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);
}
Um den Code auf deinen Arduino zu laden, musst du zunächst in der Arduino IDE deinen Arduino auswählen, damit die IDE weiß mit welchem Board dein Computer verbunden ist. Nun kannst du deinen Arduino mit deinem Computer unter Zuhilfenahme des USB-Kabels verbinden. Den Code lädst du auf deinen Arduino mit Hilfe des Pfeils links – oben in der Ecke. Eine Ausführliche Anleitung kannst du dir auch hier bei YouTube ansehen.
So baust du die Schaltung auf
Damit du Snake spielen kannst musst du nicht nur den Code auf den Arduino laden, sondern auch alle Bauteile miteinander verbinden.
Der Schaltplan sieht auf den ersten Blick etwas komplex aus. Im Grunde werden aber nur die drei erwähnten digitalen Outputs vom Arduino- Board mit dem Schieberegister 74HC595 verbunden. Darüber hinaus wird der Chip mit GND und 5V+ verbunden.
Wichtig! Der Clock Pin des Schieberegisters (SHCP) muss über einen 100nF Keramikkondensator (Aufdruck 104) mit dem GND verbunden werden!
Die Pins der Matrix werden sowohl mit dem Schieberegister aus auch mit den Transistoren in folgender Weise verbunden:
Matrix:
Pins : 13 , 3 , 4 , 10 , 6 , 11 ,15 , 16 (Matrix Rows(-ve)) → (BC547)
Pins : 9 , 14 , 8 , 12 , 1 , 7 , 2 , 5 (Matrix Col(+ve)) → (74HC595)
Nun must du noch den Joystick in deine Schaltung einbinden. Auf dem Schaltplan sieht das Ganze folgendermaßen aus:
Wie du sehen kannst wurden die Pins des Jopysticks auf die folgende Weise mit deinem Arduino verbunden:
Joystick Arduino
GND → GND
+5v → 5v
VRx → A0 (X Axe)
VRy → A1 (Y Axe)
SW → RESET
Jetzt ist dein Snake-Game fertig und du kannst spielen!
Jetzt hast du sowohl den Code auf deinen Arduino geladen als auch die Schaltung nachgebaut und du bist bereit zum Spielen. Das Spiel startet einfach nachdem du den Joystick bewegt hast.
Alle Teile für dieses Projekt kannst du in unserem Shop finden. Stöbere doch einfach ein bisschen durch unser Sortiment!
Da es wahrscheinlich eine Ewigkeit her ist, dass du Snake spielen konntest lassen wir dich nun direkt in Ruhe und wünschen dir viel Spaß beim Spielen.
Dein BerryBase-Team!
Du willst mehr heiße Arduino Projekte? Schaue dir jetzt hier unsere Sammlung an Tutorials an!