//GPL Software
#include <avr/pgmspace.h>
/* Death
If an occupied cell has 0, 1, 4, 5, 6, 7, or 8 occupied neighbors, the organism dies (0, 1: of loneliness; 4 thru 8: of overcrowding).
Survival
If an occupied cell has two or three neighbors, the organism survives to the next generation.
Birth
If an unoccupied cell has three occupied neighbors, it becomes occupied.
7 0 1 how I'm referring to neighbors
6_\|/_
/|\ 2
5 4 3
*/
#define brightness 180 //middle button cycles through these brightness settings
#define contrast 15
//LCD Pins
#define DIPin 4 // register select RS
#define DB4Pin 7
#define DB5Pin 8
#define DB6Pin 12
#define DB7Pin 13
#define ContrastPin 6
#define EnablePin 5
#define BrightnessPin 9 //control with a transistor please if you use it
typedef void (* genericFx)(void);//type for function pointers
genericFx resetFunc = 0;
//LCD prototype
class LCD{
public:
LCD( ) ;
void gotoXY(byte x, byte y);
void print(char * string);
void init();
void tickleEnable();
void cmdWriteSet();
void LcdCommandWrite(byte value);
void LcdDataWrite(byte value);
byte pushNibble(byte value);
};
LCD lcd;
int powerUp = MCUSR &1; //did we reset or power up?
#define rows 6
#define columns 16
byte tmp [] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte display [] = {
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0
};
void loop (void){
lcd.init();
byte running=1;
while(running==1){
unsigned long loopStart=millis();
running=0;
// update the neighbor counts
for(int y = 0; y < rows; y++){
for(int x = 0; x < columns; x++)
tmp[y*columns+x]=getNeighborCount(display,x,y);
}
//display the array
for(int y = 0; y < rows; y+=3){
lcd.gotoXY(0,y/3);
for(int x = 0; x < columns; x++){
byte n1=display[y*columns+x];
byte n2=getNeighbor(display,x,y,4)*2;
byte n3=getNeighbor(display,x,y+1,4)*4;
lcd.LcdDataWrite(n1|n2|n3);
}
}
//see who lives and who dies
for(int y = 0; y < rows; y++){
for(int x = 0; x < columns; x++){
byte b = display[y*columns+x];
byte n = tmp[y*columns+x];
if(b==0){
if(n==3) {
display[y*columns+x] = 1; //birth
running=1;
}
}else{
if(n==2 || n==3)
display[y*columns+x] = 1; //survival
else {
display[y*columns+x] = 0; //death
running = 1;
}
}
}
}
}
lcd.gotoXY(0,0);
lcd.print("DONE");
delay(1500);
resetFunc(); //poor mans reset :)
}
byte getNeighborCount(byte a[], byte x, byte y){
byte c = 0;
for(byte d = 0;d < 8; d++)
if(getNeighbor(a,x,y,d) != 0)
c++;
return c;
}
byte getNeighbor(byte a[], byte x, byte y, byte dir){
byte nx=x;
byte ny=y;
if(dir == 7 || dir == 0 || dir == 1)
ny--;
if(dir == 3 || dir == 4 || dir == 5)
ny++;
if(dir == 5 || dir == 6 || dir == 7)
nx--;
if(dir == 1 || dir == 2 || dir == 3)
nx++;
if(nx==255) nx = columns - 1;
if(nx==columns) nx = 0;
if(ny==255) ny = rows - 1;
if(ny==rows) ny = 0;
return a[ny*columns+nx];
}
//get a string from flash
char mBuff[17];//used by getStr
char * getStr(prog_char * str){
strcpy_P(mBuff, str);
return mBuff;
}
//LCD functions
LCD::LCD(){
}
//x=0..16, y= 0..1
void LCD::gotoXY(byte x, byte y){
byte dr=x+0x80;
if (y==1)
dr += 0x40;
if (y==2)
dr += 0x14;
if (y==3)
dr += 0x54;
lcd.LcdCommandWrite(dr);
}
void LCD::print(char * string){
byte x = 0;
char c = string[x];
while(c != 0){
lcd.LcdDataWrite(c);
x++;
c = string[x];
}
}
//do the lcd initialization voodoo
void LCD::init(){
LcdCommandWrite(B00000010); // 4 bit operation
LcdCommandWrite(B00101000);// 4-bit interface, 2 display lines, 5x8 font
LcdCommandWrite(B00001100); // display control:
LcdCommandWrite(B00000110); // entry mode set: increment automatically, no display shift
//creating the custom fonts:
LcdCommandWrite(B01000000); // set cgram
static byte chars[] PROGMEM ={
B00000,B11111,B00000,B11111,B00000,B11111,B00000,B11111,
B00000,B11111,B00000,B11111,B00000,B11111,B00000,B11111,
B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000,
B00000,B00000,B11111,B11111,B00000,B00000,B11111,B11111,
B00000,B00000,B11111,B11111,B00000,B00000,B11111,B11111,
B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000,
B00000,B00000,B00000,B00000,B11111,B11111,B11111,B11111,
B00000,B00000,B00000,B00000,B11111,B11111,B11111,B11111};
for(byte x=0;x<8;x++)
for(byte y=0;y<8;y++)
LcdDataWrite(pgm_read_byte(&chars[y*8+x])); //write the character data to the character generator ram
LcdCommandWrite(B00000001); // clear display, set cursor position to zero
LcdCommandWrite(B10000000); // set dram to zero
}
void LCD::tickleEnable(){
// send a pulse to enable
digitalWrite(EnablePin,HIGH);
delayMicroseconds(1); // pause 1 ms according to datasheet
digitalWrite(EnablePin,LOW);
delayMicroseconds(1); // pause 1 ms according to datasheet
}
void LCD::cmdWriteSet(){
digitalWrite(EnablePin,LOW);
delayMicroseconds(1); // pause 1 ms according to datasheet
digitalWrite(DIPin,0);
}
byte LCD::pushNibble(byte value){
digitalWrite(DB7Pin, value & 128);
value <<= 1;
digitalWrite(DB6Pin, value & 128);
value <<= 1;
digitalWrite(DB5Pin, value & 128);
value <<= 1;
digitalWrite(DB4Pin, value & 128);
value <<= 1;
return value;
}
void LCD::LcdCommandWrite(byte value){
value=pushNibble(value);
cmdWriteSet();
tickleEnable();
value=pushNibble(value);
cmdWriteSet();
tickleEnable();
delay(1);
}
void LCD::LcdDataWrite(byte value){
digitalWrite(DIPin, HIGH);
value=pushNibble(value);
tickleEnable();
value=pushNibble(value);
tickleEnable();
delay(1);
}
void setup (void){
MCUSR=0;
Serial.begin(9600);
pinMode(BrightnessPin,OUTPUT);
analogWrite(BrightnessPin,255-brightness);
delay(500);
pinMode(EnablePin,OUTPUT);
pinMode(DIPin,OUTPUT);
pinMode(DB4Pin,OUTPUT);
pinMode(DB5Pin,OUTPUT);
pinMode(DB6Pin,OUTPUT);
pinMode(DB7Pin,OUTPUT);
delay(500);
if(powerUp)
lcd.init();
pinMode(ContrastPin,OUTPUT);
analogWrite(ContrastPin,contrast);
lcd.LcdCommandWrite(B00000001); // clear display, set cursor position to zero
lcd.LcdCommandWrite(B10000000); // set dram to zero
lcd.gotoXY(0,0);
lcd.print(getStr(PSTR("Game of Life")));
lcd.gotoXY(0,1);
lcd.print(getStr(PSTR(" mpguino style")));
delay(1500);
}