I don't know if @neema_t is still around, but for some reason this project continues to be interesting to me. I guess continuous DC drive is the safest solution, particularly for outdoors use, but I still wonder if multiplexing might work ok. Anyway, below is a sketch that tests a single digit for brightness and picture taking as if it were part of a display refreshing at 100us. It uses one MIC5891 on the anodes, one TPIC6C595 on the cathode, seven resistors, and an Uno. So it could be breadboarded just to see if it would be bright enough within the current limits of the chips and the display. It also combines the millis() generation routine that works better than the IDE version does.
/*
This code is intended to test the brightness and video/picture suitability of
an 11-digit common-cathode multiplexed 7-segment display. The test uses only one
display digit, which is turned on 1/11th of the time. It is assumed the segment
anodes are driven from a MIC5891, and the common cathodes by a TIPC6C595.
Segment resistors must also be used so current does not exceed permitted
maximums for the chips or the displays.
The refresh interrupt occurs every 100us, and new high-side data is shifted out
automatically by the SPI peripheral during the period between interrupts.
This should work for any microcontroller using the Atmega328P, including the Uno,
the Nano and the Pro Mini 5V 16MHz.
This code does not test the overall power dissipation of the two chips since it
only subjects them to 1/11th of the average current that would be seen in a full
11-digit display. However, the single test display digit behaves as it would in
a full setup.
Note that the TPIC6C595's maximum pulse current is 250mA, about 36mA per segment.
Resistors should be chosen accordingly. To measure segment current accurately,
measure the voltage across the resistor with your scope, then calculate current.
*/
#include <SPI.h>
const byte DIGITS = 11; //Number of digits used
const byte MILLIS_INCB = 10; // interrupt every 100us at 16MHz
volatile byte milCount = 10; // millis change every 10th interrupt
extern volatile unsigned long timer0_millis; //this defined in wiring.c
const int blink13Time = 500; // flash D7 every second
unsigned long oldMillis = millis();
unsigned long newMillis = 0;
volatile byte nextDigit = DIGITS-1;
byte outByte;
const byte Latches = 5; // latch pins of both chips connected to D5
const byte cathData = 8;
const byte cathClock = 9;
// anode data is SPI MOSI = 11
// anode clock is SPI SCK = 13
// /OE pins of both chips tied low
void setup() {
// Set up alternate interrupt for millis() and refresh
pinMode(Latches,OUTPUT);
pinMode(cathData,OUTPUT);
pinMode(cathClock,OUTPUT);
pinMode(7,OUTPUT); // Blink on D7
digitalWrite(7,HIGH);
cli(); // disable interrupts while doing this
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // same for TCCR0B
TCNT0 = 0; // initialize timer0 count to 0
OCR0A = (250/MILLIS_INCB) - 1; // set top of counter for 100us interrupts
TIMSK0 &= ~bit(TOIE0); // disable overflow interrupt
TCCR0A |= bit(WGM01); // turn on CTC mode
TCCR0B |= (bit(CS01)+bit(CS00)); // Set CS00&CS01 bits for prescaler = 64
TIMSK0 |= bit(OCIE0A); // enable timer compare interrupt
sei(); // enable interrupts
pinMode(10,OUTPUT); // Master Mode for SPI
SPI.begin(); // turn on SPI
SPCR = 0x52; // set speed to fSYS/64 (full transfer = ~40us)
// SPSR = 1; // inc speed to fSYS/32 if sending two bytes
}
void loop() { // flashes D7 for 1/2 second every second
newMillis = millis();
if ((newMillis - oldMillis) >= blink13Time) {
oldMillis = newMillis;
digitalWrite(7,!digitalRead(7)); // invert pin D7 state
}
}
ISR(TIMER0_COMPA_vect) { // this is the new ISR
// it combines millis() and display refresh
digitalWrite(Latches,HIGH); // latch data already x-ferred - both chips
digitalWrite(Latches,LOW);
digitalWrite(cathData,LOW); // prepare for next digit
nextDigit++;
if (nextDigit == DIGITS) {
nextDigit = 0;
digitalWrite(cathData,HIGH); // cathode off except for digit zero
}
// This just outputs the character "8".
// Normally the segment pattern for the next digit would be sent
// such as "outByte = digitArray[nextDigit];"
outByte = 0xFF; // testing full current ("8")
SPDR = outByte; // shift-out to anode by SPI after ISR
digitalWrite(cathClock,HIGH); // clock the next digit cathode
digitalWrite(cathClock,LOW);
milCount--; // now do millis()
if(milCount == 0) {
timer0_millis++;
milCount = MILLIS_INCB;
}
}
The TPIC6C595 isn't actually rated to handle the 60mA x 7 of the display, So it might be necessary in the full circuit to add a third one, and use two inputs per digit CC.
Another possibility is to divide digits into groups of 6 and 5, and multiplex those simultaneously. You would need to add a second MIC5891, but no additional TPICs. And the Uno would just shift out two bytes instead of one. So that option would use 5 chips and 14 resistors, which is still better than 11 chips and 77 resistors. And it would provide double the brightness of the standard multiplex.