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();
}
}