OK, I got this going based on the direct clocking idea and information I found right here on this board concerning the 16-bit timer. The scheme is to have an interrupt go off every 10,000 clock cycles and count that in an ISR. So I am counting milliseconds here. There is no GPS synchronization or date arithmetic to convert the seconds into a useful time and date or anything like that, just the most basic proof of concept. You can infer the schematic from the code.
// Define GPIO pins.
const int pauseButton = 0;
const int digit1 = 1;
const int digit2 = 2;
const int digit3 = 3;
const int digit4 = 4;
const int digit5 = 5;
const int digit6 = 6;
const int digit7 = 7;
const int digit8 = 8;
const int segA = 9;
const int segB = 10;
const int segC = 11;
const int segD = 12;
const int segE = 13;
const int segF = 14;
const int segG = 15;
const int segDP = 16;
volatile long count = 0;
volatile int nocount = 0;
int dispcount = 0;
void setup() {
// Configure GPIO pins.
pinMode(pauseButton, INPUT);
pinMode(digit1, OUTPUT);
pinMode(digit2, OUTPUT);
pinMode(digit3, OUTPUT);
pinMode(digit4, OUTPUT);
pinMode(digit5, OUTPUT);
pinMode(digit6, OUTPUT);
pinMode(digit7, OUTPUT);
pinMode(digit8, OUTPUT);
pinMode(segA, OUTPUT);
pinMode(segB, OUTPUT);
pinMode(segC, OUTPUT);
pinMode(segD, OUTPUT);
pinMode(segE, OUTPUT);
pinMode(segF, OUTPUT);
pinMode(segG, OUTPUT);
pinMode(segDP, OUTPUT);
// We aren't going to use segment DP.
digitalWrite(segDP, LOW);
// Set up our timer so our ISR gets called every microsecond.
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1AH = 39; // Trigger interrupt at 9,999 (10,000 cycles). 39*256 + 15 = 9,999
OCR1AL = 15;
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS10); // prescaler of 1
TIMSK1 |= (1 << OCIE1A); // use interrupts
interrupts();
}
// Our interrupt is called, bump our counter.
ISR(TIMER1_COMPA_vect)
{
if (nocount==0)
count ++;
}
void loop() {
// Display counter is separate from main counter so pausing count via the pause button doesn't pause display refresh. But disconnecting the clock will, as it must.
dispcount ++;
if (dispcount==8) dispcount = 0;
// Depressing the pause button will cause the ISR routine to stop counting even though it will continue being called.
nocount = !digitalRead(pauseButton);
// Display Count - illuminate one of the digits each time through to effect multiplexing.
// Turn off our current display so as we set it up we don't get ghosting.
switch (dispcount) {
case 0:
digitalWrite(digit8, LOW);
break;
case 1:
digitalWrite(digit1, LOW);
break;
case 2:
digitalWrite(digit2, LOW);
break;
case 3:
digitalWrite(digit3, LOW);
break;
case 4:
digitalWrite(digit4, LOW);
break;
case 5:
digitalWrite(digit5, LOW);
break;
case 6:
digitalWrite(digit6, LOW);
break;
case 7:
digitalWrite(digit7, LOW);
break;
}
// Illuminate segments for the current digit.
// Figure out digits for current display and current count, i.e. ones digit for display zero, tens digit for display two, ten millions digit for display eight.
long digit = count;
for (int i=0;i<dispcount;i++)
{
digit /= 10;
}
digit = digit % 10;
// Actual segment map courtesy of the Arabs.
switch (digit) {
case 0:
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, HIGH);
digitalWrite(segG, LOW);
break;
case 1:
digitalWrite(segA, LOW);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, LOW);
digitalWrite(segE, LOW);
digitalWrite(segF, LOW);
digitalWrite(segG, LOW);
break;
case 2:
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, LOW);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, LOW);
digitalWrite(segG, HIGH);
break;
case 3:
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, LOW);
digitalWrite(segF, LOW);
digitalWrite(segG, HIGH);
break;
case 4:
digitalWrite(segA, LOW);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, LOW);
digitalWrite(segE, LOW);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
break;
case 5:
digitalWrite(segA, HIGH);
digitalWrite(segB, LOW);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, LOW);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
break;
case 6:
digitalWrite(segA, HIGH);
digitalWrite(segB, LOW);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
break;
case 7:
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, LOW);
digitalWrite(segE, LOW);
digitalWrite(segF, LOW);
digitalWrite(segG, LOW);
break;
case 8:
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
break;
case 9:
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, LOW);
digitalWrite(segE, LOW);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
break;
}
// Now switch on the common cathode of the current display.
switch (dispcount) {
case 0:
digitalWrite(digit1, HIGH);
break;
case 1:
digitalWrite(digit2, HIGH);
break;
case 2:
digitalWrite(digit3, HIGH);
break;
case 3:
digitalWrite(digit4, HIGH);
break;
case 4:
digitalWrite(digit5, HIGH);
break;
case 5:
digitalWrite(digit6, HIGH);
break;
case 6:
digitalWrite(digit7, HIGH);
break;
case 7:
digitalWrite(digit8, HIGH);
break;
}
// A little time to allow the LEDs to stay illuminated.
delay(1);
}
The code could stand to be reviewed by someone familiar with ATMega328P counters. This is my first project where I have used one.