Moi
Tuli tuossa keväällä rakennettua tuommoinen 512 ledin kuutio http://youtu.be/R_aXyEJWcZA. Ideahan on vanha ja itsekin rakensin kuution toisen tekemän projektin perusteella http://www.instructables.com/id/Led-Cube-8x8x8/ mutta ei ole suomalaisten tekemää projektia sattunut eteen niin ajattelin kirjoittaa tänne omasta.
Toiminta periaate ja käytetyt piirit:
Eli kyseessä on 8 kerroksinen ledi kuutio, jokaisessa kerroksessa 64 lediä. Ohjaus tapahtuu niin, että yhden kerroksen ledejä poltetaan vain kerrallaan hetken, jonka jälkeen kerros sammutetaan ja seuraavan kerroksen ledit valitaan ja valittu kerros sytytetään. Tämä sytytys ja sammutus tapahtuu niin nopeasti, ettei ledien sammumista ehdi huomata.
Jokaisen kerroksen 64:ää lediä ohjataan 8:lla 74HC164N shift registerillä http://www.alldatasheet.com/datasheet-pdf/pdf/101613/PHILIPS/74HC164N.html ja kerroksia sytytetään darlington transistori paketilla ULN2803A http://www.alldatasheet.com/datasheet-pdf/pdf/25571/STMICROELECTRONICS/ULN2803A.html, 74HC238N 3-to-8 line decoder/demultiplexerillä http://www.alldatasheet.com/datasheet-pdf/pdf/15570/PHILIPS/74HC238N.html. Ohjaukseen käytän Arduino Duemilanovea, josta projekti vaatii 8+1 pinniä ledien valintaan ja 3+1 kerrosten sytytyksiin, eli 13 lähtöä yhteensä.
Palavien ledien valinta:
Jokaisen (64:n) pystyrivin ledien anodit ovat juotettu yhteen, mutta kuten seuraavasta kappaleesta käy ilmi, vain valitun kerroksen ledien katodit kulkevat maihin, ja näin vain yksi koko pystyrivin ledeistä palaa. Ledien sytytys tapahtuu shift registereillä, joihin on kytketty kuhunkin 8 vierekkäistä pystyriviä. Tällöin yhdellä mikronkontrollerin pinnillä pystytään syöttämään 8:lle eri pystyriville on/off tila yhden shift regin kautta; kaikille shift regeille on myös yhteinen clock-pinni, joka kertoo milloin uusi tilatieto (0/1) on luettavissa. Käytännössä siis mikrokontrolleri laittaa 8 eri lähtöä(shift regien data-in pinneihin kytketyt) 0/1 tilaan, jonka jälkeen yhteinen clock-pinni käy 0->1, jolloin ledien tilatiedot siirtyvät kaikille 8:lle shift regille. Kun tämä sekvenssi on toteutettu 8:n kertaa, on yhden kerroksen 64:n ledin olotilat kirjoitettu. Jokaisen shift regin lähdön eteen on laitettu etuvastus ledeille (120ohm, olisi saanut olla 100!) joka rajoittaa virtaa.
Kerroksen sytytys:
Jokaisen kerroksen ledien katodit ovat yhteydessä toisiinsa, ja kun jokin kerros halutaan sytyttää, viedään yhteinen katodi maihin transistorin kautta. Koska kerroksia on 8:n, niin niitä pystyi ohjaamaan 3:lla mikrokontrollerin pinnillä 3-to-8 piirin avulla, ja koska piirissä oli vielä enable mahdollisuus, sai kerrosten sammutuksen totetutettua helposti.
Projektin eteneminen:
Olen jo jonkin aikaa pällistellyt ja ihaillut noita ledi kuutioita. Ensimmäinen kuutio jonka rakensin, oli todella surkean näköinen 3x3x3 RGB ledi kuutio. Sain sen kuitenkin toimimaan joten kuten ja kun lopulta törmäsin tuohon projektin esikuvaan, päätin kokeilla rakentaa isomman yksivärisen.
Ensimmäisenä tilasin ledit e-baystä… Halusin 3mm sinisiä haalealla kuvulla olevia ledejä 26mm katodilla… päädyin tilaamaan joltain kiinalaiselta 1000kpl 16dollarin hintaan ja sainkin lähes mitä halusin… muuten hienoja ledejä, mutta vain 16mm jalalla! tämä tarkoitti siis sitä että kuutiostani tulisi n. 130mm korkea/leveä eikä 200mm kuten olin alunperin halunnut.
Ledien tilauksen jälkeen kävin sähköisen ohjauksen läpi ja tilasin osat http://www.vekoy.com/.
Kun ledit saapuivat n. kuukauden jälkee tilauksesta, alkoi projekti edetä mukavalla vauhdilla. Ensimmäisenä rupesin testaamaan ledejä, koska en halunnut ottaa sitä riskiä, että keskelle kuutiota päätyisi rikkinäisiä ledejä. Testasin ledit 8:n ledin ryhmissä ihan vaan ison vastuksen läpi patterista jännitettä syöttämällä. Taisi yksi rikkinäinen ledi löytyä tässä testissä.
Kun ledit oli testattu alkoi toinen hieman puuduttava työvaihe: jokaisen ledin katodi jalan kääntö 90 asteen kulmaan. Tein myös jokaisen ledin anodiin pienen taivutuksen helpoittaakseni pystyrivien yhdistystä, mutta tämä koitui huonoksi ideaksi loppupeleissä.
512 lediä myöhemmin, sormet kipeinä, aloin mittaamaan ja merkkaamaan puulevylle 15mm välein ruudukkoa johon porasin 3,2mm reijät. Tästä tulisi siis sapluuna johon asettelin yhden kerroksen 64 lediä, ja kolvasin katodit yhteen. Tämä operaatio tapahtui 8 kertaa, ja aina kun sain yhden kerroksen valmiiksi, testasin yleis mittarin diodi testerillä että jokainen ledi vielä syttyisi. Kuten kuvista huomaa, kaikki ledit, paitsi ns ylärivin ledit ovat saman suuntaisesti, jolloin katodit jäivät mukavasti makaamaan toistensa päälle (16mm katodi, 15mm välit). Väliin piti lisätä muutama jäykkä langan pätkä pitämään taso vakaana.
Kun kaikki 8:n 64:n ledin tasoa oli valmiina, alkoi haastava osuus, kerrosten yhdistäminen. Valitsin mielestäni parhaimman tason ja asettelin sen sapluunaan, tästä tulisi siis ylin kerros. Kerrosten väliin piti löytää jotain 15mm levyistä ja käsiini sattui taiteltava mitta.
Se oli juuri 15mm leveä ja sopivasti taiteltuna, se meni kolmeen eri väliin ja antoi tarpeeksi tukea jottei lisättävä kerros liikkunut. Tinaus alkoi aina kulmasta ja eteni siitä vastakkaiseen kulmaan sitä mukaan mitä ledit taipuivat. Hieman väkivaltaa piti näyttää ajoittain jotta kaikki ledit tulivat täydellisesti päällekkäin ja riviin + sopivalle korkeudelle. Aina kun uusi kerros loputla tuli valmiiksi, tapahtui taas jokaisen ledin testaus. Yhdistin tinalla jokaisen kerroksen yhteen ja yleismittarilla testasin että jokainen ledi toimii. Lopulta kaikki 8 kerrosta oli yhdessä ja kaikki 512 lediä kytkettynä toisiinsa, ja kaikki vielä toimi ja näytti hyvältä.
Kun kuutio lopulta oli kasassa, rakensin pleksistä sille alustan johon porasin 15mm välein 64kpl 1mm(vai 1,5mm) reikiä yhteisille anodeille ja vielä 4,5mm reijät kulmiin, jotta saisin “jalat” telineelle.
Kun teline oli valmis, lisäsin 8:n erillistä pystytankoa kuution sisään, yksi kullekin kerrokselle. Näin sain jokaisen kerroksen yhteiset katodit alas anodi pinnien viereen, josta tulisin viemään ne ohjauslevylle.
Siinä kuutiota kasaillessa välillä lepuutin sormiani ja hermojani rakentamalla ohjaus piirilevyä. En jaksanut käydä piirtämään ja tekemään koko piirilevyä alusta loppuun, vaan käytin tuollaista täplälevyä ja kasasin siihen järjestelmän. Jostain helvetin kumman syystä päädyin käyttämään noita valkoisia liittimiä jotta saisin kuution ledit irti ohjauslevystä… en nyt tiedä mikä se hieno idea siinä oli takana mutta lopulta liittimet osoittautuivat huonoksi ideaksi ja joskus varmasti tulen ottamaan ne irti. Mutta niin, homma lähti layoutin kehittelyllä, eli mihin tulee piirikannat ja vastukset ja ne hemmetin liittimet. Kun tämä oli selvä, tinasin piirikannat, jonka jälkeen vastukset ja tämän jälkeen liittimet. Lopuksi yhdistin plussat, miinukset ja clock-pinnit.
Kun ohjauslevyn shift reggien komponentit olivat paikoillaan, aloin kehittelemään linkkiä ledien ja ohjauksen välille. Päädyin käyttämään töissä käyttämäämme verkkokaapelia, koska siinä on 8 eriväristä ohutta johdinta, ja koska kaapeli on kiinteäksi tarkoitettu, olivat johtimet yksisäikeisiä eli kohtuu jäykkiä. Johdotin liittimet, jonka jälkeen päätin johtojen pituuden ja liitin johdot kuution yhteisiin anodeihin. Tämän jälkeen kytkin myös 8 johtoa yhteisiin kerrosten katodeihin.
Tässä vaiheessa rupesi polttelemaan jo niin paljon, että oli pakko testata. En myöskään ollut (tai ole vieläkään!) tilannut erillistä arduinoa kuutiota varten, niin en viitsinyt kerrosten ohjausta lisätä ohjaus levyyn tässä vaiheessa, vaan käytin koekytkentä levyä kerrosten ohjauseen.
Kytkin siis ohjaus levystä 8:n shiftregin data-in pinnit ja yhteisen clock pinnin, koekytkentälevystä 3 kerroksen valintaan liittyvää pinniä ja enablen arduinoon, ja +5V ja GND:n arduinosta koekytkentä levyyt ja ohjaus levyyn. Näin koko järjestelmä oli kasassa ja testikoodin pystyi syöttämään sisään.
Koodin pyörittelyn jälkeen sain lopulta kuutioon eloa ja liittimien kosketusongelmien poistamisen jälkeen, kaikki 512 lediä loistivat kirkkaina.
Sitten homma olikin pitkälti tehosteiden ohjelmointia ja kehittelyä… Koodi toimii käytännössä niin, että kontrolleri interrupin avulla hoitaa ledien sytytykset ja sammutukset, kun taas pääohjelma valitsee mitkä ledit tulee olla seuraavaksi päällä ja mitkä ei. Jos joku innostuu rakentamaan vastaavan härvelin, voin pistää tarkemaa tietoa ohjelmasta.
Lopuksi kun maltoin testailuilta, yhdistin kerrosten ohjausen ohjauslevyyn ja yhdistin ohjauslevyn ja kuution yhdeksi nätiksi paketiksi toisen pleksilevyn avulla.
Nyt kuutio on muuten lähes valmis, ainoastaan pitäisi vielä se mikrokontrolleri hommata ja kiinnittää kiinteäksi osaksi kuutiota jolloin sen voi laittaa vaikka hyllylle patterin voimin välkkymään.
Kuutiosta tuli hyvän näköinen vaikka se onkin suht pieni lyhyiden ledien jalkojen takia ja efektit ovat todella näyttäviä kun on hieman hämärä valaistus.
Tässä on nyt mitä tällä istumalla jaksoin kirjoittaa… jos tulee jotain mieleen, kysykää vaan niin vastaan… ja pyrin myös lisäilemään tänne sitä mukaan mitä itselläni puskee mieleen.
Tässä vielä koodi.
[code]#include <avr/interrupt.h>
byte aakkoset[29][8] = {{0,0,0,0,0,0,0,0},
{0,24,36,66,126,66,66,66},
{0,56,36,36,56,36,36,56},
{0,28,34,64,64,64,34,28},
{0,120,68,68,68,68,68,120},
{0,124,64,64,120,64,64,124},
{0,124,64,64,120,64,64,64},
{0,60,66,64,78,66,66,60},
{0,68,68,68,124,68,68,68},
{0,16,16,16,16,16,16,16},
{0,8,8,8,8,72,72,48},
{0,68,72,80,96,80,72,68},
{0,64,64,64,64,64,64,124},
{0,65,99,85,73,65,65,65},
{0,66,98,114,90,78,70,66},
{60,66,66,66,66,66,66,60},
{0,56,36,36,56,32,32,32},
{56,68,130,130,130,154,68,58},
{0,56,36,36,56,36,36,36},
{56,68,64,56,4,4,68,56},
{0,127,8,8,8,8,8,8},
{0,66,66,66,66,66,66,60},
{0,65,65,34,34,20,20,8},
{0,130,130,146,146,170,68,0},
{129,66,36,24,24,36,66,129},
{130,130,68,40,16,16,16,16},
{0,126,4,8,16,32,64,126},
{102,24,36,66,126,66,66,66},
{102,24,36,66,66,66,36,24}};
int rivi[8] = {0,1,2,3,4,5,6,7}; //Portti D
int clock=13;
int enable = 17;
int k1=14;
int k2=15;
int k3=16;
volatile byte kuva[8][8]; // Z-kerros , Y-sivu
volatile int kerros=0;
volatile boolean tyhjennetaan=false;
void setup(){
TCCR2A = 0x00;
TCCR2B = 0x00;
//Interruppi asetukset
TCCR2A |= (0x01 << WGM21);
OCR2A = 40;
TCNT2 = 0x00;
TCCR2B |= (0x01 << CS22) | (0x01 << CS21);
TIMSK2 |= (0x01 << OCIE2A);
for(int i=0; i<8; i++){
pinMode(rivi[i],OUTPUT);
}
pinMode(clock,OUTPUT);
pinMode(enable,OUTPUT);
pinMode(k1,OUTPUT);
pinMode(k2,OUTPUT);
pinMode(k3,OUTPUT);
}
//Interruppi, Sytyttää aina yhden kerroksen kerrallaan ja palaa pääohjelmaan
ISR (TIMER2_COMPA_vect){
if(tyhjennetaan){
for(int a=0; a<8; a++){
for(int b=0; b<8; b++){
kuva[a][b]=0;
}}
tyhjennetaan=false;
}
else{
digitalWrite(enable,LOW); //Ledit offfffff
//Kerroksen lisäys ja asetus
kerros++;
if(kerros>=8){kerros=0;}
SetKerros(kerros);
// Kerroksen ledien asetus
for(int i=0; i<8; i++){
digitalWrite(clock,LOW);
PORTD = kuva[kerros][i];
digitalWrite(clock,HIGH);
}
//Ledien sytytys
digitalWrite(enable,HIGH);
}
}
//----------------------------LOOOOOOOOP------------------------------
void loop(){
splash(3);
kirjain_lento(‘R’,50);
kirjain_lento(‘U’,50);
kirjain_lento(‘U’,50);
kirjain_lento(‘V’,50);
kirjain_lento(‘I’,50);
kirjain_lento(‘P’,50);
kirjain_lento(‘E’,50);
kirjain_lento(‘N’,50);
kirjain_lento(‘K’,50);
kirjain_lento(‘K’,50);
kirjain_lento(‘I’,50);
aalto(15);
merenaalto(15);
antiaalto(15);
sineCubeP(15,50);
sineCubeV(15,50);
effect_random_filler(10,1);
delay(500);
effect_random_filler(10,0);
effect_rain(200);
tyhjenna();
for(int j=0; j<5;j++){
for(int i=0; i<4; i++){
tyhjenna();
box_wireframe(i,i,i,7-i,7-i,7-i);
delay(j50);
}
for(int i=3; i>0; i–){
tyhjenna();
box_wireframe(i,i,i,7-i,7-i,7-i);
delay(j50);
}
}
tyhjenna();
box_wireframe(0,0,0,7,7,7);
delay(2000);
tyhjenna();
}
//-------------------------------------------------------------------
void sineCube(){
float phase=0;
int size=8;
float Z=0;
unsigned long tikit;
for(int g=0; g<14; g++){
for(phase=0; phase<2*PI; phase=phase+0.09){
tyhjenna();
for(int x = 0; x < size; x++){
for(int y = 0; y < size; y++){
Z = sin(phase + sqrt(pow(skaalaus(x,0,7,-PI,PI),2) + pow(skaalaus(y,0,7,-PI,PI),2)));
Z = round(skaalaus(Z,-1,1,0,size-1));
int z = int(Z);
setLed(x,y,z);
}
}
tikit=millis();
while(tikit+5>millis()){
;
}
}
}
}
//-----------------------------------------------------------------
//Pysty liike
void sineCubeP(int kierrokset, int tauko){
float phase=0;
float Z=0;
for(int g=0; g<kierrokset; g++){
for(phase=0; phase<2*PI; phase=phase+0.39){
tyhjenna();
for(int x = 0; x < 4; x++){
for(int y = 0; y < 4; y++){
Z = sin(phase + sqrt(pow(skaalaus(x,0,7,-PI,PI),2) + pow(skaalaus(y,0,7,-PI,PI),2)));
Z = round(skaalaus(Z,-1,1,0,7));
int z = int(Z);
setLed(x,y,z);
setLed(x,7-y,z);
setLed(7-x,y,z);
setLed(7-x,7-y,z);
}
}
delay(tauko);
}
}
}
//-----------------------------------------------------------------
//vaaka liike
void sineCubeV(int kierrokset, int tauko){
float phase=0;
float Y=0;
for(int g=0; g<kierrokset; g++){
for(phase=0; phase<2*PI; phase=phase+0.39){
tyhjenna();
for(int x = 0; x < 4; x++){
for(int z = 0; z < 4; z++){
Y = sin(phase + sqrt(pow(skaalaus(x,0,7,-PI,PI),2) + pow(skaalaus(z,0,7,-PI,PI),2)));
Y = round(skaalaus(Y,-1,1,0,7));
int y = int(Y);
setLed(x,y,z);
setLed(x,y,7-z);
setLed(7-x,y,z);
setLed(7-x,y, 7-z);
}
}
delay(tauko);
}
}
}
//-----------------------------------------------------------------
//aaltoilu
void aalto(int kierrokset){
for(int g=0; g<kierrokset; g++){
for(float kierros=0; kierros< 2*PI; kierros=kierros+0.39){
for(int x=0; x<8; x++){
int z = int(round(skaalaus(sin(kierros + skaalaus(x,0,7,0,PI)),-1,1,0,7) ));
setLed(x,0,z);
setLed(x,1,z);
setLed(x,2,z);
setLed(x,3,z);
setLed(x,4,z);
setLed(x,5,z);
setLed(x,6,z);
setLed(x,7,z);
}
delay(50);
tyhjenna();
}
}
}
//-----------------------------------------------------------------
//aaltoilu
void merenaalto(int kierrokset){
for(int g=0; g<kierrokset; g++){
for(float kierros=0; kierros< 2*PI; kierros=kierros+0.39){
for(int x=0; x<8; x++){
int z = int(round(skaalaus(sin(kierros + skaalaus(x,0,7,0,PI)),-1,1,0,7) ));
for(int i=0; i<=z; i++){
setLed(x,0,i);
setLed(x,1,i);
setLed(x,2,i);
setLed(x,3,i);
setLed(x,4,i);
setLed(x,5,i);
setLed(x,6,i);
setLed(x,7,i);
}
}
delay(50);
tyhjenna();
}
}
}
//-----------------------------------------------------------------
//käänteinen aaltoilu
void antiaalto(int kierrokset){
for(int g=0; g<kierrokset; g++){
for(float kierros=0; kierros< 2*PI; kierros=kierros+0.39){
tayta();
for(int x=0; x<8; x++){
int z = int(round(skaalaus(sin(kierros + skaalaus(x,0,7,0,PI)),-1,1,0,7) ));
resLed(x,0,z);
resLed(x,1,z);
resLed(x,2,z);
resLed(x,3,z);
resLed(x,4,z);
resLed(x,5,z);
resLed(x,6,z);
resLed(x,7,z);
if(z<7){
resLed(x,0,z+1);
resLed(x,1,z+1);
resLed(x,2,z+1);
resLed(x,3,z+1);
resLed(x,4,z+1);
resLed(x,5,z+1);
resLed(x,6,z+1);
resLed(x,7,z+1);
}
if(z>0){
resLed(x,0,z-1);
resLed(x,1,z-1);
resLed(x,2,z-1);
resLed(x,3,z-1);
resLed(x,4,z-1);
resLed(x,5,z-1);
resLed(x,6,z-1);
resLed(x,7,z-1);
}
}
delay(50);
}
}
tyhjenna();
}
//-----------------------------------------------------------------
float skaalaus(float in, float inMin, float inMax, float outMin, float outMax){
float out;
out = (in-inMin)/(inMax-inMin)*(outMax-outMin) + outMin;
return out;
}
//----------------------------------------------------------
void splash(int kiertomaara){
for(int i=0; i<kiertomaara; i++){
//täytto
for(int j=0; j<8; j++){
kuva[j][0]=255;
kuva[j][1]=255;
kuva[j][2]=255;
kuva[j][3]=255;
kuva[j][4]=255;
kuva[j][5]=255;
kuva[j][6]=255;
kuva[j][7]=255;
delay(15);
}
delay(100);
//tyhjennys
for(int j=0; j<8; j++){
kuva[j][0]=0;
kuva[j][1]=0;
kuva[j][2]=0;
kuva[j][3]=0;
kuva[j][4]=0;
kuva[j][5]=0;
kuva[j][6]=0;
kuva[j][7]=0;
delay(15+j*10);
}
}
}
//----------------------------------------------------------
// Set or clear exactly 512 voxels in a random order.
void effect_random_filler (int viive, int state){
int x,y,z;
int loop = 0;
if (state == 1){tyhjenna();}
else{tayta();}
while (loop<511){
x = rand()%8;
y = rand()%8;
z = rand()%8;
if ((state == 0 && getLed(x,y,z) == 0x01) || (state == 1 && getLed(x,y,z) == 0x00))
{
altervoxel(x,y,z,state);
delay(viive);
loop++;
}
}
}
//---------------------------------------------------------------------
void box_walls(int x1, int y1, int z1, int x2, int y2, int z2)
{
int iy;
int iz;
argorder(x1, x2, &x1, &x2);
argorder(y1, y2, &y1, &y2);
argorder(z1, z2, &z1, &z2);
for (iz=z1;iz<=z2;iz++)
{
for (iy=y1;iy<=y2;iy++)
{
if (iy == y1 || iy == y2 || iz == z1 || iz == z2)
{
kuva[iz][iy] = byteline(x1,x2);
} else
{
kuva[iz][iy] |= ((0x01 << x1) | (0x01 << x2));
}
}
}
}
//-----------------------------------------------------------------
void effect_rain (int iterations)
{
int i, ii;
int rnd_x;
int rnd_y;
int rnd_num;
for (ii=0;ii<iterations;ii++)
{
rnd_num = rand()%4;
for (i=0; i < rnd_num;i++)
{
rnd_x = rand()%8;
rnd_y = rand()%8;
setLed(rnd_x,rnd_y,7);
}
delay(50);
shift(1,-1);
}
}
//--------------------------------------------------------------------
void draw_positions_axis (char axis, unsigned char positions[64], int invert)
{
int x, y, p;
tyhjenna();
for (x=0; x<8; x++)
{
for (y=0; y<8; y++)
{
if (invert)
{
p = (7-positions[(x8)+y]);
} else
{
p = positions[(x8)+y];
}
if (axis == 1)
setLed(x,y,p);
if (axis == 2)
setLed(x,p,y);
if (axis == 3)
setLed(p,y,x);
}
}
}
//-------------------------------------------------------------------
void kirjain_lento(char kirjain, int nopeus){
tyhjenna();
if(kirjain==32){kirjain=0;};
if(kirjain>64 && kirjain<91){kirjain = kirjain - 64;}; //A-Z (isot)
if(kirjain>96 && kirjain<123){kirjain = kirjain - 96;}; //A-Z (pienet)
if(kirjain ==63 ){kirjain=27;};// Ä
if(kirjain ==33 ){kirjain=28;};// Ö
for(int i=0; i<8; i++){
//piirretään kirjain
kuva[7][i]=aakkoset[kirjain][0];
kuva[6][i]=aakkoset[kirjain][1];
kuva[5][i]=aakkoset[kirjain][2];
kuva[4][i]=aakkoset[kirjain][3];
kuva[3][i]=aakkoset[kirjain][4];
kuva[2][i]=aakkoset[kirjain][5];
kuva[1][i]=aakkoset[kirjain][6];
kuva[0][i]=aakkoset[kirjain][7];
delay(nopeus);//Tauko
if(i==7){
delay(3*nopeus);
}
//Tyhjennetään uutta sivua varten
kuva[0][i]=0;
kuva[1][i]=0;
kuva[2][i]=0;
kuva[3][i]=0;
kuva[4][i]=0;
kuva[5][i]=0;
kuva[6][i]=0;
kuva[7][i]=0;
}
}
//---------------------------------------------------------------------
void effect_axis_updown_randsuspend (char axis, int tauko, int sleep, int invert){
unsigned char positions[64];
unsigned char destinations[64];
int i,px;
//set 64 rand pos
for(i=0; i<64; i++){
positions[i] = 0;
destinations[i] = rand()%8;
}
//loop 8 times to allow dest. 7 to reach all the way
for(i=0; i<8; i++){
//For every iteration, move all position one step closer to dest.
for(px=0; px<64; px++){
if(positions[px]<destinations[px]){positions[px]++;}
//piirto ja tauko
draw_positions_axis(axis, positions, invert);
delayMicroseconds(tauko);
}
}
//set all destin. to 7 opposite<>start
for(i=0; i<64; i++){destinations[i]=7;}
//suspend the positions in mid air for while
delay(sleep);
for(i=0; i<8; i++){
for(px=0; px<64; px++){
if(positions[px]<destinations[px]){positions[px]++;}
if(positions[px]>destinations[px]){positions[px]–;}
}
draw_positions_axis(axis, positions, invert);
delayMicroseconds(tauko);
}
}
//----------------------------------------------------------------------
void setLed( int x, int y, int z){
if(inrange(x,y,z)){kuva[z][y] |= (1<< x);}
}
void resLed( int x, int y, int z){
if(inrange(x,y,z)){kuva[z][y] &= ~(1<<x);}
}
boolean getLed( int x, int y, int z){
if(inrange(x,y,z)){
if(kuva[z][y] & (1<<x)){ return true;}
else{ return false;}
}
else{ return false;}
}
void altervoxel(int x, int y, int z, int state)
{
if (state == 1){
setLed(x,y,z);}
else{
resLed(x,y,z);}
}
void tayta(){
for(int a=0; a<8; a++){
for(int b=0; b<8; b++){
kuva[a][b]=255;
}}
}
void tyhjenna(){
tyhjennetaan=true;
while(tyhjennetaan==true){
;
}
}
boolean inrange(int x, int y, int z){
if(x >= 0 && x < 8 && y >= 0 && y < 8 && z >= 0 && z < 8){return true;}
else{return false;}
}
// Draw a wireframe box. This only draws the corners and edges,
// no walls.
void box_wireframe(int x1, int y1, int z1, int x2, int y2, int z2)
{
int iy;
int iz;
argorder(x1, x2, &x1, &x2);
argorder(y1, y2, &y1, &y2);
argorder(z1, z2, &z1, &z2);
// Lines along X axis
kuva[z1][y1] = byteline(x1,x2);
kuva[z1][y2] = byteline(x1,x2);
kuva[z2][y1] = byteline(x1,x2);
kuva[z2][y2] = byteline(x1,x2);
// Lines along Y axis
for (iy=y1;iy<=y2;iy++)
{
setLed(x1,iy,z1);
setLed(x1,iy,z2);
setLed(x2,iy,z1);
setLed(x2,iy,z2);
}
// Lines along Z axis
for (iz=z1;iz<=z2;iz++)
{
setLed(x1,y1,iz);
setLed(x1,y2,iz);
setLed(x2,y1,iz);
setLed(x2,y2,iz);
}
}
char byteline (int start, int end){
return ((0xff<<start) & ~(0xff<<(end+1)));
}
void argorder(int ix1, int ix2, int *ox1, int *ox2){
if (ix1>ix2){
int tmp;
tmp = ix1;
ix1= ix2;
ix2 = tmp;
}
*ox1 = ix1;
*ox2 = ix2;
}
// Draw a line between any coordinates in 3d space.
// Uses integer values for input, so dont expect smooth animations.
void line(int x1, int y1, int z1, int x2, int y2, int z2){
float xy; // how many voxels do we move on the y axis for each step on the x axis
float xz; // how many voxels do we move on the y axis for each step on the x axis
unsigned char x,y,z;
unsigned char lasty,lastz;
int X,Y,Z;
// We always want to draw the line from x=0 to x=7.
// If x1 is bigget than x2, we need to flip all the values.
if (x1>x2){
int tmp;
tmp = x2; x2 = x1; x1 = tmp;
tmp = y2; y2 = y1; y1 = tmp;
tmp = z2; z2 = z1; z1 = tmp;
}
if (y1>y2){
xy = (float)(y1-y2)/(float)(x2-x1);
lasty = y2;
} else
{
xy = (float)(y2-y1)/(float)(x2-x1);
lasty = y1;
}
if (z1>z2)
{
xz = (float)(z1-z2)/(float)(x2-x1);
lastz = z2;
} else
{
xz = (float)(z2-z1)/(float)(x2-x1);
lastz = z1;
}
// For each step of x, y increments by:
for (x = x1; x<=x2;x++)
{
y = (xy*(x-x1))+y1;
z = (xz*(x-x1))+z1;
//X=int(x);
//Y=int(y);
//Z=int(z);
setLed(X,Y,Z);
}
}
// Shift the entire contents of the cube along an axis
// This is great for effects where you want to draw something
// on one side of the cube and have it flow towards the other
// side. Like rain flowing down the Z axiz.
void shift (char axis, int direction){
int i, x ,y;
int ii, iii;
int state;
for (i = 0; i < 8; i++){
if (direction == -1)
{
ii = i;
} else
{
ii = (7-i);
}
for (x = 0; x < 8; x++){
for (y = 0; y < 8; y++){
if (direction == -1)
{
iii = ii+1;
} else
{
iii = ii-1;
}
if (axis == 1)
{
state = getLed(x,y,iii);
altervoxel(x,y,ii,state);
}
if (axis == 2)
{
state = getLed(x,iii,y);
altervoxel(x,ii,y,state);
}
if (axis == 3)
{
state = getLed(iii,y,x);
altervoxel(ii,y,x,state);
}
}
}
}
if (direction == -1)
{
i = 7;
} else
{
i = 0;
}
for (x = 0; x < 8; x++)
{
for (y = 0; y < 8; y++)
{
if (axis == 1)
resLed(x,y,i);
if (axis == 2)
resLed(x,i,y);
if (axis == 3)
resLed(i,y,x);
}
}
}
//---------------------------------------------------------------------------
void SetKerros(int x){
switch(x){
case 0:
//1 kerros
digitalWrite(k1,LOW);
digitalWrite(k2,LOW);
digitalWrite(k3,LOW);
break;
case 1:
//2 kerros
digitalWrite(k1,HIGH);
digitalWrite(k2,LOW);
digitalWrite(k3,LOW);
break;
case 2:
//3 kerros
digitalWrite(k1,LOW);
digitalWrite(k2,HIGH);
digitalWrite(k3,LOW);
break;
case 3:
//4 kerros
digitalWrite(k1,HIGH);
digitalWrite(k2,HIGH);
digitalWrite(k3,LOW);
break;
case 4:
//5 kerros
digitalWrite(k1,LOW);
digitalWrite(k2,LOW);
digitalWrite(k3,HIGH);
break;
case 5:
//6 kerros
digitalWrite(k1,HIGH);
digitalWrite(k2,LOW);
digitalWrite(k3,HIGH);
break;
case 6:
//7 kerros
digitalWrite(k1,LOW);
digitalWrite(k2,HIGH);
digitalWrite(k3,HIGH);
break;
case 7:
//8 kerros
digitalWrite(k1,HIGH);
digitalWrite(k2,HIGH);
digitalWrite(k3,HIGH);
break;
}
}
[/code]