Pages: [1]   Go Down
Author Topic: Programming a LED Cube with Arduino Mega 1280 using Shift Register CAT4016(W).  (Read 2013 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello, I am programming a LED cube (5x5x5) using Shift Register (CAT4016W) on a circuit board   http://picprojects.org.uk/projects/lc/

I have a program that works, but I want to program it myself, to display what I want it to show, but I'm new to C/C++, I've found some links to programs, but it seems I can't make it work for the CAT4016W chip.

The Code I'm running at the moment, from this thread http://forum.arduino.cc/index.php/topic,8757.0.html :


What I ask for is, is it possible to get a code and maybe a few hints to program it? I can't see what i can delete/remove from the program, to still make it work.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:

/*
 Hardware design based on:
 http://picprojects.org.uk/projects/lc/index.htm#Schematic  This is a PIC based project but the Arduino
 has all it takes to drive the display. After building the basic driver board using jumpers to an Arduino
 board, I later added a AVR 328 socket to the driver board and moved the processor to it for standalone operation.
 I choose to build the LED cube and driver as seperate assemblies, coupled with a 40 pin IDC ribbon cable. That way
 I can rebuild the cube someday if I wish, using different support/soldering method.
 
Software:
The MsTimer2 libaray (http://www.arduino.cc/playground/Main/MsTimer2) is used to generate a 2msec timer interrupt,
so the five row cube is completly refreshed every 10msec. faster then the eye can detect flickering. I have yet to test
using a pattern script from EEPROM memory as of this time. I know how to load a hex file to the AVR chip, but I haven't
figured out how I might create the hex file! A cube editor would be very useful, but well beyond my software skills.

The two column driver chips connected in series are Allegro A6276. I got mine from Newark Electronics. It combines the function
of a 32 bit serial in, parallel output shift register, plus 32 constant current drive output pins.  The data output pin's
constant current sink value is programmable (set by a fixed or variable resistor), so 125 external current limiting resistors are not
required, and the lamp brightness can be easily adjustable, nice! I used two 650 ohm resistors I had on hand. The two series
connected 16 bit shift registers allows for a total of 32 bits of column data. For a 5X5X5 cube only 25 bits (0-24) are wired
and used, bits 25-31 could be used for future additions. Maybe drive a 5x7 numeric display at same time as the cube?
The five NPN row driver transistors (I used TIP29C) allow the Arduino to update each 25 light row (or level) for 2msec after
the 25 column data bits have been shifted out to the column driver chips and latched into the current driver outputs.

http://www.allegromicro.com/en/Products/Part_Numbers/6276/6276.pdf


                           April 14, 2010 by retrolefty @ http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl

*/

#include <MsTimer2.h>     // used to set scanning rate
#include <avr/eeprom.h>   // used to read pattern data from on chip eeprom


const byte potInput = 10;    // used to get optional variable cube update interval time via analog input pin 0, not implemented of tested.
const byte clockPin = 5;   // shift reg clock pin
const byte dataPin = 6;    // shift reg data pin
const byte latchPin = 13;   // shift reg latch pin, note that the Arduino built in pin 13 LED will show this latch activity, but very dim.
const byte row0Pin =0;      // 5 cube row driver output pins to drive 5 row driver transistors
const byte row1Pin =1;
const byte row2Pin =2;
const byte row3Pin =3;
const byte row4Pin =4;
const int  timedelay = 200;  // how fast to update cube with a new data pattern (milliseconds)
const byte updatetype = 0;   // 0 = fixed update interval using timedelay constant value
                             // 1 = variable update interval using analog input pin 0 voltage
                             // 2 = time interval obtained by high 7 hits in active_display[4], from EEPROM script
                             
                         
const unsigned long all_off_display[5] = {0,0,0,0,0};  // all LEDs off pattern
const unsigned long all_on_display[5]  = {0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff}; // all LEDs on pattern
const unsigned long alt_on_display[5]  = {0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa}; // alternating LED pattern
const unsigned long alt_off_display[5] = {0x55555555,0x55555555,0x55555555,0x55555555,0x55555555}; // opposite alt LED pattern

unsigned long patternDelay;
volatile byte active_row = 0;  // represents the active row of five vertical rows of the cube, 0-4 = bottom to top rows
volatile unsigned long active_display[5] = {0,0,0,0,0}; // holds 5 rows of 25 leds (125 LEDs/bits) to update cube
unsigned int address = 0;      // EEPROM starting address, mega168 holds 128 patterns, mega328 holds 256, mega1280 holds 1,024 patterns
byte Pattern = 2;              // data pattern to send to cube, 0= blink all LEDs on/off, 1 = alternating LEDs on/off,
                               // 2 = random LEDs pattern, 3 = run a script pattern from preloaded EEPROM data (not tested yet)
                       
                       void setup() {
 
  // setup 5 output pins to drive cube row driver transistors
  pinMode(row0Pin, OUTPUT);   // setup and turn off all 5 row driver transistors
  digitalWrite(row0Pin, LOW);
  pinMode(row1Pin, OUTPUT);
  digitalWrite(row1Pin, LOW);
  pinMode(row2Pin, OUTPUT);
  digitalWrite(row2Pin, LOW);
  pinMode(row3Pin, OUTPUT);
  digitalWrite(row3Pin, LOW);
  pinMode(row4Pin, OUTPUT);
  digitalWrite(row4Pin, LOW);
 
  // setup and turn off 3 shift register control pins
  pinMode(clockPin, OUTPUT); 
  digitalWrite(clockPin, LOW);
  pinMode(dataPin, OUTPUT);
  digitalWrite(dataPin,  LOW);
  pinMode(latchPin, OUTPUT);
  digitalWrite(latchPin, LOW);
 
  // four input pins used to select pattern update type by jumper ground clip on driver/processor board
  pinMode(7, INPUT);                 
  digitalWrite(7, HIGH);  //jumper will select pattern 0 on/off
  pinMode(8, INPUT);           
  digitalWrite(8, HIGH);  //jumper will select pattern 1 alternating on/off
  pinMode(9, INPUT);           
  digitalWrite(9, HIGH);  //jumper will select pattern 2 random pattern
  pinMode(10, INPUT);           
  digitalWrite(10, HIGH); //jumper will select pattern 3 EEPROM script pattern


 
 
  for (byte j = 0; j < 32; j++) {          // set shift reg to all columns outputs off, in case shift reg doesn't power-up cleared
       digitalWrite (dataPin, LOW);        // probably not needed, but why not start in a known all off condition.
       digitalWrite(clockPin, HIGH);       // clock 32 low bits to shift regester
       digitalWrite(clockPin, LOW);
     }
  digitalWrite(latchPin, HIGH);            //latch all zeros to 25 column output pins
  digitalWrite(latchPin, LOW);
 
  randomSeed(analogRead(1));               // used for random LED pattern mode for cube

 
  Serial.begin(57600);
  Serial.println ("5X5X5 Cube Ready");     // signal initalization done
 
 

  MsTimer2::set(2, refresh_display);      // 2ms period, generates a 2msec interrupt to the ISR routine

  MsTimer2::start();
   
}  // End of setup


Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:


void loop() {
 
  // select pattern to use 
  if(!digitalRead(7)){
    Pattern = 0;  // on/off
    }   
  if(!digitalRead(8)){
    Pattern = 1;  // alternate lamps on/off
    }
  if(!digitalRead(9)){
    Pattern = 2;  //random lamps
    }
   if(!digitalRead(10)){
    Pattern = 3;  // get script pattern from eprom
    }
 
 // phase one pattern loading   
  noInterrupts();                            // we want new pattern data to transfer 'atomic' so as not to effect display

  for (byte i = 0; i <= 4; i++) {
      if (Pattern == 0) {
        active_display[i] = all_on_display[i];
      }
      if (Pattern == 1) {
        active_display[i] = alt_on_display[i];
      }
      if (Pattern == 2) {
        active_display[i] = random(0x02000000);
      }
      if (Pattern == 3) {
        active_display[i] = eeprom_read_dword((uint32_t *)address);
        address = address + 4;
      }
  }
  interrupts();
 
  if (updatetype == 0) {
       patternDelay = timedelay;            // fixed cube update time via fixed constant
     }   
  if (updatetype == 1) {
       patternDelay = analogRead(potInput);
       if (patternDelay < 20) {
         patternDelay = 20;                 // variable time interval, clamp variable update time to 50hz minimum 
       }
  }
   if (updatetype == 2) {
     
     patternDelay = (((active_display[4] >> 25) +2)*10);    //high 7 bits of active_display[4] +2 X 10 msec
        // Serial.println (patternDelay);  // for debugging eeprom data as EEPROM scripting not tested yet.
     }   
   if (Pattern == 2) {
        patternDelay = random(100,200);  // added to give a littl random delay to make random pattern more uh random.
      } 
  delay(patternDelay);
   
   noInterrupts();

// phase two, for on/off, alt pattern usage, otherwise only one phase would have been required in main loop
  for (byte i = 0; i < 5; i++) {
      if (Pattern == 0) {
        active_display[i] = all_off_display[i];
      }
      if (Pattern == 1) {
        active_display[i] = alt_off_display[i];
      }
      if (Pattern == 2) {
        active_display[i] = random();
      }
      if (Pattern == 3) {
       active_display[i] = eeprom_read_dword((uint32_t *)address);
       address = address + 4;
      }
  }
 
   interrupts();
   
   if (updatetype == 2) {
      // patternDelay = (active_display[4] >> 25) * 20;    //high 7 bits (0-127) X 20 msec
      patternDelay = (((active_display[4] >> 25) +2)*10);    //high 7 bits of active_display[4] +2 X 10 msec
      // Serial.println (patternDelay);  // for debugging eeprom data
     }
   
   if (Pattern == 2) {
        patternDelay = random(100,200);
      }
     
   delay(patternDelay);
}

 // Start of Interrupt routine for driving a display cube row, all 5 rows (levels) are driven over a 10msec period (5 x 2msec)
void refresh_display() {
     
     unsigned long shiftdata = active_display[active_row]; // get row data for 25 leds
     unsigned long shiftmask = 1;

     for (byte i = 0; i < 32; i++) {                     // shift 32 bits (only 25 bits are wired up to cube) of data out for the 25 display columns
     
       if (shiftdata & shiftmask) {
         digitalWrite(dataPin, HIGH);
         }
         else {
           digitalWrite(dataPin, LOW);
           }
       
       digitalWrite(clockPin, HIGH);                     //  clock each bit into shift register
       digitalWrite(clockPin, LOW);
       
       shiftmask = shiftmask * 2;       //right shift bit mask one bit
     }
     
     if (active_row == 0) {
       digitalWrite(row4Pin, LOW);            // turn off row 4 driver if row 0 is now active, this is wrap around case
     }
     else {
       digitalWrite((active_row + 1), LOW);  // turn off driver from prior row update interrupt
     }
   
     digitalWrite(latchPin, HIGH);           // turn on shift register output pins, column drivers
     digitalWrite(latchPin, LOW);
     digitalWrite((active_row + 2), HIGH);   // turn on active row driver transistor
     
   // Set next active row number for next timer interrrupt 
     if (active_row >= 4) {   
         active_row = 0;  // wraparound case
     }
     else { active_row++;  // increament row number for next interrupt cycle
     }
   



Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's a schematic of my project:

http://picprojects.org.uk/projects/lc/Cube555Csch.pdf
Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 518
Posts: 26341
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Couple of issues
- you have a PIC processor instead of something like an Atmega328P.
- you have NPN transistors sourcing current instead of PNP
-  you didn't provide a link to CAT4016
http://www.onsemi.com/pub_link/Collateral/CAT4016-D.PDF
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes it's a PIC processor i switched out for the Arduino Mega, but will that be a problem? Link for the original processor: http://smackaay.com/datasheet/mcu/16f688.pdf

And the NPN and PNP transistors, will that also become a problem?

And yes, I forgot the link for the CAT4016, if there's any more information i can provide, just tell me.


And the attached file is how I connected the pins, Latch, Data and Clock etc.


I am sorry if I didn't provide enough information, I'm new to the arduino and electronics (transistors, micro contollers etc. ).


* Inputs PIC16F688 (LED CUBE).jpg (1833.78 KB, 3264x1836 - viewed 71 times.)
Logged

Pages: [1]   Go Up
Jump to: