Initial working version

This commit is contained in:
David Baranyai 2018-08-30 23:15:51 +02:00
commit 438b31085f
2 changed files with 341 additions and 0 deletions

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# Classic Snake game for the STM32 board
## Hardware prerequisities
* stm32duino (should work on generic Arduino boards)
* Philips PCD8544 (Nokia 3310) LCD
## Software prerequisities
* Arduino Software
* [Arduino Core for STM32](https://github.com/stm32duino/Arduino_Core_STM32)
* [Adafruit PCD8544 Library](https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library)
* [Adafruit GFX Library](https://github.com/adafruit/Adafruit-GFX-Library)
* [SimpleTimer Library for Arduino](https://playground.arduino.cc/Code/SimpleTimer#Download)
* [Standard C++ for Arduino](https://github.com/maniacbug/StandardCplusplus)
## Building and flashing
Just as with normal Arduino codes, build and flash it from the Arduino Software.
* Board: Generic STM32F103C series
* Variant: STM32F103C8 (20K RAM. 64K Flash)
* CPU Speed: 72MHz
## Note
If using a different board, then change the configuration and modify the pins accordingly.
For the STM32 board the following changes are necessary:
Adafruit_PCD8544.h:
```
#define PCD8544_SPI_CLOCK_DIV SPI_CLOCK_DIV4 -> #define PCD8544_SPI_CLOCK_DIV SPI_CLOCK_DIV8
```
```
#ifdef __SAM3X8E__
typedef volatile RwReg PortReg;
typedef uint8_t PortMask; -> typedef uint32_t PortMask;
#else
typedef volatile uint32_t PortReg;
typedef uint8_t PortMask; -> typedef uint32_t PortMask;
#endif
```

304
snake.ino Normal file
View File

@ -0,0 +1,304 @@
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <vector>
#include <SimpleTimer.h>
#define clk PB13
#define din PB15
#define dc PB14
#define cs PB12
#define rst PA15
// Software SPI (slower updates, more flexible pin options):
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(clk, din, dc, cs, rst);
//speed in ms
#define SPEED 250
SimpleTimer timer;
#define SNAKE_INIT_LENGTH 10 //Initial length of snake
#define SNAKE_START_X 42 //Initial x position
#define SNAKE_START_Y 20 //Initial y position
//Pin setup according to the board
#define left PA1
#define right PB8
#define up PA0
#define down PB9
#define center PC13
#define left_led PB6
#define right_led PB7
//Store the coordinates in a structure
struct coordinates
{
int x;
int y;
};
std::vector<coordinates> snake; //store the snake points
coordinates snake_last_piece; //store the last point | needed for visualisation
coordinates food; //food coordinates
bool leds = true; //for LED blink
int direction = 0;
int last_direction = 0;
int points = 0;
void setup() {
// put your setup code here, to run once:
//Serial port
Serial.begin(9600);
//Set inputs and outputs
pinMode(left, INPUT_PULLUP);
pinMode(right, INPUT_PULLUP);
pinMode(up, INPUT_PULLUP);
pinMode(down, INPUT_PULLUP);
pinMode(center, INPUT_PULLUP);
pinMode(left_led, OUTPUT);
pinMode(right_led, OUTPUT);
display.begin();
display.setContrast(63);
display.display(); //show splashscreen
delay(2000);
display.clearDisplay();
init_game();
timer.setInterval(SPEED, TimerCallbackFunc); //Timer for moving the snake
}
void init_game()
{
/*
* This function initializes the snake, clears the points and direction, and generate a new food.
* Can be used to reset the game.
*/
//init the snake
direction = 0;
points = 0;
snake.clear(); //clear the vector
for(int i = 0; i < SNAKE_INIT_LENGTH; i++)
{
coordinates helper;
helper.x = SNAKE_START_X - i;
helper.y = SNAKE_START_Y;
snake.push_back(helper);
}
snake_last_piece.x = 0;
snake_last_piece.y = 0;
generate_food();
}
void TimerCallbackFunc()
{
//blinks the 2 LED
digitalWrite(left_led, leds);
digitalWrite(right_led, !leds);
leds = !leds;
//Moving in the given direction
snake_move(direction);
}
void generate_food()
{
/*
* Generates random x and y points until it's out of the snake's points.
*/
bool equal = true;
while(equal)
{
equal = false;
food.x = random(0, 83);
food.y = random(0,47);
for(int i = 0; i < snake.size(); i++)
{
if(snake[0].x == food.x && snake[0].y == food.y)
{
equal = true;
}
}
}
display.drawPixel(food.x, food.y, BLACK);
display.display();
}
void draw_snake()
{
/*
* Draw the snake points.
*/
for(int i = 0; i < snake.size(); i++)
{
display.drawPixel(snake[i].x, snake[i].y, BLACK);
}
display.drawPixel(snake_last_piece.x, snake_last_piece.y, WHITE);
display.display();
}
bool check_crash()
{
/*
* Returns true if the snake crashing into itself.
*/
for(int i = 1; i < snake.size(); i++)
{
if(snake[0].x == snake[i].x && snake[0].y == snake[i].y)
{
return true;
}
}
return false;
}
void snake_move(int direction)
{
/*
* Handling the moving directions and next points.
*/
last_direction = direction;
snake_last_piece.x = snake[snake.size()-1].x;
snake_last_piece.y = snake[snake.size()-1].y;
coordinates helper;
if(direction == 0) //right
{
helper = snake[0];
helper.x++;
if(helper.x > 83)
{
helper.x = 0;
}
}
else if(direction == 1) //left
{
helper = snake[0];
helper.x--;
if(helper.x < 0)
{
helper.x = 83;
}
}
else if(direction == 2) //up
{
helper = snake[0];
helper.y--;
if(helper.y < 0)
{
helper.y = 47;
}
}
else if(direction == 3) //down
{
helper = snake[0];
helper.y++;
if(helper.y > 47)
{
helper.y = 0;
}
}
//move forward every coordinate and replace the first with the new one
for(int i = snake.size(); i > 0; i--)
{
snake[i] = snake [i-1];
}
snake[0] = helper;
draw_snake();
//if the snake ate the food, then increment by one and generate a new one
if(snake[0].x == food.x && snake[0].y == food.y)
{
increment_snake();
generate_food();
}
}
void increment_snake()
{
snake.push_back(snake[snake.size()]);
points++;
}
void loop() {
// put your main code here, to run repeatedly:
timer.run();
if(digitalRead(left) == 0)
{
Serial.print("Left button pressed");
if(last_direction != 0)
{
direction = 1;
}
}
if(digitalRead(right) == 0)
{
Serial.print("Right button pressed");
if(last_direction != 1)
{
direction = 0;
}
}
if(digitalRead(up) == 0)
{
Serial.print("Up button pressed");
if(last_direction != 3)
{
direction = 2;
}
}
if(digitalRead(down) == 0)
{
Serial.print("Down button pressed");
if(last_direction != 2)
{
direction = 3;
}
}
if(digitalRead(center) == 0)
{
Serial.print("Center button pressed");
display.drawPixel(food.x, food.y, BLACK);
display.display();
}
if(check_crash())
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0,0);
display.println("Game over!");
//display.setCursor(0,10);
display.println("Score: ");
display.print(points, DEC);
display.display();
while(digitalRead(center) != 0)
{
}
display.clearDisplay();
init_game();
}
}