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 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]) ,;
else {
Display[Di/2] = word( , lowByte(Display[Di/2]));
for (Di=0;Di<SMax;Di++){
if (Di%2==1){

// 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

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


// 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!

Recommended Posts

A Fun Recipe for Kitchen Chemistry

Chemistry is all around us every day. And now, it’s all over my father-in-laws refrigerator, too. My father-in-law is a chemical engineer and a kitchen chemist in his free time. My wife and I thought that the chemistry equivalent of poetry fridge magnets would be the perfect Christmas gift for him. The concept is pretty simple, find […]


Salvage – It’s Not Just for Sinking Boats

What do you do when your beloved printer, scanner, blender, or remote controlled car breaks? I’m glad you asked because this weeks’ post is about salvage. I’m going to use my experience to help you quickly sift through the junk and help you find the good stuff. sal·vage ( sal-vij )  – To rescue or […]


A Twist to Build a Dream On

Some projects, like this deburring/countersinking tool sit on the back-burner for a long time. Dusting them off to finish the job feels like sharing a meal with an old friend. This deburring tool is a handy way I came up with to reduce the amount of time I spend switching between drill bits and countersinking […]


Leave A Comment