OK, I couldn’t help myself… running two more ‘595 shift registers in parallel with the ones for the LED bargraph provides enough bits for a DL1414 four character ASCII display:
The serial data input (SER
) and serial clock (SCK
) lines drive both shift register strings with the same values at the same time. The two strings have different parallel register clocks (RCK
), so you twiddle only the one you want; the other string gets the same data, but it never reaches those parallel outputs.
This being a breadboard lashup, there’s no red filter to boost the contrast; :
A red filter would really help, as shown on my old Tek ROM readout board.
The DL1414 datasheet seems very hard to find; that’s a clean version I fetched from datasheetarchive.com.
They’ve also become insanely expensive these days and you don’t want to use them for a new design, but if you happen to have a NOS tube lying around and hadn’t thought of monetizing your assets, well…
To simplify debugging, the test code blips both RCK
lines after shifting the data out, which means the LED bargraph shows the actual bits driving the DL1414. Slow down the update rate, un-comment the delay(1000)
statements, and you can watch the DL1414 pins in “real time”. Cheaper than a logic analyzer…
The test routine displays HELO
, then shows the low word of the running millis()
value in hex every 100 ms, for lack of anything smarter.
You could use a single shift register string with two ‘595 chips driving both the LED bargraph and the DL1414; the bars would flicker briefly when updating the DL1414, but that might not be even slightly objectionable for some geek-chic projects.
You could put the two shift registers in series, which means you must shift twice as many bits to update the DL1414 display; you’d need only one RCK
line for both sets if you shifted the unchanging bits every time. That might not be such a big deal, even though writing each character requires three complete shift sequences.
I used a union to overlay a word variable with a bitfield structure:
union DL1414_ { word ShiftWord; // word overlay struct { // bitfield sent to the display unsigned int Addr:2; unsigned int NotWrite:1; unsigned int Ctl3_7:5; // unused bits unsigned int Data:7; unsigned int Data7:1; // unused bit } ShiftBits; };
Bit-twiddling operations then work on the bitfield elements and shifting uses byte-wide chunks:
union DL1414_ DL1414; DL1414.ShiftBits.Data = Char & 0x7F; DL1414.ShiftBits.Addr = ~CharID & 0x03; // reverse order of chars DL1414.ShiftBits.NotWrite = 1; // set up data and address shiftOut(PIN_MOSI,PIN_SCK,MSBFIRST,DL1414.ShiftWord >> 8); shiftOut(PIN_MOSI,PIN_SCK,MSBFIRST,DL1414.ShiftWord & 0x00ff);
I briefly thought about overlaying two bytes instead of a word, but came to my senses. I assume the compiler can optimize those byte-sized shifts out of existence, but it doesn’t really matter.
The DL1414 address layout puts character 0 on the right, but we want it on the left to match the string subscript; just invert the address bits and move on.
The complete Arduino source code:
// LED Character Display // Ed Nisley - KE4ANU - November 2012 // Uses obsolete DL1414 LED displays // Display pinout: // https://softsolder.com/2009/08/05/arduino-using-ancient-litronix-dl-1414-led-displays/ // https://softsolder.com/2012/12/07/arduino-snippets-dl1414-led-character-display/ //---------- // Pin assignments // These are *software* pins for shiftOut(), not the *hardware* SPI functions const byte PIN_MOSI = 8; // data to shift reg const byte PIN_SCK = 6; // shift clock to shift reg const byte PIN_RCKC = 12; // latch clock for LED character shift reg const byte PIN_RCKB = 7; // latch clock for LED bar bits shift reg const byte PIN_SYNC = 13; // scope sync //---------- // Constants const int UPDATEMS = 100; // update LEDs only this many ms apart #define TCCRxB 0x02 // Timer prescaler #define LED_SIZE 4 // chars per LED #define LED_DISPLAYS 1 // number of displays #define LED_CHARS (LED_DISPLAYS * LED_SIZE) //---------- // Globals char LEDCharBuffer[LED_CHARS + 1] = "HELO"; // raw char buffer, can be used as a string union DL1414_ { word ShiftWord; // word overlay struct { // bitfield sent to the display unsigned int Addr:2; unsigned int NotWrite:1; unsigned int Ctl3_7:5; // unused bits unsigned int Data:7; unsigned int Data7:1; // unused bit } ShiftBits; }; unsigned long MillisNow; unsigned long MillisThen; //-- Helper routine for printf() int s_putc(char c, FILE *t) { Serial.write(c); } //-- Write single char to DL1414 void WriteLEDChar(char Char,char CharID) { union DL1414_ DL1414; DL1414.ShiftBits.Data = Char & 0x7F; DL1414.ShiftBits.Addr = ~CharID & 0x03; // reverse order of chars DL1414.ShiftBits.NotWrite = 1; // set up data and address shiftOut(PIN_MOSI,PIN_SCK,MSBFIRST,DL1414.ShiftWord >> 8); shiftOut(PIN_MOSI,PIN_SCK,MSBFIRST,DL1414.ShiftWord & 0x00ff); digitalWrite(PIN_RCKC,HIGH); digitalWrite(PIN_RCKC,LOW); digitalWrite(PIN_RCKB,HIGH); digitalWrite(PIN_RCKB,LOW); // delay(1000); DL1414.ShiftBits.NotWrite = 0; // write the character shiftOut(PIN_MOSI,PIN_SCK,MSBFIRST,DL1414.ShiftWord >> 8); shiftOut(PIN_MOSI,PIN_SCK,MSBFIRST,DL1414.ShiftWord & 0x00ff); digitalWrite(PIN_RCKC,HIGH); digitalWrite(PIN_RCKC,LOW); digitalWrite(PIN_RCKB,HIGH); digitalWrite(PIN_RCKB,LOW); // delay(1000); DL1414.ShiftBits.NotWrite = 1; // disable write shiftOut(PIN_MOSI,PIN_SCK,MSBFIRST,DL1414.ShiftWord >> 8); shiftOut(PIN_MOSI,PIN_SCK,MSBFIRST,DL1414.ShiftWord & 0x00ff); digitalWrite(PIN_RCKC,HIGH); digitalWrite(PIN_RCKC,LOW); digitalWrite(PIN_RCKB,HIGH); digitalWrite(PIN_RCKB,LOW); // delay(1000); } //------------------ // Set things up void setup() { pinMode(PIN_SYNC,OUTPUT); digitalWrite(PIN_SYNC,LOW); // show we arrived // TCCR1B = TCCRxB; // set frequency for PWM 9 & 10 // TCCR2B = TCCRxB; // set frequency for PWM 3 & 11 pinMode(PIN_MOSI,OUTPUT); digitalWrite(PIN_MOSI,LOW); pinMode(PIN_SCK,OUTPUT); digitalWrite(PIN_SCK,LOW); pinMode(PIN_RCKC,OUTPUT); digitalWrite(PIN_RCKC,LOW); pinMode(PIN_RCKB,OUTPUT); digitalWrite(PIN_RCKB,LOW); Serial.begin(9600); fdevopen(&s_putc,0); // set up serial output for printf() printf("LED Character Display - DL1414\r\nEd Nisley - KE4ZNU - November 2012\r\n"); for (byte i=0; i < LED_CHARS; ++i) WriteLEDChar(LEDCharBuffer[i],i); delay(1000); MillisThen = millis(); } //------------------ // Run the test loop void loop() { MillisNow = millis(); if ((MillisNow - MillisThen) > UPDATEMS) { digitalWrite(PIN_SYNC,HIGH); sprintf(LEDCharBuffer,"%04X",(word)MillisNow); for (byte i=0; i < LED_CHARS; ++i) WriteLEDChar(LEDCharBuffer[i],i); digitalWrite(PIN_SYNC,LOW); MillisThen = MillisNow; } }
Update: A question arrived about power for those displays …
In your older post about driving ancient DL1414s from Arduino, did you manage to drive these solely from a USB-powered Arduino, or did they need some external power supply help?
I got a couple of 2416s from A1, Toronto’s last surviving major surplus store. For the life of me, they won’t light. Looking back at the failure, I’m guessing the total current draw is hitting the Uno’s USB “MaxPower” [sic; it’s what lsusb says] of 100 mA.
Still looking out for the rare DL3422, which now commands utterly pointless pricing. It can do lower case, though …
As it happens, those displays suck juice like nothing else around!
I have two datasheets offering either 65 or 130 mA for a DL-1414 with all the lights on; the HP datasheet says their HPDL-2416 displays cook at 170 mA and 232 mA (!) when showing four block cursors. Take your pick, any of those will drain a piddly Pi USB port dry.
Having been burned often enough, I run Arduinos from the wall wart that also powers whatever gimmick I’m building. If the gimmick requires a relatively high voltage (9-ish V and up), I put a 7 V pre-regulator in front of the Arduino’s SMD regulator to reduce its power dissipation.
For the vacuum tube lights I’m using now, I jam +5 V into the Nano’s VCC pin, straight into the regulator’s /output/, and just hold my nose. It works well enough for my simple needs, even if I’d have a hard time justifying that sort of thing as “common engineering practice”.
So, yeah, you’re gonna need a separate supply for those puppies.
“The serial data input (SER) and serial clock (SCK) lines drive both shift register strings with the same values at the same time. The two strings have different parallel register clocks (RCK)…”
Might want to double check that schematic, Chief :-)
The other shift register string appeared yesterday; it’s the one driving the bargraph!
[Edit: The top pair of ‘595 chips in the photo.]
I see — in fact it is just as you said in the very first sentence of the post. Oops.
Well, it’s not as if I’ve never missed anything like that… [wince]