Pages: [1]   Go Down
Author Topic: Cascading Four 74HC595 Shift Registers To Control a 16x16 LED Matrix  (Read 2684 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all,

I've been working on a project involving the use of four 74HC595's to control four 8x8 LED matrices in order to form a 16x16 matrix. I was able to create a successful prototype using a single 8x8 matrix but I'm getting a lot of strange things happening when I moved to the cascading shift registers.

My code is below. I'm using the following array to contain the image that is to displayed,
Code:
unsigned long drawing[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // LED control array
where the first eight bits of the long int contain the information for the first LED matrix, the second eight bits for the second LED matrix, and so on. For the purpose of this post and for my own debugging I have been hard coding values into drawing[0] in order to try and figure out what is going on.

Here's where it get strange, consider the code segment:
Code:
unsigned long drawing[8] = {32768, 0, 0, 0, 0, 0, 0, 0};
As one would expect this lights a single LED on the matrix in the location it should be. However, if I do this:
Code:
unsigned long drawing[8] = {1<<15, 0, 0, 0, 0, 0, 0, 0};
the same LED lights up in addition to all the LEDs in the next two shift registers. (1<<15 == 32768). It's as if I wrote a 0xFFFF8000 into the shift registers. And if I shift one any more than fifteen, nothing at all is displayed.

In addition, I've discovered that if I use any number, as long as it does not contain a bit shift operator, it will be displayed correctly. I believe that this means I've got the cascading aspect of it down.

I have tried several different methods of rectifying the problem and have quadruple checked that everything is connected correctly; I just cannot seem to figure out what is going on. I'm hoping that one of you has some insights as to what may be happening and how I can solve this problem. If anymore clarification is needed please let me know, and thanks in advance for your help!

Entire Code:
Code:
#include <avr/io.h>
#include <avr/interrupt.h>

#define DIMENSION 16 //length and width of Matrix
#define DIVISOR (int)(1024/DIMENSION) //Poteniometer increment value

// Variables
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;

int rowPot = 1; //Right side potentiometer
int colPot = 5; //Left side pot
int currentRow = 0;
int cRow = 0, cCol = 0; //Cursor row and col
int soft_prescaler = 0;
unsigned long drawing[8] = {1<<8, 0, 0, 0, 0, 0, 0, 0}; // LED control array

void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  DDRD = B11111111; //Sets digital pins 0-7 as outputs
 
  // Calculation for timer 2
  // 16 MHz / 8 = 2 MHz (prescaler 8)
  // 2 MHz / 256 = 7812 Hz
  // soft_prescaler = 15 ==> 520.8 updates per second
  // 520.8 / 8 rows ==> 65.1 Hz for the complete display
  TCCR2A = 0;           // normal operation
  TCCR2B = (1<<CS21);   // prescaler 8
  TIMSK2 = (1<<TOIE2);  // enable overflow interrupt
 
  // Sets initial cursor row and column
  //cRow = analogRead(rowPot) / DIVISOR;
  //cCol = analogRead(colPot) / DIVISOR;
 
  //drawing[0] = (unsigned long)(1<<16);
}

/**
 * ISR TIMER2_OVF_vect
 * This is the timer interrupt service routine.
 * It gets called at 7812 times per second.
 */
ISR(TIMER2_OVF_vect)
{
  soft_prescaler++;
  if (soft_prescaler == 15)
  {
    //Turn off currentRow
    //PORTD = (0<<currentRow);
    currentRow = (currentRow+1) % 8;
   
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, (drawing[currentRow])>>24);
    shiftOut(dataPin, clockPin, LSBFIRST, (drawing[currentRow])>>16);
    shiftOut(dataPin, clockPin, LSBFIRST, (drawing[currentRow])>>8);
    shiftOut(dataPin, clockPin, LSBFIRST, (drawing[currentRow])>>0);
    digitalWrite(latchPin, HIGH);
   
    PORTD = (1<<currentRow);   
   
    soft_prescaler = 0;
  }
}

void loop()
{}
Logged

Norway
Offline Offline
Sr. Member
****
Karma: 4
Posts: 423
microscopic quantum convulsions of space-time
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Strange. Sounds like a variation of sign-extension, only the "wrong way". http://arduino.cc/en/Reference/Bitshift
Since you use constants, I'm guessing something to do with the complier (at compile time), or maybe it's supposed to be like that, I'm not really sure. Have you tried casting it to either unsigned or signed long?

Code:
unsigned long drawing[8] = { (unsigned long)1<<15, 0, 0, 0, 0, 0, 0, 0};


EDIT: Come to think about it, you define constant types by letters after the numbers, like 1234L for long, or 1234UL for unsigned long.
Code:
unsigned long drawing[8] = { 1UL<<15, 0, 0, 0, 0, 0, 0, 0};

Otherwise it is treated like a signed integer (http://arduino.cc/en/Reference/IntegerConstants)
« Last Edit: March 28, 2011, 01:42:42 pm by raron » Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8967
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Strange. Sounds like a variation of sign-extension, only the "wrong way".

It's a quirk of C and C++:  Type conversions do length, then 'signedness'.

If you take an int 1 and shift it left 15 bits you get an int that looks like 0x80000, which is a signed int value -32768.  When it gets saved in an unsigned long the compiler first makes it long (0xFFFF8000L so it still has the value -32767) and then unsigned so it becomes 4294934528UL.

Specifying 1U or 1UL would prevent the problem.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Norway
Offline Offline
Sr. Member
****
Karma: 4
Posts: 423
microscopic quantum convulsions of space-time
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

johnwasser:

Thanks for the explanation! Of course. When you put it that way it seems so obvious now smiley
Logged

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

Yup! That did the trick! Thanks a lot you two, that is something I never would have been able to figure out on my own. I can't say I've ever seen that before but it's an extremely important thing to know. Thanks again!
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8967
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've been gored by that one before.  It's often when I forget that a "character" is, by default, SIGNED:

char Character = 0x80;

unsigned int Unsigned;

Unsigned = Character;  // Now Unsigned = 0xFF80
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Pages: [1]   Go Up
Jump to: