/* The 8x8x8 RGB LED Cube by Kevin Darrah www.kevindarrah.com V7 01/24/2013 Disclaimer: Not a professional LED cube builder, this is how I did it, and this is my cube */ #include // SPI Library used to clock data out to the shift registers #define latch_pin 2// can use any pin you want to latch the shift registers #define blank_pin 4// same, can use any pin you want for this, just make sure you pull up via a 1k to 5V #define data_pin 11// used by SPI, must be pin 11 #define clock_pin 13// used by SPI, must be 13 //***variables***variables***variables***variables***variables***variables***variables***variables //These variables are used by multiplexing and Bit Angle Modulation Code int shift_out;//used in the code a lot in for(i= type loops byte anode[8];//byte to write to the anode shift register, 8 of them, shifting the ON level in each byte in the array //This is how the brightness for every LED is stored, //Each LED only needs a 'bit' to know if it should be ON or OFF, so 64 Bytes gives you 512 bits= 512 LEDs //Since we are modulating the LEDs, using 4 bit resolution, each color has 4 arrays containing 64 bits each byte red0[64], red1[64], red2[64], red3[64]; byte blue0[64], blue1[64], blue2[64], blue3[64]; byte green0[64], green1[64], green2[64], green3[64]; //notice how more resolution will eat up more of your precious RAM int level=0;//keeps track of which level we are shifting data to int anodelevel=0;//this increments through the anode levels int BAM_Bit, BAM_Counter=0; // Bit Angle Modulation variables to keep track of things //These variables can be used for other things unsigned long start;//for a millis timer to cycle through the animations //****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup void setup(){ SPI.setBitOrder(MSBFIRST);//Most Significant Bit First SPI.setDataMode(SPI_MODE0);// Mode 0 Rising edge of data, keep clock low SPI.setClockDivider(SPI_CLOCK_DIV2);//Run the data in at 16MHz/2 - 8MHz //Serial.begin(115200);// if you need it? noInterrupts();// kill interrupts until everybody is set up //We use Timer 1 to refresh the cube TCCR1A = B00000000;//Register A all 0's since we're not toggling any pins TCCR1B = B00001011;//bit 3 set to place in CTC mode, will call an interrupt on a counter match //bits 0 and 1 are set to divide the clock by 64, so 16MHz/64=250kHz TIMSK1 = B00000010;//bit 1 set to call the interrupt on an OCR1A match OCR1A=30; // you can play with this, but I set it to 30, which means: //our clock runs at 250kHz, which is 1/250kHz = 4us //with OCR1A set to 30, this means the interrupt will be called every (30+1)x4us=124us, // which gives a multiplex frequency of about 8kHz // here I just set up the anode array, this is what's written to the anode shift register, to enable each level anode[0]=B00000001; anode[1]=B00000010; anode[2]=B00000100; anode[3]=B00001000; anode[4]=B00010000; anode[5]=B00100000; anode[6]=B01000000; anode[7]=B10000000; // don't hate on how I assigned the values to this register! haha //finally set up the Outputs pinMode(latch_pin, OUTPUT);//Latch pinMode(data_pin, OUTPUT);//MOSI DATA pinMode(clock_pin, OUTPUT);//SPI Clock pinMode(blank_pin, OUTPUT);//Output Enable important to do this last, so LEDs do not flash on boot up SPI.begin();//start up the SPI library interrupts();//let the show begin, this lets the multiplexing start }//***end setup***end setup***end setup***end setup***end setup***end setup***end setup***end setup***end setup***end setup void loop(){//***start loop***start loop***start loop***start loop***start loop***start loop***start loop***start loop***start loop //Each animation located in a sub routine // To control an LED, you simply: // LED(level you want 0-7, row you want 0-7, column you want 0-7, red brighness 0-15, green brighness 0-15, blue brighness 0-15); rainVersionTwo(); folder(); sinwaveTwo(); wipe_out(); bouncyvTwo(); color_wheelTWO(); }//***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop void LED(int level, int row, int column, byte red, byte green, byte blue){ //****LED Routine****LED Routine****LED Routine****LED Routine //This is where it all starts //This routine is how LEDs are updated, with the inputs for the LED location and its R G and B brightness levels // First, check and make sure nothing went beyond the limits, just clamp things at either 0 or 7 for location, and 0 or 15 for brightness if(level<0) level=0; if(level>7) level=7; if(row<0) row=0; if(row>7) row=7; if(column<0) column=0; if(column>7) column=7; if(red<0) red=0; if(red>15) red=15; if(green<0) green=0; if(green>15) green=15; if(blue<0) blue=0; if(blue>15) blue=15; //There are 512 LEDs in the cube, so when we write to level 2, column 5, row 4, that needs to be translated into a number from 0 to 511 //This looks confusing, I know... int whichbyte = int(((level*64)+(row*8)+column)/8); // The first level LEDs are first in the sequence, then 2nd level, then third, and so on //the (level*64) is what indexes the level's starting place, so level 0 are LEDs 0-63, level 1 are LEDs 64-127, and so on //The column counts left to right 0-7 and the row is back to front 0-7 //This means that if you had level 0, row 0, the bottom back row would count from 0-7, //so if you looked down on the cube, and only looked at the bottom level // 00 01 02 03 04 05 06 07 // 08 09 10 11 12 13 14 15 // 16 17 18 19 20 21 22 23 // 24 25 26 27 28 29 30 31 // 32 33 34 35 36 37 38 39 // 40 41 42 43 44 45 46 47 // 48 49 50 51 52 53 54 55 // 56 57 58 59 60 61 62 63 //Then, if you incremented the level, the top right of the grid above would start at 64 //The reason for doing this, is so you don't have to memorize a number for each LED, allowing you to use level, row, column //Now, what about the divide by 8 in there? //...well, we have 8 bits per byte, and we have 64 bytes in memory for all 512 bits needed for each LED, so //we divide the number we just found by 8, and take the integ7er of it, so we know which byte, that bit is located //confused? that's ok, let's take an example, if we wanted to write to the LED to the last LED in the cube, we would write a 7, 7, 7 // giving (7*64)+(7*8)=7 = 511, which is right, but now let's divide it by 8, 511/8 = 63.875, and take the int of it so, we get 63, //this is the last byte in the array, which is right since this is the last LED // This next variable is the same thing as before, but here we don't divide by 8, so we get the LED number 0-511 int wholebyte=(level*64)+(row*8)+column; //This will all make sense in a sec //This is 4 bit color resolution, so each color contains x4 64 byte arrays, explanation below: bitWrite(red0[whichbyte], wholebyte-(8*whichbyte), bitRead(red, 0)); bitWrite(red1[whichbyte], wholebyte-(8*whichbyte), bitRead(red, 1)); bitWrite(red2[whichbyte], wholebyte-(8*whichbyte), bitRead(red, 2)); bitWrite(red3[whichbyte], wholebyte-(8*whichbyte), bitRead(red, 3)); bitWrite(green0[whichbyte], wholebyte-(8*whichbyte), bitRead(green, 0)); bitWrite(green1[whichbyte], wholebyte-(8*whichbyte), bitRead(green, 1)); bitWrite(green2[whichbyte], wholebyte-(8*whichbyte), bitRead(green, 2)); bitWrite(green3[whichbyte], wholebyte-(8*whichbyte), bitRead(green, 3)); bitWrite(blue0[whichbyte], wholebyte-(8*whichbyte), bitRead(blue, 0)); bitWrite(blue1[whichbyte], wholebyte-(8*whichbyte), bitRead(blue, 1)); bitWrite(blue2[whichbyte], wholebyte-(8*whichbyte), bitRead(blue, 2)); bitWrite(blue3[whichbyte], wholebyte-(8*whichbyte), bitRead(blue, 3)); //Are you now more confused? You shouldn't be! It's starting to make sense now. Notice how each line is a bitWrite, which is, //bitWrite(the byte you want to write to, the bit of the byte to write, and the 0 or 1 you want to write) //This means that the 'whichbyte' is the byte from 0-63 in which the bit corresponding to the LED from 0-511 //Is making sense now why we did that? taking a value from 0-511 and converting it to a value from 0-63, since each LED represents a bit in //an array of 64 bytes. //Then next line is which bit 'wholebyte-(8*whichbyte)' //This is simply taking the LED's value of 0-511 and subracting it from the BYTE its bit was located in times 8 //Think about it, byte 63 will contain LEDs from 504 to 511, so if you took 505-(8*63), you get a 1, meaning that, //LED number 505 is is located in bit 1 of byte 63 in the array //is that it? No, you still have to do the bitRead of the brightness 0-15 you are trying to write, //if you wrote a 15 to RED, all 4 arrays for that LED would have a 1 for that bit, meaning it will be on 100% //This is why the four arrays read 0-4 of the value entered in for RED, GREEN, and BLUE //hopefully this all makes some sense? }//****LED routine end****LED routine end****LED routine end****LED routine end****LED routine end****LED routine end****LED routine end ISR(TIMER1_COMPA_vect){//***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM //This routine is called in the background automatically at frequency set by OCR1A //In this code, I set OCR1A to 30, so this is called every 124us, giving each level in the cube 124us of ON time //There are 8 levels, so we have a maximum brightness of 1/8, since the level must turn off before the next level is turned on //The frequency of the multiplexing is then 124us*8=992us, or 1/992us= about 1kHz PORTD |= 1<7){ fx=7; fxm=-1;} if(fy<0){ fy=0; fym=1;} if(fy>7){ fy=7; fym=-1;} if(fz<0){ fz=0; fzm=1;} if(fz>7){ fz=7; fzm=-1;} direct=random(3); if(direct==0) ftx= ftx+ftxm; if(direct==1) fty= fty+ftym; if(direct==2) ftz= ftz+ftzm; if(ftx<0){ ftx=0; ftxm=1;} if(ftx>7){ ftx=7; ftxm=-1;} if(fty<0){ fty=0; ftym=1;} if(fty>7){ fty=7; ftym=-1;} if(ftz<0){ ftz=0; ftzm=1;} if(ftz>7){ ftz=7; ftzm=-1;} }//while for(xxx=0; xxx<8; xxx++){ for(yyy=0; yyy<8; yyy++){ for(zzz=0; zzz<8; zzz++){ LED(xxx, yyy, zzz, 0, 0, 0); }}} }//wipeout void rainVersionTwo(){//****rainVersionTwo****rainVersionTwo****rainVersionTwo****rainVersionTwo****rainVersionTwo int x[64], y[64], z[64], addr, leds=64, bright=1, ledcolor, colowheel; int xx[64], yy[64], zz[64], xold[64], yold[64], zold[64], slowdown; for(addr=0; addr<64; addr++){ x[addr]=random(8); y[addr]=random(8); z[addr]=random(8); xx[addr]=random(16); yy[addr]=random(16); zz[addr]=random(16); } start=millis(); while(millis()-start<20000){ //wipe_out(); //for(addr=0; addr=7) LED(z[addr], x[addr], y[addr], 0, 5, 15); if(z[addr]==6) LED(z[addr], x[addr], y[addr], 0, 1, 9); if(z[addr]==5) LED(z[addr], x[addr], y[addr], 0, 0, 10); if(z[addr]==4) LED(z[addr], x[addr], y[addr], 1, 0, 11); if(z[addr]==3) LED(z[addr], x[addr], y[addr], 3, 0, 12); if(z[addr]==2) LED(z[addr], x[addr], y[addr], 10, 0, 15); if(z[addr]==1) LED(z[addr], x[addr], y[addr], 10, 0, 10); if(z[addr]<=0) LED(z[addr], x[addr], y[addr], 10, 0, 1); }}//200 if(ledcolor>=200&&ledcolor<300){ for(addr=0; addr=7) LED(z[addr], x[addr], y[addr], 15, 15, 0); if(z[addr]==6) LED(z[addr], x[addr], y[addr], 10, 10, 0); if(z[addr]==5) LED(z[addr], x[addr], y[addr], 15, 5, 0); if(z[addr]==4) LED(z[addr], x[addr], y[addr], 15, 2, 0); if(z[addr]==3) LED(z[addr], x[addr], y[addr], 15, 1, 0); if(z[addr]==2) LED(z[addr], x[addr], y[addr], 15, 0, 0); if(z[addr]==1) LED(z[addr], x[addr], y[addr], 12, 0, 0); if(z[addr]<=0) LED(z[addr], x[addr], y[addr], 10, 0, 0); }}//300 if(ledcolor>=300&&ledcolor<400){ } if(ledcolor>=500&&ledcolor<600){ } ledcolor++; if(ledcolor>=300) ledcolor=0; for(addr=0; addr7){ xbit=-1; x[0]=7; xx[0]=random(16); yy[0]=random(16); zz[0]=0; //wipe_out(); } if(x[0]<0){ xbit=1; x[0]=0; xx[0]=random(16); yy[0]=0; zz[0]=random(16); //wipe_out(); } if(y[0]>7){ ybit=-1; y[0]=7; xx[0]=0; yy[0]=random(16); zz[0]=random(16); //wipe_out(); } if(y[0]<0){ ybit=1; y[0]=0; xx[0]=0; yy[0]=random(16); zz[0]=random(16); //wipe_out(); } if(z[0]>7){ zbit=-1; z[0]=7; xx[0]=random(16); yy[0]=0; zz[0]=random(16); //wipe_out(); } if(z[0]<0){ zbit=1; z[0]=0; xx[0]=random(16); yy[0]=random(16); zz[0]=0; //wipe_out(); } for(addr=ledcount; addr>0; addr--){ x[addr]=x[addr-1]; y[addr]=y[addr-1]; z[addr]=z[addr-1]; xx[addr]=xx[addr-1]; yy[addr]=yy[addr-1]; zz[addr]=zz[addr-1]; } }//while }//bouncyv2 void sinwaveTwo(){//*****sinewaveTwo*****sinewaveTwo*****sinewaveTwo*****sinewaveTwo*****sinewaveTwo*****sinewaveTwo int sinewavearray[8], addr, sinemult[8], colselect, rr=0, gg=0, bb=15, addrt; int sinewavearrayOLD[8], select, subZ=-7, subT=7, multi=0;//random(-1, 2); sinewavearray[0]=0; sinemult[0]=1; sinewavearray[1]=1; sinemult[1]=1; sinewavearray[2]=2; sinemult[2]=1; sinewavearray[3]=3; sinemult[3]=1; sinewavearray[4]=4; sinemult[4]=1; sinewavearray[5]=5; sinemult[5]=1; sinewavearray[6]=6; sinemult[6]=1; sinewavearray[7]=7; sinemult[7]=1; start=millis(); while(millis()-start<15000){ for(addr=0; addr<8; addr++){ if(sinewavearray[addr]==7){ sinemult[addr]=-1; } if(sinewavearray[addr]==0){ sinemult[addr]=1; } sinewavearray[addr] = sinewavearray[addr] + sinemult[addr]; }//addr if(sinewavearray[0]==7){ select=random(3); if(select==0){ rr=random(1, 16); gg=random(1, 16); bb=0;} if(select==1){ rr=random(1, 16); gg=0; bb=random(1, 16);} if(select==2){ rr=0; gg=random(1, 16); bb=random(1, 16);} /* if(multi==1) multi=0; else multi=1; */ } for(addr=0; addr<8; addr++){ LED(sinewavearrayOLD[addr], addr, 0, 0, 0, 0); LED(sinewavearrayOLD[addr], 0, addr, 0, 0, 0); LED(sinewavearrayOLD[addr], subT-addr, 7, 0, 0, 0); LED(sinewavearrayOLD[addr], 7, subT-addr, 0, 0, 0); LED(sinewavearray[addr], addr, 0, rr, gg, bb); LED(sinewavearray[addr], 0, addr, rr, gg, bb); LED(sinewavearray[addr], subT-addr,7, rr, gg, bb); LED(sinewavearray[addr], 7, subT-addr, rr, gg, bb); }//} for(addr=1; addr<7; addr++){ LED(sinewavearrayOLD[addr+multi*1], addr, 1, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*1], 1, addr, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*1], subT-addr, 6, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*1], 6, subT-addr, 0, 0, 0); LED(sinewavearray[addr+multi*1], addr, 1, rr, gg, bb); LED(sinewavearray[addr+multi*1], 1, addr, rr, gg, bb); LED(sinewavearray[addr+multi*1], subT-addr,6, rr, gg, bb); LED(sinewavearray[addr+multi*1], 6, subT-addr, rr, gg, bb); } for(addr=2; addr<6; addr++){ LED(sinewavearrayOLD[addr+multi*2], addr, 2, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*2], 2, addr, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*2], subT-addr, 5, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*2], 5, subT-addr, 0, 0, 0); LED(sinewavearray[addr+multi*2], addr, 2, rr, gg, bb); LED(sinewavearray[addr+multi*2], 2, addr, rr, gg, bb); LED(sinewavearray[addr+multi*2], subT-addr,5, rr, gg, bb); LED(sinewavearray[addr+multi*2], 5, subT-addr, rr, gg, bb); } for(addr=3; addr<5; addr++){ LED(sinewavearrayOLD[addr+multi*3], addr, 3, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*3], 3, addr, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*3], subT-addr, 4, 0, 0, 0); LED(sinewavearrayOLD[addr+multi*3], 4, subT-addr, 0, 0, 0); LED(sinewavearray[addr+multi*3], addr, 3, rr, gg, bb); LED(sinewavearray[addr+multi*3], 3, addr, rr, gg, bb); LED(sinewavearray[addr+multi*3], subT-addr,4, rr, gg, bb); LED(sinewavearray[addr+multi*3], 4, subT-addr, rr, gg, bb); } for(addr=0; addr<8; addr++) sinewavearrayOLD[addr]=sinewavearray[addr]; delay(30); }//while }//SinewaveTwo void color_wheel(){ int xx, yy, zz, ww, rr=1, gg=1, bb=1, ranx, rany, swiper; start=millis(); while(millis()-start<100000){ swiper=random(3); ranx=random(16); rany=random(16); for(xx=0;xx<8;xx++){ for(yy=0;yy<8;yy++){ for(zz=0;zz<8;zz++){ LED(xx, yy, zz, ranx, 0, rany); }} delay(50); } ranx=random(16); rany=random(16); for(xx=7;xx>=0;xx--){ for(yy=0;yy<8;yy++){ for(zz=0;zz<8;zz++){ LED(xx,yy, zz, ranx, rany, 0); }} delay(50); } ranx=random(16); rany=random(16); for(xx=0;xx<8;xx++){ for(yy=0;yy<8;yy++){ for(zz=0;zz<8;zz++){ LED(xx,yy, zz, 0, ranx, rany); }} delay(50); } ranx=random(16); rany=random(16); for(xx=7;xx>=0;xx--){ for(yy=0;yy<8;yy++){ for(zz=0;zz<8;zz++){ LED(xx,yy, zz, rany, ranx, 0); }} delay(50); } }//while }//color wheel void color_wheelTWO(){//*****colorWheelTwo*****colorWheelTwo*****colorWheelTwo*****colorWheelTwo*****colorWheelTwo int xx, yy, zz, ww, rr=1, gg=1, bb=1, ranx, rany ,ranz, select, swiper; start=millis(); while(millis()-start<10000){ swiper=random(6); select=random(3); if(select==0){ ranx=0; rany=random(16); ranz=random(16);} if(select==1){ ranx=random(16); rany=0; ranz=random(16);} if(select==2){ ranx=random(16); rany=random(16); ranz=0;} if(swiper==0){ for(yy=0;yy<8;yy++){//left to right for(xx=0;xx<8;xx++){ for(zz=0;zz<8;zz++){ LED(xx, yy, zz, ranx, ranz, rany); }} delay(30); }} if(swiper==1){//bot to top for(xx=0;xx<8;xx++){ for(yy=0;yy<8;yy++){ for(zz=0;zz<8;zz++){ LED(xx, yy, zz, ranx, ranz, rany); }} delay(30); }} if(swiper==2){//back to front for(zz=0;zz<8;zz++){ for(xx=0;xx<8;xx++){ for(yy=0;yy<8;yy++){ LED(xx, yy, zz, ranx, ranz, rany); }} delay(30); }} if(swiper==3){ for(yy=7;yy>=0;yy--){//right to left for(xx=0;xx<8;xx++){ for(zz=0;zz<8;zz++){ LED(xx, yy, zz, ranx, ranz, rany); }} delay(30); }} if(swiper==4){//top to bot for(xx=7;xx>=0;xx--){ for(yy=0;yy<8;yy++){ for(zz=0;zz<8;zz++){ LED(xx, yy, zz, ranx, ranz, rany); }} delay(30); }} if(swiper==5){//front to back for(zz=7;zz>=0;zz--){ for(xx=0;xx<8;xx++){ for(yy=0;yy<8;yy++){ LED(xx, yy, zz, ranx, ranz, rany); }} delay(30); }} }//while }//color wheel