Like you said, Paul, it's basically just reading the BCD's and dumping them to a location, and the location is determined by which strobe is low. If strobe 6 is low, BCDA goes to the "1's" digit on player 1, and BCDB goes to the "1's" digit for player 3.
Hmm.
Is there at least a tiny pause where all the strobes are high? As in, they are all normally high, and occasionally one of them goes low?
There might be a way to sense when any of them go low. Perhaps an OR gate (or a cascade of them to get as many inputs as you need) with an inverter on the inputs. Run that into an arduino interrupt and sense the RISING condition (because they are inverted). Or run all the strobes into an AND gate and sense the FALLING condition. Same thing.
The interrupt should do nothing but sense which strobe is low and grab the current BCD bits and stuff them somewhere. It has to be fast. It doesn't have time to think. The main loop() has the job of driving the display.
So, let's say that the BCD inputs are all on PORTB (pins 14-19), and the strobes are on PORTD (pins 2-6 and 11-13) on pins 3-6 and 11-12. Which pins are on what ports depends on which particular arduino you have, of course. Pin 2 is the interrupt, and we avoid pint 13 because there's an LED on it.
The declaration s would be:
const byte STROBEMASK = 0b10000001; // mask out pins 2 and 13
volatile boolean scoreNotify = false;
// PORTD - low means that the strobe has gone low
volatile byte strobe;
volatile byte bcd[8]; // each byte is a copy of PORTB at the time the strobe went low
the interrupt logic would be something like:
void ISR() {
byte thisStrobe = PORTD | STROBEMASK;
strobe &= thisStrobe;
// to be fast, the compiler must convert this switch/case to a computed jump.
// If it doesn't do that, assembler may be required.
switch(thisStrobe) {
case 0b11111101: bcd[1] = PORTB; break; // pin 3
case 0b11111011: bcd[2] = PORTB; break; // pin 4
case 0b11110111: bcd[3] = PORTB; break; // pin 5
case 0b11101111: bcd[4] = PORTB; break; // pin 6
case 0b11011111: bcd[5] = PORTB; break; // pin 11
case 0b10111111: bcd[6] = PORTB; break; // pin 12
// no default. If the strobe is not one of these six values, then something odd is going on
}
scoreNotify = true;
}
and the loop logic wold be:
void loop() {
byte _strobe;
byte _bcd[8];
// this is the block to deal with contention
noInterrupts();
if(!scoreNotify) {
interrupts();
return;
}
_strobe = strobe;
memcpy(_bcd, bcd, 8);
strobe= ~0;
scoreNotify = false;
interrupts();
// at this point, we have now retrieved the most recent updates to the digits
for(int i = 1; i<= 6; i++) {
if(_strobe & (1<<i) == 0) {
// grab the BCD value from _bcd[i] and put it at position [i] on the display.
}
}
}
I suppose the "scorenotify" gear is irrelevant, because the display will always be doing some sort of update if it's running at 1mhz. The cde could just assume that it's always set.
This setup does leave you a little short on ins, but You could probably use the analog pins as outputs for your i2c display.