Friday, July 27, 2012

Create your own LED cube

A LED cube is a very interesting and fascinating item that can gain lot of fun and knowledge. It's simply a 3D screen that can demonstrate your own models in a 3D space. If you are very good at programming, it will be very useful to craft more complex patterns on the cube

In my project I created my LED cube which is size of 8*8*8 (512 Leds). Here is the video
 I used red 3mm LEDs with 2.5 cm distance. Size, color and distance of LEDs are very important to make cube more visible and avoid ghost effects of reflection. It is better if you can use diffused LEDs (they can emit light to every direction with same intensity) but I couldn't find those in local market.

I used PIC16f877A microcontroller to  control entire cube. It has 40 pins and about 30 -25 usable pins to our task. But thing we don't forget here is that cube has 512 LEDs and they should have separate 512 wires to work with. Here I used the theory of using layers. So each layer has 64 LEDs and there are 8 such layers. One layer is lighten up at a time. Using the sensitivity of our eyes we can pretend that all layers are lightening at once when we switch them in a very high frequency.

In a layer all cathodes of leds are connected to one and anodes are kept free. Creating a layer is a bit challenging task. We should guarantee that all leds in the layer are keeping 2.5 cm gap and lie on the same plane. So it is easy if we can make a model like this to create the layer.

Then we can put leds into these holes and solder as we wish

After all cathodes are soldered we can see a layer like this

After all layers are finished we can move to connect layers to each other. When we are connecting layers we should make sure that anodes of the leds of one layer should be connected to the same anodes of other layer. Finally we have 64 wires for layer anodes and 8 wires for layers (common cathodes of each layer).

Next problem is how to connect all 64 wires of layers to microcntroller. Instead connecting them directly I used 8 74hc574 latch ics which have D flipflops. Using these ICs, you need only 20 pins from PIC. 8 pins to light up the layer leds, 8 pins to select the layer and 4 pins to select the latch ic.

Q0 - Q7 pins of 74hc574 (for more information refer to 74hc574 datasheet) ics are connected to rows of layer anodes. There are 8 rows the layer anodes so each row is represented by one latch ic. For putting data on a layer first select the latch ic and put data on PORTB of pic. Then move to next latch ic. When we move to next ic, values of previous ones are not changed because its D flipflops remind the previous states. Likewise we can light up a whole layer and then select the layer. Layer common cathodes are connected to J9. Using PORTD we can select a layer.



This is the brief description of the cube I have made. Those all are electronic stuffs and the most challenging task I have experienced is programming this cube. I used Timer0 clock interrupts of pic to switch between layers. Here is the code I have written. I used mikroc pro compiler



unsigned char layers[8][8]={0},i,j,k,l,m,n,q,x,y; //layers array has all values of the cube LEDs.
void loadRegister(int num){ //Here correct latch is selected
     PORTA.B0  = num%2;
     num=num>>1;
     PORTA.B1  = num%2;
     num=num>>1;
     PORTA.B2  = num%2;
     PORTA.B3=0;
     PORTA.B3=1;
}


void loadLayer(int layerNum){ //lightening a layer is done
     PORTD= 0b00000000;
     for(i=0;i<8;i++){
          PORTB=layers[layerNum][i];
          loadRegister(i);
     }
     if(layerNum==0){
          PORTD= 0b00000001; //selecting the layer
     }else if(layerNum==1){
          PORTD= 0b00000010;
     }else if(layerNum==2){
          PORTD= 0b00000100;
     }else if(layerNum==3){
          PORTD= 0b00001000;
     }else if(layerNum==4){
          PORTD= 0b00010000;
     }else if(layerNum==5){
          PORTD= 0b00100000;
     }else if(layerNum==6){
          PORTD= 0b01000000;
     }else if(layerNum==7){
          PORTD= 0b10000000;
     }
}


int num=0,conter=0;
char doCount=0;


void interrupt(){                              //Timer0 interrupts are handled at here. Here is the main driving section of the cube
     if(INTCON.TMR0IF){
        if(doCount){
           conter++;
        }
        loadLayer(num);
        num++;
        if(num==8)num=0;
        INTCON.TMR0IF = 0; // clear TMR1IF
     }


}


void init_timer(){
    OPTION_REG = 0b10000101; //Timer0 interrupts are configured
    INTCON = 0b10100000; //Interrupts are enabled.
}


void delayms(int num){
     doCount=1;
     while(conter<num);
     conter=0;
     doCount=0;


}
int power(int p){
    int val=1;
    if(p==0)return 1;
    for(k=0;k<p;k++){
        val=val*2;
    }
    return val;
}


int clearAll(){
    int i,j;
    for(i=0;i<8;i++){
      for(j=0;j<8;j++){
         layers[i][j]=0;
      }
    }
}


void circle(int xcod,int ycod,int zcod,int rad){
     int x,y,m;
     for(x=0;x<8;x++){
         for(y=0;y<8;y++){
             for(m=0;m<8;m++){
                 if((x-xcod)*(x-xcod)+(y-ycod)*(y-ycod)+(m-zcod)*(m-zcod)-rad<=0){
                     layers[m][x]= layers[m][x]|power(y);
                 }
             }
         }
     }
}


void parabola(int xcod,int ycod,int c){


     int x,y,z;
     //clearAll();
     for(x=0;x<8;x++){
        for(y=0;y<8;y++){
            for(z=0;z<8;z++){
                if(-(x-xcod)*(x-xcod)-(y-ycod)*(y-ycod)+c-z>=0)
                layers[z][x] = layers[z][x]|power(y);
            }
        }


     }


}


void plane(int a,int b,int c,int d){
     int x,y,z;
     //clearAll();
     for(x=0;x<8;x++){
        for(y=0;y<8;y++){
            for(z=0;z<8;z++){
                if((a*x+b*y-d)/c==z)
                layers[z][x] = layers[z][x]|power(y);
            }
        }


     }
}


int random,temp;


void main() {
     TRISB =0;
     TRISD=0;
     TRISA=0;
     ADCON1 = 0b00000111;
     PORTA.B3=0; //en pin






     init_timer();
     while(1){
        for(m=0;m<8;m++){
           for(n=0;n<8;n++){
             for(l=0;l<8;l++){
                layers[l][m]=layers[l][m]+power(n);
                delayms(10);
             }
           }
        }
        for(m=0;m<8;m++){
           for(n=0;n<8;n++){
             for(l=0;l<8;l++){
                layers[l][m]=layers[l][m]-power(n);
                delayms(10);
             }
           }
        }
        clearAll();
        for(m=0;m<8;m++){
           for(n=0;n<8;n++){
             for(l=0;l<8;l++){
                layers[l][m]=power(n);
                delayms(10);
                clearAll();
             }
           }
        }
        clearAll();




     for(q=0;q<100;q++){
       for(x=0;x<5;x++){
       for(l=1;l<8;l++){
          for(m=0;m<8;m++){
             temp=layers[7-l][m];
             layers[8-l][m]=temp;
          }
       }
       random= rand()%64;
       layers[0][random/8]=power(random%8);
       delayms(15);
       }
     }
     clearAll();




      for(y=0;y<8;y++){
         for(m=0;m<8;m++){
             circle(m,m,m,4);
             delayms(20);
             clearAll();
         }
      }
      
      for(y=0;y<8;y++){
         for(m=0;m<8;m++){
             circle(m,7-m,m,4);
             delayms(20);
             clearAll();
         }
      }
      
      for(y=0;y<8;y++){
         for(m=0;m<8;m++){
             circle(7-m,7-m,m,4);
             delayms(20);
             clearAll();
         }
      }
      
      for(y=0;y<8;y++){
         for(m=0;m<8;m++){
             circle(7-m,m,m,4);
             delayms(20);
             clearAll();
         }
      }


      for(y=0;y<8;y++){
         for(m=0;m<8;m++){
            parabola(3,3,m);
            delayms(50);
            clearAll();
         }
      }


      for(y=0;y<10;y++){
         for(m=0;m<8;m++){
            plane(rand()%5,rand()%5,rand()%5,rand()%5);
            delayms(50);
            clearAll();
         }
      }
     
     }


}

I should say that this is a very very brief description and sometime you may find difficult to understand some concepts of this article. If so please don't hesitate to ask questions and I'm very happy to help you :)

Thank you