Hi all!
I'm doing a 48x8 LED-matrix as a "getting started- project". I'm using cascaded 74hc595 shift-registers (Yeah, I know about current-limitations, but it was cheap enough to try) for the columns and a CD4017 decade counter for the rows. -See attached circuitry (During test only 8x8 is used and thus, only one shift-register).
*Edit: I'm using 2N3904, not 2N2222 as shown in the schematics, since my 2n2222's hasn't arrived yet.
The whole thing is controlled by a Nano (powered through USB, but both the shift- register and 4017 are powered by an external voltage source)
I got 2 issues I could use some help with:
- I get a constant flickering of the LED's! I've tried some delays, but it just seems to make it worse. When deactivating the 4017 clock pulse (only one row lights up), the flickering stops, so I assume this is caused by the 4017. During test (see simple test code code below), I only light up 3 LED's per row (to lower total current drawn from shiftregister), but I get the same effect no matter how many LED's are turned on.
//Setup pins for 4017 Decade counter
#define DIO_decade_CLK 7 //4017 CLK pin
#define DIO_decade_reset 13 //4017 Reset pin
//Setup pins for 74HC595 ShiftRegister
#define DIO_shiftReg_shiftCLK 2 //Shift Register Shift Register CLK pin (SHCP) (Shifts bits and store in temporary memory)
#define DIO_shiftReg_storeCLK 3 //Storage Register CLK pin (STCP) ("Latch" to output on rising trigger)
#define DIO_shiftReg_reset 4 //Shift Register Master Reset pin (MR) ACTIVE LOW! -SET HIGH TO NOT CLEAR MEMORY (Use storeCLK after)
#define DIO_shiftReg_data 5 //Shift Register Serial Data pin (DS)
#define characterLength 8 //Total number of bits in a segment. Standard is 8.
void setup() {
// put your setup code here, to run once:
resetDecadeCounter();
Serial.begin(9600); //Setup serial connection for display messages
//Output (1), input(0) setup
DDRD = DDRD | B10111100; //Set digital pin 2,3,4,5 as output (replaces pinMode)
DDRB = DDRB & ~B00000001; //Set digital pin 8 as Input
//Set pin default values
PORTD = PORTD | (1 << DIO_shiftReg_reset); //Set Digital pin 4 high (replaces digitalWrite)
}
void resetPin(byte pin){ //Reset $param pin to LOW
digitalWrite(pin, LOW); //Replace with PORTx in live code!
}
void setPin(byte pin) { //Set $Param pin to HIGH
digitalWrite(pin, HIGH); //Replace with PORTx in live code!
}
void pulsePin(byte pin){ //Set $Param pin to HIGH then LOW
digitalWrite(pin, HIGH); //Replace with PORTx in live code!
digitalWrite(pin, LOW); //Replace with PORTx in live code!
}
void pulsePin_slow(byte pin, int duration){ //Set $Param pin to HIGH, wait $Param duration then set pin to LOW
digitalWrite(pin, HIGH); //Replace with PORTx in live code!
delay(duration); //Delay in milliseconds
digitalWrite(pin, LOW); //Replace with PORTx in live code!
}
void resetDecadeCounter(){ //Resets the 4017 Decade Counter
pinMode(DIO_decade_reset,OUTPUT); //Set DIO_decade_Reset as output
pulsePin(DIO_decade_reset); //Reset
pinMode(DIO_decade_reset, INPUT); //Set DIO_decade_Reset as input again (Don't actually remember why I'm doing this(?)
// Serial.println("Reset");
// Serial.println("");
}
void sendByte(byte rowByte, unsigned int amount) { //Send one byte to 74hc595 temporary memory, one bit at a time. rowByte = data to print, amount = number of bits to print
byte bitsToPrint = amount;
unsigned int zeroCharactersWanted = 0; //Number of bytes full of zeros wanted (Changes if amount>characterLength)
if(amount>characterLength){ //if Too many bits are requested (More than characterLength), then fill with zeroes until all bits are set
bitsToPrint = amount%characterLength; //wanted number of bits that are exceeding full bytes
zeroCharactersWanted = amount/characterLength; //Number of full zero-characters
}
for (byte i = characterLength; i>(characterLength-bitsToPrint); i--) { //While there are bits to set (up to one full byte)
// Serial.print(!!(rowByte & (1<<(i-1))));
digitalWrite(DIO_shiftReg_data, !!(rowByte & (1<<(i-1)))); //Set databit to 0 or 1 as per MSG
pulsePin(DIO_shiftReg_shiftCLK); //store bit to ShiftReg input memory
}
resetPin(DIO_shiftReg_data); //Reset databit to LOW
}
void loop() {
byte number = B11100000;
sendByte(number,8);
pulsePin(DIO_decade_CLK);
pulsePin(DIO_shiftReg_storeCLK);
}
- When playing around with delays (10-500ms) between shift-reg.latch- and decade clock, some LED's doesn't turn on when using scrolling effect (See code below, it's the same as above, but a little different loop() ). It seems that the same LED's are always skipped.
I would like to see if anyone has any hint on what might be causing this?
//Setup pins for 4017 Decade counter
#define DIO_decade_CLK 7 //4017 CLK pin
#define DIO_decade_reset 13 //4017 Reset pin
//Setup pins for 74HC595 ShiftRegister
#define DIO_shiftReg_shiftCLK 2 //Shift Register Shift Register CLK pin (SHCP) (Shifts bits and store in temporary memory)
#define DIO_shiftReg_storeCLK 3 //Storage Register CLK pin (STCP) ("Latch" to output on rising trigger)
#define DIO_shiftReg_reset 4 //Shift Register Master Reset pin (MR) ACTIVE LOW! -SET HIGH TO NOT CLEAR MEMORY (Use storeCLK after)
#define DIO_shiftReg_data 5 //Shift Register Serial Data pin (DS)
#define characterLength 8 //Total number of bits in a segment. Standard is 8.
void setup() {
// put your setup code here, to run once:
resetDecadeCounter();
Serial.begin(9600); //Setup serial connection for display messages
//Output (1), input(0) setup
DDRD = DDRD | B10111100; //Set digital pin 2,3,4,5 as output (replaces pinMode)
DDRB = DDRB & ~B00000001; //Set digital pin 8 as Input
//Set pin default values
PORTD = PORTD | (1 << DIO_shiftReg_reset); //Set Digital pin 4 high (replaces digitalWrite)
}
void resetPin(byte pin){ //Reset $param pin to LOW
digitalWrite(pin, LOW); //Replace with PORTx in live code!
}
void setPin(byte pin) { //Set $Param pin to HIGH
digitalWrite(pin, HIGH); //Replace with PORTx in live code!
}
void pulsePin(byte pin){ //Set $Param pin to HIGH then LOW
digitalWrite(pin, HIGH); //Replace with PORTx in live code!
digitalWrite(pin, LOW); //Replace with PORTx in live code!
}
void pulsePin_slow(byte pin, int duration){ //Set $Param pin to HIGH, wait $Param duration then set pin to LOW
digitalWrite(pin, HIGH); //Replace with PORTx in live code!
delay(duration); //Delay in milliseconds
digitalWrite(pin, LOW); //Replace with PORTx in live code!
}
void resetDecadeCounter(){ //Resets the 4017 Decade Counter
pinMode(DIO_decade_reset,OUTPUT); //Set DIO_decade_Reset as output
pulsePin(DIO_decade_reset); //Reset
pinMode(DIO_decade_reset, INPUT); //Set DIO_decade_Reset as input again (Don't actually remember why I'm doing this(?)
// Serial.println("Reset");
// Serial.println("");
}
void sendByte(byte rowByte, unsigned int amount) { //Send one byte to 74hc595 temporary memory, one bit at a time. rowByte = data to print, amount = number of bits to print
byte bitsToPrint = amount;
unsigned int zeroCharactersWanted = 0; //Number of bytes full of zeros wanted (Changes if amount>characterLength)
if(amount>characterLength){ //if Too many bits are requested (More than characterLength), then fill with zeroes until all bits are set
bitsToPrint = amount%characterLength; //wanted number of bits that are exceeding full bytes
zeroCharactersWanted = amount/characterLength; //Number of full zero-characters
}
for (byte i = characterLength; i>(characterLength-bitsToPrint); i--) { //While there are bits to set (up to one full byte)
// Serial.print(!!(rowByte & (1<<(i-1))));
digitalWrite(DIO_shiftReg_data, !!(rowByte & (1<<(i-1)))); //Set databit to 0 or 1 as per MSG
pulsePin(DIO_shiftReg_shiftCLK); //store bit to ShiftReg input memory
}
resetPin(DIO_shiftReg_data); //Reset databit to LOW
}
void loop() {
byte number =0;
for (byte i=0; i<8; i++){
number = 3<<i;
sendByte(number, 8);
pulsePin_slow(DIO_shiftReg_storeCLK,100); //I've tried without delay too //latch shiftregister output
}
}