469 lines
8.1 KiB
C++
469 lines
8.1 KiB
C++
#include <Arduino.h>
|
|
|
|
/*
|
|
for cheap Chinese 64 dots LED-Projector
|
|
|
|
Board has unmarked chip in socket - pin layout fits to ATTiny 2313 an 4313
|
|
the LEDS are connected to 8 pcs 74HC595
|
|
|
|
|
|
--u--
|
|
RST 1 20 VCC
|
|
NC (0) 2 19 (16) IN SCK
|
|
NC (1) 3 18 (15) IN MISO
|
|
XTAL 4 17 (14) IN MOSI
|
|
XTAL 5 16 (13) IN
|
|
OUT (4) 6 15 (12) IN
|
|
OUT (5) 7 14 (11) IN
|
|
OUT (6) 8 13 (10) IN
|
|
NC (7) 9 12 (9) MIC
|
|
GND 10 11 (8) IN
|
|
-----
|
|
|
|
() = Arduino Pins
|
|
RST = Reset - 10K to GND, 10uF to VCC
|
|
XTAL = 16 MHz Crystal
|
|
IN = switches
|
|
MIC = Input from microphone amplifier (LM358)
|
|
*/
|
|
|
|
/*
|
|
x
|
|
XXXXXXX
|
|
XX XXX XX
|
|
XXXXXXXXXXX
|
|
X XXXXXXX X
|
|
X X X X
|
|
XX XX
|
|
*/
|
|
|
|
|
|
#define LATCHPIN 5
|
|
#define DATAPIN 4
|
|
#define CLOCKPIN 6
|
|
byte ledsData[8];
|
|
|
|
byte currentled = 0;
|
|
|
|
int stepcount = 0;
|
|
|
|
|
|
// low level functions
|
|
|
|
void clear() {
|
|
for (int i=0; i < 8; i++) {
|
|
// low is led on
|
|
ledsData[i] = 255;
|
|
}
|
|
}
|
|
|
|
void writebuffer(byte ledNr) {
|
|
byte chipNr = ledNr / 8;
|
|
byte pinNr = ledNr % 8;
|
|
if(chipNr < 8) {
|
|
bitWrite(ledsData[chipNr], pinNr, LOW);
|
|
}
|
|
}
|
|
|
|
void writexy(byte x, byte y) {
|
|
byte lednr = x*8 + y;
|
|
writebuffer(lednr);
|
|
}
|
|
|
|
byte rowmask[8] = {5,3,1,0,2,4,6,7};
|
|
void pushout() {
|
|
digitalWrite(LATCHPIN, LOW);
|
|
for(int i = 8-1; i>=0; i--) {
|
|
byte row = rowmask[i];
|
|
shiftOut(DATAPIN, CLOCKPIN, MSBFIRST, ledsData[row]);
|
|
}
|
|
digitalWrite(LATCHPIN, HIGH);
|
|
}
|
|
|
|
// space invader
|
|
|
|
//byte invaderA0[11] = {112,24,125,182,188,60,188,182,125,24,112};
|
|
//byte invaderA1[11] = {14,24,189,118,60,60,60,118,189,24,14};
|
|
|
|
static byte invader_A0[8] = {152,92,182,95,95,182,92,152};
|
|
static byte invader_A1[8] = {88,188,22,63,63,22,188,88};
|
|
|
|
bool invader_read(int x, int y, bool invader_state) {
|
|
if (invader_state) {
|
|
return bitRead(invader_A0[x],y);
|
|
} else {
|
|
return bitRead(invader_A1[x],y);
|
|
}
|
|
}
|
|
|
|
void invader_draw(int xposition, int yposition, bool invaderstate) {
|
|
for (int x=0; x<8; x++) {
|
|
int screenx = x+xposition;
|
|
if (screenx >=0 && screenx < 8) {
|
|
for (int y=0; y<8; y++) {
|
|
int screeny = y+yposition;
|
|
if (screeny >=0 && screeny < 8) {
|
|
if ( invader_read(x,y,invaderstate) ) {
|
|
writexy(screenx,screeny);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
byte invader_currentcol=1;
|
|
bool invader_direction = true;
|
|
|
|
int invader_start = -12;
|
|
int invader_end = 8;
|
|
int invader_position = invader_start;
|
|
bool invader_state = true;
|
|
|
|
int invader_statecount = 0;
|
|
|
|
void invader_setup() {
|
|
invader_state = true;
|
|
stepcount = 0;
|
|
invader_statecount = 0;
|
|
}
|
|
|
|
void invader_step() {
|
|
invader_draw(0,0, invader_state);
|
|
|
|
pushout();
|
|
|
|
invader_state = !invader_state;
|
|
stepcount++;
|
|
invader_statecount++;
|
|
|
|
if (invader_statecount >=4) {
|
|
invader_position++;
|
|
if (invader_position >=invader_end) {
|
|
invader_position = invader_start;
|
|
}
|
|
invader_statecount = 0;
|
|
}
|
|
delay(600);
|
|
}
|
|
|
|
|
|
// Game of life
|
|
|
|
byte gol_last[8];
|
|
byte gol_next[8];
|
|
byte gol_last2[8];
|
|
byte gol_last3[8];
|
|
byte gol_last4[8];
|
|
|
|
long gol_stepcount;
|
|
int gol_deadcount = 0;
|
|
|
|
void gol_setup() {
|
|
gol_deadcount = 0;
|
|
for (int x=0; x<8; x++) {
|
|
gol_last[x] = 0;
|
|
for (int y=0; y<8; y++) {
|
|
if (random(4)<1) {
|
|
bitWrite(gol_last[x], y, HIGH);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static byte gol_glider[8] = {4,5,6,0,0,0,0,0};
|
|
void gol_setup_glider() {
|
|
gol_deadcount = 0;
|
|
for (int i=0; i<8; i++) {
|
|
gol_last[i] = gol_glider[i];
|
|
}
|
|
}
|
|
|
|
static byte gol_spaceship[8] = {12,28,26,14,4,0,0,0};
|
|
void gol_setup_spaceship() {
|
|
gol_deadcount = 0;
|
|
for (int i=0; i<8; i++) {
|
|
gol_last[i] = gol_spaceship[i];
|
|
}
|
|
}
|
|
|
|
void setup() {
|
|
pinMode(LATCHPIN, OUTPUT);
|
|
pinMode(DATAPIN, OUTPUT);
|
|
pinMode(CLOCKPIN, OUTPUT);
|
|
|
|
gol_setup();
|
|
clear();
|
|
pushout();
|
|
}
|
|
|
|
void gol_clearnext() {
|
|
for (int i=0; i<8; i++) {
|
|
gol_next[i] = 0;
|
|
}
|
|
}
|
|
|
|
bool gol_getstate(int x, int y) {
|
|
// warp around
|
|
if (x<0) {
|
|
x=7;
|
|
}
|
|
if (x>7) {
|
|
x=0;
|
|
}
|
|
if (y<0) {
|
|
y=7;
|
|
}
|
|
if (y>7) {
|
|
y=0;
|
|
}
|
|
return bitRead(gol_last[x],y);
|
|
}
|
|
|
|
byte gol_countNeighbours(int x, int y) {
|
|
byte count = 0;
|
|
for (int xoff=-1; xoff <= 1; xoff++) {
|
|
for (int yoff=-1; yoff <= 1; yoff++) {
|
|
if ( !(xoff==0 && yoff==0) ) {
|
|
if (gol_getstate(x+xoff, y+yoff) ) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void gol_setnext(int x, int y) {
|
|
bitWrite( gol_next[x], y, HIGH);
|
|
}
|
|
|
|
void gol_writeLEDS() {
|
|
for(int x=0; x<8; x++) {
|
|
for (int y=0; y<8; y++) {
|
|
if (bitRead(gol_next[x],y)) {
|
|
writexy(x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int gol_pixelcount;
|
|
int gol_diffrences;
|
|
int gol_diffrences2;
|
|
int gol_diffrences3;
|
|
int gol_diffrences4;
|
|
|
|
void gol_step() {
|
|
gol_clearnext();
|
|
gol_pixelcount = 0;
|
|
for (int x=0; x<8; x++) {
|
|
for (int y=0; y<8; y++) {
|
|
bool myself = gol_getstate(x,y);
|
|
byte neighbours = gol_countNeighbours(x,y);
|
|
if ( neighbours==3) {
|
|
gol_setnext(x,y);
|
|
gol_pixelcount++;
|
|
}
|
|
if ( neighbours==2 && myself) {
|
|
gol_setnext(x,y);
|
|
gol_pixelcount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
gol_writeLEDS();
|
|
pushout();
|
|
|
|
gol_diffrences = 0;
|
|
gol_diffrences2 = 0;
|
|
gol_diffrences3 = 0;
|
|
gol_diffrences4 = 0;
|
|
for (int i=0; i<8; i++) {
|
|
if (gol_last4[i] != gol_next[i]) {
|
|
gol_diffrences4++;
|
|
}
|
|
gol_last4[i] = gol_last3[i];
|
|
|
|
if (gol_last3[i] != gol_next[i]) {
|
|
gol_diffrences3++;
|
|
}
|
|
gol_last3[i] = gol_last2[i];
|
|
|
|
if (gol_last2[i] != gol_next[i]) {
|
|
gol_diffrences2++;
|
|
}
|
|
gol_last2[i] = gol_last[i];
|
|
|
|
if (gol_last[i] != gol_next[i]) {
|
|
gol_diffrences++;
|
|
}
|
|
gol_last[i] = gol_next[i];
|
|
}
|
|
|
|
if (gol_diffrences == 0 || gol_diffrences2==0 || gol_diffrences3 == 0 || gol_diffrences4 == 0 || gol_pixelcount == 0) {
|
|
//went static
|
|
gol_deadcount++;
|
|
}
|
|
|
|
gol_stepcount++;
|
|
delay(200);
|
|
}
|
|
|
|
// pattern 1
|
|
|
|
int pattern_state = 0;
|
|
bool pattern_direction = true;
|
|
|
|
void pattern1_setup() {
|
|
stepcount = 0;
|
|
pattern_state = 0;
|
|
pattern_direction = true;
|
|
}
|
|
|
|
void pattern1_step() {
|
|
// x-line
|
|
for(byte i=0; i<8; i++) {
|
|
writexy(i,pattern_state);
|
|
}
|
|
// y line
|
|
for(byte i=0; i<8; i++) {
|
|
writexy(pattern_state,i);
|
|
}
|
|
if(pattern_direction) {
|
|
pattern_state++;
|
|
} else {
|
|
pattern_state--;
|
|
}
|
|
if (pattern_state >=8) {
|
|
pattern_state = 6;
|
|
pattern_direction = false;
|
|
}
|
|
if (pattern_state <0) {
|
|
pattern_state=1;
|
|
pattern_direction = true;
|
|
}
|
|
pushout();
|
|
|
|
stepcount++;
|
|
delay(120);
|
|
}
|
|
|
|
// pattern 2
|
|
|
|
void pattern2_setup() {
|
|
stepcount = 0;
|
|
pattern_state = 0;
|
|
pattern_direction = true;
|
|
}
|
|
|
|
void pattern2_step() {
|
|
for (int i=pattern_state; i < 8-pattern_state; i++) {
|
|
writexy(pattern_state,i);
|
|
writexy(i,pattern_state);
|
|
writexy(7-pattern_state,i);
|
|
writexy(i,7-pattern_state);
|
|
}
|
|
|
|
pattern_state++;
|
|
if(pattern_state>=4) {
|
|
pattern_state= 0;
|
|
}
|
|
|
|
pushout();
|
|
|
|
stepcount++;
|
|
delay(800);
|
|
}
|
|
|
|
// main loop
|
|
|
|
int mode = 0;
|
|
#define NRMODES 6
|
|
|
|
void switchmode( ){
|
|
mode = random(NRMODES);
|
|
|
|
switch(mode) {
|
|
case 0: //game of life
|
|
gol_stepcount = 0;
|
|
gol_setup();
|
|
break;
|
|
case 1: // gol glider;
|
|
gol_stepcount = 0;
|
|
gol_setup_glider();
|
|
break;
|
|
case 2: // gol spaceship
|
|
gol_stepcount = 0;
|
|
gol_setup_spaceship();
|
|
break;
|
|
case 3: // spaceinvader
|
|
stepcount = 0;
|
|
invader_setup();
|
|
break;
|
|
case 4:
|
|
stepcount = 0;
|
|
pattern1_setup();
|
|
break;
|
|
case 5:
|
|
stepcount = 0;
|
|
pattern2_setup();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void loop() {
|
|
clear();
|
|
|
|
// check for end
|
|
|
|
switch(mode) {
|
|
case 0: // game of life
|
|
case 1:
|
|
case 2:
|
|
if (gol_stepcount >150) {
|
|
switchmode();
|
|
}
|
|
if (gol_deadcount > 12) {
|
|
switchmode();
|
|
}
|
|
break;
|
|
case 3: // spaceinvader
|
|
if (stepcount > 50) {
|
|
switchmode();
|
|
}
|
|
break;
|
|
case 4:
|
|
if (stepcount > 100) {
|
|
switchmode();
|
|
}
|
|
break;
|
|
case 5:
|
|
if (stepcount > 40) {
|
|
switchmode();
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch(mode) {
|
|
case 0: // game of life
|
|
case 1:
|
|
case 2:
|
|
gol_step();
|
|
break;
|
|
case 3: // spaceinvader
|
|
invader_step();
|
|
break;
|
|
case 4:
|
|
pattern1_step();
|
|
break;
|
|
case 5:
|
|
pattern2_step();
|
|
break;
|
|
|
|
}
|
|
}
|