Arduino Snippets: DL1414 LED Character Display

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:

LED Character Display
LED Character 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; :

DL1414 LED Character Display - breadboard
DL1414 LED Character Display – breadboard

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.

9 thoughts on “Arduino Snippets: DL1414 LED Character Display

  1. “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 :-)

    1. drive both shift register strings

      The other shift register string appeared yesterday; it’s the one driving the bargraph!

      [Edit: The top pair of ‘595 chips in the photo.]

      1. I see — in fact it is just as you said in the very first sentence of the post. Oops.

Comments are closed.