OK, here's the code. I'll post it to the blog site once I work out how to constrain it to a scrolly window...
/*
--------------------------------------------------------------------------------
-- 7 Segment Dual Scrolling Display
-- by Ade Vickers
--
-- Adapted from LucidTronix 7 Segment LED and 74HC595 shift
-- register tutorial at: http://www.lucidtronix.com/tutorials/41
--
-- Circuit requirements:
-- 3x 74XX595 shift registers
-- 2x 4-character LED displays (common anode or cathode)
-- Current limiting resistors - 1 per segment. Use resistor arrays, much neater
-- Decoupling caps to taste
-- An Arduino.
--
-- Version On By Comment
-- -------- ----------- --- ----------------------------------------------------
-- 1.00 02-Jan-2014 JAV Created
--
--------------------------------------------------------------------------------
*/
// SPI interface.
int dataPin = 2;
int latchPin = 3;
int clockPin = 4;
/*
Alphanumerics
0 1 2 3 4 5 6 7 8 9
a b c d e f g h i j
k l m n o p q r s t
u v w z y z - _ ^
Invert all 0/1s if you are using a common cathode display
*/
byte dec_digits[] = { 0b00000011,0b10011111,0b00100101,0b00001101,0b10011001,0b01001001,0b01000001,0b00011111,0b00000001,0b00001001,
0b00010001, 0b11000001, 0b01100011, 0b10000101, 0b01100001, 0b01110001, 0b01000011, 0b11010001, 0b10011111, 0b10001111,
0b10010001, 0b11100011, 0b01010111, 0b11010101, 0b00000011, 0b00110001, 0b00011001, 0b11110101, 0b01001001, 0b11100001,
0b10000011, 0b10100011, 0b10101011, 0b11111111, 0b10011001, 0b11111111, 0b11111101, 0b11111111, 0b01111111, 0b11101111 };
// Position codes
byte dec_display[]= { 0b00010001, 0b00100010 ,0b01000100, 0b10001000 };
// The message to display. Terminates with char 255 (because it turns out zero is a valid character, doh!).
// TODO: Read from serial port?
byte message[] = {38, 36, 39, 36, 38, 37, 7, 36, 28, 14, 16, 22, 14, 23, 29, 37, 13, 18, 28, 25, 21, 10, 34, 37, 12, 24, 30, 27, 29, 14, 28, 14,
34, 37, 24, 15, 37, 28, 25, 10, 27, 20, 15, 30, 23, 37, 37, 37, 29, 17, 10, 23, 20, 28, 37, 16, 30, 34, 28, 37, 37, 39, 36, 38,
36, 39, 37, 37, 37, 255};
int msgLength;
// Loop variables
int iPos = 0; // Position in message to start sending digits this time (assuming we're scrolling the message)
int iCount = 0; // Counter to provide a delay
void setup() {
//set pins to output so you can control the shift register
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
// Work out how long the message is
// Max 1000 chars.
// Use a Geordie loop for this
for (int yi = 0; yi <= 999; yi++) {
if (message[yi]==255) {
msgLength = yi;
yi=1000; // Quit the loop now
}
}
}
void loop() {
int _d0, _d1; // The 2 digits we will activate
// HOW IT WORKS
// There are 3 shift registers chained together, in left-to-right order DIG1, DIG2, DIGSELECT
// DIG1 can display any one of the 4 digits at a time. The 4 MSBits of DIGSELECT choose which one is ON.
// DIG2 is identical. The least significant 4 bits of DIGSELECT choose which one.
// e.g. to show the number 1 at position 1 (counting L->R), we load 3 bytes: 1001 1111, 1111 1111, 1000 0000
// So DIG1 gets 1001 1111 (= segs b & c switched on - remember, active LOW on the cathode),
// DIG2 gets 1111 1111 = all off
// DIGSELECT gets 1000 0000 = display digit 1 in DIG1
//
// e.g. to show 1234 5678, we would:
// - Send 1 (1001 1111), 5 (0100 1000) and 1000 1000, pause a ms or 2, then
// - send 2 (0010 0101), 6 (0100 0001) and 0100 0100, pause a ms or 2.... then the next 2 digits.
// Then repeat.
//
for (int digitOffset = 0; digitOffset < 4; digitOffset++) {
// Set the appropriate digits.
_d0 = iPos + 4 + digitOffset;
_d1 = iPos + digitOffset;
// These 2 lines cause the message to wrap around when we run out of characters.
if (_d0 >= msgLength) _d0 = _d0 - msgLength;
if (_d1 >= msgLength) _d1 = _d1 - msgLength;
// Write the appropriate digits
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, dec_digits[message[_d0]]);
shiftOut(dataPin, clockPin, LSBFIRST, dec_digits[message[_d1]]);
shiftOut(dataPin, clockPin, LSBFIRST, dec_display[3 - digitOffset]);
digitalWrite(latchPin, HIGH);
// Wait 5ms to allow POV, then move to the next digit
// Turns out we don't need this. Run the bugger as fast as possible, otherwise
// it just flickers.
//delay(2);
}
// Cheesy delay loop. After 200 counters, move to the next digit in the message.
// Comment out to prevent scrolling. Adjust value to adjust scrolling speed.
iCount++;
if (iCount > 200) {
//Shift to the next digit
iCount = 0;
iPos++;
if (iPos >= msgLength) iPos = 0;
}
}