Seven Segments… What More Could You Need?

Seven-segment displays are pretty useful tools for taking a project from indicator lamps to actual human-machine interaction. The only problem is, one digit of one display adds 7 outputs that you have to drive (or sink) and that doesn’t leave many signals for the process. How do you overcome this hurdle? Well, electronics engineers thought of that and came up with display driver IC chips. Basically, these take a more condensed set of data and deal with the overhead of controlling the display for you. For this project day, my goal was to use the least outputs possible to drive a 2-digit seven-segment display using the outputs from a microcontroller (I used Arduino Uno). Read on to see how I did.

 

Prototype Display Circuit

Prototype Display Circuit

For the uninitiated, a seven-segment display is just an array of LEDs arranged to form the number 8. Well, actually any light source could be used, but I’m focusing on LED displays. By choosing which of the LEDs to light, the arrangement can articulate any numeral. This technology is used pretty much anywhere cheap numbers are needed, so in digital watches, calculators, thermometers, etc. LED displays in particular come in one of two flavors, common cathode and common anode. The type is important in selecting your driver, so watch out.

Seven-Segment LED Display

Seven-Segment LED Display

My display is a two-digit display with decimal points (Avago Technologies HDSP-5621, common anode, 2.5V, 30mA per segment)

There are a number of choices when it comes to display drivers. Input types include BCD, parallel binary, and serial. The output types vary from driving particular display types like LED, LCD, CRT to driving a generic output and from one up to eight digits . The driver I had on hand was a BCD to common anode LED driver for one digit (Texas Instruments SN74LS47). Part of my goal was to use the components I had to reduce my costs, but if I were to buy a driver from scratch, I’d want to go with a two-digit common anode driver with serial input.

At this point, I could have driven all 14 LEDs from 8 inputs to the display driver ICs, but 8 pins is a lot to ask on a small microcontroller, so the only way to reduce again was to look at serial. I chose to use a simple parallel-out shift register IC (takes in serial data and a clock pulse and outputs the last 8 serial bits as parallel data). I didn’t have anything on hand, so I selected Texas Instruments SN74HC164N.

Prototyping was pretty straightforward. I selected 220Ohm resistors to limit the current between each segment and the driving IC (assuming 1.2V-2.5V drop across resistors, that would be 17mA – 11mA from my 5V source). Also, I had to choose if the serial data would come from the microcontroller as LSb first or MSb first. The choice was completely mine since I wouldn’t be able to use the Serial method in the Arduino due to the clock requirement on the shift register. I opted to stick with convention and send the LSb first.

Here is a drawing of my prototype circuit:

Schematic of Seven-Segment Display Driver

Schematic of Seven-Segment Display Driver

Here is the Arduino code I used to drive the display:

// define all constant parameters here

int LEDPin = 2;
int CLKPin = 3;
int i = 0;
int j = 0;

//Debugging settings
#define DebugBaud 9600

void setup()
{
// Debugging Setup
Serial.begin(DebugBaud);

pinMode(LEDPin, OUTPUT);
pinMode(CLKPin, OUTPUT);
}

void loop()
{
//Debugging Message
// Serial.println(“Online”);

for (j = 0; j <= 9; j++){
Serial.print(j);
Serial.println(” is on the display”);
Transmit((byte) j);
Serial.println();
delay(1000);
}

}

void Transmit(byte Msg)
{
for (i = 0; i <= 7; i++){
writeBit(bitRead(Msg,i));
Serial.print(bitRead(Msg,i));
// delay(100);
}
}

void writeBit(boolean Val) {
digitalWrite(CLKPin, LOW);
// delay(1);

if (Val) {digitalWrite(LEDPin, HIGH);}
else {digitalWrite(LEDPin, LOW);}

digitalWrite(CLKPin, HIGH);
}

That was my project day!

If you liked this project, check out some of my others:

Integration… It’s not just about that silly ‘S’

Instant Parade!

The ThrAxis – Our Scratch-Built CNC Mill

Did you like It’s Project Day? You can subscribe to email notifications by clicking ‘Follow’ in the side bar on the right, or leave a comment below.

 

Integration… It’s not just about that silly ‘S’

Many years ago, I got about a dozen 16×16 bi-color LED display panels that were a part of a broken segment on a marquis. Until now, they’ve been sitting in my spare parts cabinet just waiting for a project to come up. Nothing has and now space has become a premium, so it’s time to do something with them or get rid of them. Since I haven’t used them before and I don’t have a display driver, I don’t know how useful they will be or even if they will work.

When these panels came to me, they were mounted on a frame and had small FPC (flexible printed circuit) ribbon cables connecting each row in series. The backs are printed with two part numbers KLM-163-CAH and KLM-163-CAN which made tracking down a datasheet challenging. I found one on datasheetdirect.com. The panels are powered by 5VDC and take 5VDC TTL logic levels (making them 100% compatible with Arduino or any other 5V microcontroller).

In terms of basic operation, you have to select the line, write a serial string to indicate the LEDs to light, then flip an enable bit to lock in that sequence until you get done with the next line. The serial data is timed by an external clock so timing with the serial sequence isn’t important. In fact, I bit-bashed my way through the example code and it worked just fine. The display only shows one line at a time, so you have to be able to scan through the sequence pretty fast. The data sheet has a pretty clear timeline of the sequence of operations, so figuring out the timing shouldn’t hold you up. The only thing that I got hung up on (and still haven’t figured out) is an offset on line addressing, but I’ve worked around it with a 15 line offset.

I also put a bit in the code that allows the Arduino to accept a serial sequence (through the USB port) and it will display that sequence. I tested it using HyperTerminal and it showed the bit-wise ASCII codes for the keys I pressed (so that’s success, right?)

I plan on writing at least one more post about these displays, so look for that in the future.

Here is the Arduino code I used to drive the display:

#define SBaud 9600

#define OE 2 //Out Enable pin
#define Latch 3 //Latch pin
#define CLK 4 //Clock pin
#define GData 5 //Green data pin
#define RData 6 //Red data pin
#define Ad0 8 //Address bit 0 pin
#define Ad1 9 //Address bit 1 pin
#define Ad2 10 //Address bit 2 pin
#define Ad3 11 //Address bit 3 pin
#define Timer 0 //Delay Timer

#define RowMin 0 // Decimal min in row
#define RowMax 15 // Decimal max in row
#define ColMin 0 // Decimal min in col
#define ColMax 15 // Decimal max in col

#define SMax 32 // number of bytes to read from serial

word Display[] = {0x0000, 0x03C0, 0x0FF0, 0x1FB8, 0x3F1C, 0x3F8C, 0x7EC6, 0x7C46, 0x760E, 0x631E, 0x303C, 0x387C, 0x1CF8, 0x0FF0, 0x03C0, 0x0000};
int Di = 0;

int Row = 0;
int Col = 0;

void setup() {
pinMode(OE, OUTPUT);
pinMode(Latch, OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(GData, OUTPUT);
pinMode(RData, OUTPUT);
pinMode(Ad0, OUTPUT);
pinMode(Ad1, OUTPUT);
pinMode(Ad2, OUTPUT);
pinMode(Ad3, OUTPUT);

//Start with all bits low
digitalWrite(OE, LOW);
digitalWrite(Latch, LOW);
digitalWrite(CLK, LOW);
digitalWrite(GData, LOW);
digitalWrite(RData, LOW);
digitalWrite(Ad0, LOW);
digitalWrite(Ad1, LOW);
digitalWrite(Ad2, LOW);
digitalWrite(Ad3, LOW);

//Start the serial monitor
Serial.begin(SBaud, SERIAL_8N1);
Serial.setTimeout(1); //stop checking the port if no data is available after 1 ms

}

void loop() {

//check the serial buffer for data, if there is some, use it
//otherwise continue putting data on the screen
if (Serial.available() > SMax) {
//when enough bytes are available to fill the screen, load them into the image buffer
for (Di = 0; Di <= SMax ; Di++){
if (Di%2 == 1) {
Display[Di/2] = word(highByte(Display[Di/2]) , Serial.read());
}
else {
Display[Di/2] = word(Serial.read() , lowByte(Display[Di/2]));
}
}
for (Di=0;Di<SMax;Di++){
if (Di%2==1){
Serial.print(lowByte(Display[Di/2]));
}
else{
Serial.print(highByte(Display[Di/2]));
}
}
Serial.println(“”);
}

// initialize enable to be high (disable)
// Step 1. Bring both Latch and Enable High to prepare for new data
digitalWrite(OE, HIGH);
digitalWrite(Latch, HIGH);

for (Row = RowMin; Row <= RowMax; Row++){

// Step 2. With Latch and Enable High, set the row address
writeAddress(Row+15);

// Step 3. Enable goes low to activate the display
digitalWrite(OE, LOW);

delay(Timer);

// Step 4. The bitwise data is written to red and green
for (Col = ColMin; Col <= ColMax; Col++){
writeBit(bitRead(Display[Row],Col), 0);
}

// Step 5. After the row is done, bring Enable High and
//Latch Low to set the data for that row
digitalWrite(CLK, LOW);
digitalWrite(OE, HIGH);
digitalWrite(Latch, LOW);
digitalWrite(Latch, HIGH);
}
}

void writeBit(boolean RVal, boolean GVal) {
digitalWrite(CLK, LOW);

if (RVal) {digitalWrite(RData, LOW);}
else {digitalWrite(RData, HIGH);}

if (GVal){digitalWrite(GData, LOW);}
else {digitalWrite(GData, HIGH);}

digitalWrite(CLK, HIGH);
}

void writeAddress(int RowNum) {
if (bitRead(RowNum,0)==1){ digitalWrite(Ad0, HIGH);}
else {digitalWrite(Ad0, LOW);}
if (bitRead(RowNum,1)==1){ digitalWrite(Ad1, HIGH);}
else {digitalWrite(Ad1, LOW);}
if (bitRead(RowNum,2)==1){ digitalWrite(Ad2, HIGH);}
else {digitalWrite(Ad2, LOW);}
if (bitRead(RowNum,3)==1){ digitalWrite(Ad3, HIGH);}
else {digitalWrite(Ad3, LOW);}
}

That was my project day!

If you liked this project, check out some of my others:

Instant Parade!

The ThrAxis – Our Scratch-Built CNC Mill

Give Aging Technology a Chance

Did you like It’s Project Day? You can subscribe to email notifications by clicking ‘Follow’ in the side bar on the right, or leave a comment below.