Friday, November 2, 2012
PIC18F4550 Snake Game on 128x64 GLCD v2
much better graphics :) enjoy!
source code: (PIC18F4550, CCS C)
file kbd.h:
#define keyUp PIN_B2
#define keyDown PIN_B3
#define keyLeft PIN_B4
#define keyRight PIN_B5
#define keyA PIN_B6
#define keyB PIN_B7
#define keyUpPressed !input(keyUp)
#define keyDownPressed !input(keyDown)
#define keyLeftPressed !input(keyLeft)
#define keyRightPressed !input(keyRight)
#define keyAPressed !input(keyA)
#define keyBPressed !input(keyB)
file glcd.c:
#ifndef GLCD_C
#define GLCD_C
#define ON 1
#define OFF 0
#define YES 1
#define NO 0
// GLCD PIN CONFIGURATION:
#bit GLCD_CS1 = porte.1
#bit GLCD_CS2 = porte.2
#bit GLCD_DI = portc.0
#bit GLCD_RW = porte.0
#bit GLCD_E = portc.1
#byte GLCD_DATA = portd
#bit tris_GLCD_CS1 = trise.1
#bit tris_GLCD_CS2 = trise.2
#bit tris_GLCD_DI = trisc.0
#bit tris_GLCD_RW = trise.0
#bit tris_GLCD_E = trisc.1
#byte tris_GLCD_DATA = trisd
////////////////////////////
// IO functions:
void glcdPulseE() {
GLCD_E = 1;
delay_us(10); // for more speed improve the data bus to glcd
GLCD_E = 0;
}
void glcdWrite1(unsigned int8 data) {
GLCD_CS1 = 1;
GLCD_RW = 0; // R/W = Write
GLCD_DATA = data;
tris_GLCD_DATA = 0;
GLCD_DATA = data;
glcdPulseE();
GLCD_CS1 = 0;
}
void glcdWrite2(unsigned int8 data) {
GLCD_CS2 = 1;
GLCD_RW = 0; // R/W = Write
GLCD_DATA = data;
tris_GLCD_DATA = 0;
GLCD_DATA = data;
glcdPulseE();
GLCD_CS2 = 0;
}
unsigned int8 glcdRead1() {
unsigned int8 data;
GLCD_CS1 = 1;
tris_GLCD_DATA = 0xFF; // input
GLCD_RW = 1; // R/W = Read
GLCD_E = 1;
delay_us(10);
GLCD_E = 0;
delay_us(10);
GLCD_E = 1;
delay_us(10);
data = GLCD_DATA;
GLCD_E = 0;
GLCD_CS1 = 0;
return data;
}
unsigned int8 glcdRead2() {
unsigned int8 data;
GLCD_CS2 = 1;
tris_GLCD_DATA = 0xFF; // input
GLCD_RW = 1; // R/W = Read
GLCD_E = 1;
delay_us(10);
GLCD_E = 0;
delay_us(10);
GLCD_E = 1;
delay_us(10);
data = GLCD_DATA;
GLCD_E = 0;
GLCD_CS2 = 0;
return data;
}
/////////////////////////////////////////
void glcdFillScreen(unsigned int8 color) {
int x, y;
if(color!=0) color = 0xFF;
for(x=0; x<8; x++) { // for all 8 rows of the glcd
GLCD_DI = 0; // D/I = Instruction
glcdWrite1(0b01000000); // start of the row
glcdWrite2(0b01000000);
glcdWrite1(x | 0b10111000); // Set row
glcdWrite2(x | 0b10111000);
GLCD_DI = 1; // D/I = Data
for(y=0; y<64; y++) { // fill columns of the row with pixels
glcdWrite1(color);
glcdWrite2(color);
}
}
}
void glcdInit(int1 active) { // 1 = on, 0 = off
GLCD_E = 0;
tris_GLCD_E = 0;
GLCD_E = 0;
GLCD_CS1 = 0;
tris_GLCD_CS1 = 0;
GLCD_CS1 = 0;
GLCD_CS2 = 0;
tris_GLCD_CS2 = 0;
GLCD_CS2 = 0;
GLCD_DI = 0;
tris_GLCD_DI = 0;
GLCD_DI = 0; // D/I = Instruction
GLCD_RW = 0;
tris_GLCD_RW = 0;
GLCD_RW = 0; // R/W = Write
glcdWrite1(0xC0);
glcdWrite2(0xC0);
glcdWrite1(0x40);
glcdWrite2(0x40);
glcdWrite1(0xB8);
glcdWrite2(0xB8);
glcdWrite1(0x3E + active); // turn on or off
glcdWrite2(0x3E + active);
glcdFillScreen(OFF);
}
void glcdClear() {
glcdFillScreen(OFF);
}
#endif
file main.c:
#include "18F4550.h"
#DEVICE PASS_STRINGS = IN_RAM
#fuses HSPLL, PLL5, CPUDIV1, NOWDT, NOPROTECT, PUT, BORV43, NOLVP, NOMCLR, USBDIV, VREGEN, WRT=14, WRTB
#use delay(clock=48000000)
#zero_ram
#byte porta = 0xF80
#byte portb = 0xF81
#byte portc = 0xF82
#byte portd = 0xF83
#byte porte = 0xF84
#byte trisa = 0xF92
#byte trisb = 0xF93
#byte trisc = 0xF94
#byte trisd = 0xF95
#byte trise = 0xF96
#byte ucon = 0xF6D
#bit usben = ucon.3
#byte ucfg = 0xF6F
#bit utrdis = ucfg.3
#include "kbd.h"
#include "glcd.c"
void cpu_init() {
usben = 0;
utrdis = 1;
setup_comparator(NC_NC_NC_NC);
SETUP_ADC_PORTS(NO_ANALOGS);
SETUP_ADC(ADC_OFF);
port_b_pullups(true);
}
unsigned int32 _Randseed;
unsigned int16 rand(void) {
_Randseed = _Randseed * 1103515245 + 12345;
return ((unsigned int16)(_Randseed >> 16) );
}
void srand(unsigned int32 seed) {
_Randseed = seed;
}
#define CODE_EMPTY '.'
#define CODE_FOOD 3
#define CODE_SNAKE 219
#define OFFSET_FOOD 0
#define OFFSET_SNVE 8
#define OFFSET_SNHO 16
#define OFFSET_SNDL 24
#define OFFSET_SNUL 32
#define OFFSET_SNUR 40
#define OFFSET_SNDR 48
#define OFFSET_SNHU 56
#define OFFSET_SNHR 64
#define OFFSET_SNHD 72
#define OFFSET_SNHL 80
#define OFFSET_SNTU 88
#define OFFSET_SNTR 96
#define OFFSET_SNTD 104
#define OFFSET_SNTL 112
const unsigned int8 BITMAP[] = {0b00011110, // food
0b00100001,
0b01000001,
0b10000010,
0b10000010,
0b01000001,
0b00100001,
0b00011110,
0b00000000, // snake_vertical
0b00000000,
0b11101110,
0b11101110,
0b01110111,
0b01110111,
0b00000000,
0b00000000,
0b00001100, // snake_horizontal
0b00111100,
0b00111100,
0b00110000,
0b00001100,
0b00111100,
0b00111100,
0b00110000,
0b00001100, // snake_down_left
0b00111100,
0b11111100,
0b11101000,
0b01111000,
0b01100000,
0b00000000,
0b00000000,
0b00001100, // snake_up_left
0b00111100,
0b00111110,
0b00010110,
0b00011111,
0b00000111,
0b00000000,
0b00000000,
0b00000000, // snake_up_right
0b00000000,
0b00000110,
0b00011110,
0b00010111,
0b00111111,
0b00111100,
0b00110000,
0b00000000, // snake_down_right
0b00000000,
0b11100000,
0b11111000,
0b01101000,
0b01111100,
0b00111100,
0b00110000,
0b00000000, // snake_head_up // link up, head looks down
0b01110000,
0b10011110,
0b11111110,
0b11111111,
0b10011111,
0b01110000,
0b00000000,
0b00111100, // snake_head_right // link right
0b01011010,
0b01011010,
0b01111110,
0b00111100,
0b00111100,
0b00111100,
0b00110000,
0b00000000, // snake_head_down // link down
0b00001110,
0b11111001,
0b11111111,
0b01111111,
0b01111001,
0b00001110,
0b00000000,
0b00001100, // snake_head_left // link left
0b00111100,
0b00111100,
0b00111100,
0b01111110,
0b01011010,
0b01011010,
0b00111100,
0b00000000, // snake_tail_up // link up
0b00000000,
0b00101110,
0b11101110,
0b11110111,
0b00110111,
0b00000000,
0b00000000,
0b00011000, // snake_tail_right // link right
0b00011000,
0b00111100,
0b00110000,
0b00001100,
0b00111100,
0b00111100,
0b00110000,
0b00000000, // snake_tail_down // link down
0b00000000,
0b11101100,
0b11101111,
0b01110111,
0b01110100,
0b00000000,
0b00000000,
0b00001100, // snake_tail_left // link left
0b00111100,
0b00111100,
0b00110000,
0b00001100,
0b00111100,
0b00011000,
0b00011000};
unsigned int8 arena[16][8]; // x, y
int snakeDir = 1;
unsigned int8 snakeX[100];
unsigned int8 snakeY[100];
unsigned int8 snakeLen = 3;
unsigned int8 snakeBitmapOffset(unsigned int8 x, unsigned int8 y) {
unsigned int8 i;
i = 0;
while(true) {
if(snakeX[i]==x && snakeY[i]==y) break;
i++;
}
if(i==0) {
if(snakeX[i+1]==x+1) return OFFSET_SNHR;
if(snakeX[i+1]==x-1) return OFFSET_SNHL;
if(snakeY[i+1]==y+1) return OFFSET_SNHD;
if(snakeY[i+1]==y-1) return OFFSET_SNHU;
}
if(i==snakeLen-1) {
if(snakeX[i-1]==x+1) return OFFSET_SNTR;
if(snakeX[i-1]==x-1) return OFFSET_SNTL;
if(snakeY[i-1]==y+1) return OFFSET_SNTD;
if(snakeY[i-1]==y-1) return OFFSET_SNTU;
}
if(snakeX[i+1]==x && snakeX[i-1]==x) return OFFSET_SNVE;
if(snakeY[i+1]==y && snakeY[i-1]==y) return OFFSET_SNHO;
if(snakeX[i+1]==x+1 && snakeY[i-1]==y+1) return OFFSET_SNDR;
if(snakeX[i-1]==x+1 && snakeY[i+1]==y+1) return OFFSET_SNDR;
if(snakeX[i+1]==x-1 && snakeY[i-1]==y+1) return OFFSET_SNDL;
if(snakeX[i-1]==x-1 && snakeY[i+1]==y+1) return OFFSET_SNDL;
if(snakeX[i+1]==x+1 && snakeY[i-1]==y-1) return OFFSET_SNUR;
if(snakeX[i-1]==x+1 && snakeY[i+1]==y-1) return OFFSET_SNUR;
if(snakeX[i+1]==x-1 && snakeY[i-1]==y-1) return OFFSET_SNUL;
if(snakeX[i-1]==x-1 && snakeY[i+1]==y-1) return OFFSET_SNUL;
return OFFSET_SNVE;
}
void glcdUpdate() {
unsigned int8 x, y, code, i;
unsigned int8 bitmapOffset;
for(y = 0; y < 8; y++) {
GLCD_DI = 0;
glcdWrite1(0b01000000);
glcdWrite2(0b01000000);
glcdWrite1(y | 0b10111000);
glcdWrite2(y | 0b10111000);
GLCD_DI = 1;
for(x=0; x<16; x++) {
code = arena[x][y];
if(code==CODE_SNAKE) {
bitmapOffset = snakeBitmapOffset(x, y);
if(x<8)
for(i=0; i<8; i++)
glcdWrite1(BITMAP[bitmapOffset+i]);
else
for(i=0; i<8; i++)
glcdWrite2(BITMAP[bitmapOffset+i]);
}/////////////////////////
if(code==CODE_EMPTY) {
if(x<8)
for(i=0; i<8; i++)
glcdWrite1(0x00);
else
for(i=0; i<8; i++)
glcdWrite2(0x00);
}/////////////////////////
if(code==CODE_FOOD) {
if(x<8)
for(i=0; i<8; i++)
glcdWrite1(BITMAP[OFFSET_FOOD+i]);
else
for(i=0; i<8; i++)
glcdWrite2(BITMAP[OFFSET_FOOD+i]);
}/////////////////////////
}
}
}
unsigned int8 score = 0;
void arena_clear() {
int x, y;
for(x=0; x<16; x++)
for(y=0; y<8; y++)
arena[x][y] = CODE_EMPTY;
}
void put_food() {
unsigned int8 x, y;
while(true) {
x = rand() % 16;
y = rand() % 8;
if(arena[x][y]!=CODE_SNAKE) {
arena[x][y] = CODE_FOOD;
break;
}
}
}
unsigned int8 move_snake() {
signed int8 tail_x, tail_y, head_x, head_y;
unsigned int8 i;
tail_x = snakeX[snakeLen-1];
tail_y = snakeY[snakeLen-1];
for(i=snakeLen-1; i>0; i--) {
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
head_x = snakeX[0];
head_y = snakeY[0];
switch(snakeDir) {
case 0: head_y--; break;
case 1: head_x++; break;
case 2: head_y++; break;
case 3: head_x--; break;
}
snakeX[0] = head_x;
snakeY[0] = head_y;
if(head_x < 0)
return -1;
if(head_y < 0)
return -1;
if(head_x >= 16)
return -1;
if(head_y >= 8)
return -1;
if(arena[head_x][head_y] != CODE_FOOD) { // nothing eaten
arena[tail_x][tail_y] = CODE_EMPTY; // cut tail
}
if(arena[head_x][head_y] == CODE_FOOD) {
snakeX[snakeLen] = tail_x;
snakeY[snakeLen] = tail_y;
snakeLen++;
arena[head_x][head_y] = CODE_SNAKE; // add head
return 2;
}
arena[head_x][head_y] = CODE_SNAKE; // add head
return 0;
}
int1 refreshSnakeDir() {
unsigned int8 oldDir;
oldDir = snakeDir;
if(keyUpPressed) snakeDir = 0;
if(keyRightPressed) snakeDir = 1;
if(keyDownPressed) snakeDir = 2;
if(keyLeftPressed) snakeDir = 3;
if(oldDir!=snakeDir)
return 1;
else
return 0;
}
void main() {
unsigned int8 i;
unsigned int8 res;
unsigned int1 dirChanged;
cpu_init();
delay_ms(100);
glcdInit(ON);
arena_clear();
snakeY[0] = 0;
snakeY[1] = 0;
snakeY[2] = 0;
snakeX[0] = 2;
snakeX[1] = 1;
snakeX[2] = 0;
arena[0][0] = CODE_SNAKE;
arena[1][0] = CODE_SNAKE;
arena[2][0] = CODE_SNAKE;
put_food();
glcdUpdate();
while(true) {
for(i=0; i<4; i++) {
dirChanged = refreshSnakeDir();
delay_ms(20);
dirChanged |= refreshSnakeDir();
delay_ms(20);
dirChanged |= refreshSnakeDir();
delay_ms(20);
dirChanged |= refreshSnakeDir();
delay_ms(20);
dirChanged |= refreshSnakeDir();
if( dirChanged || keyBPressed || keyAPressed )
break;
}
if(keyBPressed) {
delay_ms(20);
while(keyBPressed)
delay_ms(10);
while(!keyBPressed)
delay_ms(10);
while(keyBPressed)
delay_ms(10);
}
refreshSnakeDir();
res = move_snake();
if(res==2) {
score++;
put_food();
}
if(res==-1) {
glcdClear();
//glcdPutc("Game Over\r\nscore = ");
//glcdPutn(score);
delay_ms(1000);
reset_cpu();
}
glcdUpdate();
}
}
Subscribe to:
Post Comments (Atom)
can u send the working code on easypic6 kit..plz ireally need it urgent thnkx in advance
ReplyDeleteGreat Work, I "translated" it for Arduino Uno and modified it a bit (put an external one pixel width wall, menus, difficulties). Now I'm trying to make it for avr mcu in general
ReplyDeletedear sir
Deletecan you please send me working code for avr microcontroller
Awesome. Thanks for codes.
ReplyDeletecan you send the circuit diagram?
ReplyDelete