Monday, May 25, 2020

Hacking Salvaged LED Displays (Part 1)

You can buy many kinds of standard 7-segment displays, but I prefer hacking salvaged ones you can find in broken e-waste. True, it's easy to buy displays with integrated drivers that make them much easier to connect to a micro-controller and program, but more often than not I end up finding components and making up projects for them, rather than the other way around. In this post I'll show how I salvage a standard single digit 7-seg display, figure out the pinout, and make it do some fun things. In a following post I'll show how I do the same with a more complicated, non-standard, multi-digit salvaged display.

Remove the Display

Once you get the board out that contains the display you can see what you're in for. Sometimes the pins are long enough you can just clip them like on this answering machine digit I'm working with here. Even so I went ahead and took the hard road and desoldered it, shown in the next step.
While this digit only has 8 pins some displays can have dozens of pins to desolder from the board. If you can get most of the solder away from the pins so you can see the hole around the pad that should be enough to wiggle each pin loose and when enough are loose you can start wiggling the whole thing free.

Figure out the pin arrangement

Occasionally the display will have a serial number you can look up to find a datasheet. I tried with this one and didn't come up with anything so it's on to the next step, figuring out what pins control what.


A single digit LED display is just 7 LEDs in a parallel circuit. They all share a common pin that is either the cathode (negative) or anode (positive) voltage in the circuit. So you connect a 3V battery to a breadboard and connect one positive and negative lead to pairs of the digit pins until something lights up. Then you look for a pattern until you can find out which is the single shared pin and whether it is the anode or the cathode.  In this case the anode is the common pin and the other 7 are cathodes. You don't necessarily have to but I added a 220 ohm resistor to the anode because the AA batteries were quite strong. 


It is always a good idea to make a drawing of the pinout once you find it, which will make it easier to configure the pins in code.


Arduino Code

Next step is moving the circuit to an Arduino. I used the diagram above to configure a pin layout that matches up segment 1 on top to Arduino pin 2, segment 2 going clockwise to Arduino pin 3, and so on. Instead of putting a single resistor on the common pin it will be better to put a resistor on each cathode. 
The first thing to do in Arduino code is get all the segments to light up. Once the pin variables are defined I put the pin names in an array. This will make it easier to create patterns through loops in various functions. The first place to use the array in a loop is in setup, to set the pinMode for all the segments. The for loop looks more complicated than it should, but simplest way to get the number of elements in an array in Arduino is to divide the array by the size of one element in the array.
One more thing about this code, since this 7-segment digit is common anode that means any segment we want to light up has to go LOW while the common pin goes HIGH. Any segment we want to turn off has to go HIGH so there is no voltage potential between the segment in and the common pin.

//common anode 7-segment
const int seg1 = 2; //cathodes
const int seg2 = 3;
const int seg3 = 4;
const int seg4 = 5;
const int seg5 = 6;
const int seg6 = 7;
const int seg7 = 8;

const int digit = 9;  //anode
//put the segments in an array to use more easily later
const int segments[] = {seg1, seg2, seg3, seg4, seg5, seg6, seg7};

void setup() {
  //use the array to set them OUTPUT
  for (int i = 0; i < sizeof(segments) / sizeof(segments[0]); i++) {
    pinMode(segments[i], OUTPUT);
  }
  pinMode(digit, OUTPUT);
}

void loop() {
  //use the array to set them all LOW
  //segments go LOW for on because they are cathodes
for (int i = 0; i < sizeof(segments) / sizeof(segments[0]); i++) {
    digitalWrite(segments[i], LOW);
  }
  //set the digit to HIGH, since common anode
  digitalWrite(digit, HIGH);  
}

Create Useful Functions

Once I have a useful block of code, like this for loop that turns on all the segments, I usually move it to its own function so it's easy to use it from the main loop.
void on() {
for (int i = 0; i < sizeof(segments) / sizeof(segments[0]); i++) {
    digitalWrite(segments[i], LOW);
  }
  digitalWrite(digit, HIGH);    
}

More fun

With a couple modifications the on pattern above can be changed to make a fun pattern like a snake zipping around. First I make a new array of segments in the order they will light up in, and place it at the beginning of the function. In the middle of the for loop each segment in the array turns on (LOW) and after a short delay turns off (HIGH).


void snake() {
  const int pattern[] = {seg1, seg2, seg7, seg5, seg4, seg3, seg7, seg6};
  digitalWrite(digit, HIGH); 
  for (int i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) {
    digitalWrite(pattern[i], LOW);
    delay(100);
    digitalWrite(pattern[i], HIGH);
  }   
}

Numbers

7-segment displays are made for numbers so let's put some numbers on it. If we were using a module like that linked above numbers would be very easy. If we wired it up through a driver IC like a HEF4794 (common anode) or a MAX7219 (common cathode) we could do the same. But we're not so first we have to create segment maps for the numbers. 
To do that we make a 2D array, an array of 10 numbers, each an array itself. The array for each number contains a series of 1's and 0's that will register as HIGH or LOW when mapped to the sequence of pins in a function below. 
const int numbers[10][7] = {
  {0, 0, 0, 0, 0, 0, 1}, //0
  {1, 0, 0, 1, 1, 1, 1}, //1
  {0, 0, 1, 0, 0, 1, 0}, //2
  {0, 0, 0, 0, 1, 1, 0}, //3
  {1, 0, 0, 1, 1, 0, 0}, //4
  {0, 1, 0, 0, 1, 0, 0}, //5
  {0, 1, 0, 0, 0, 0, 0}, //6
  {0, 0, 0, 1, 1, 1, 1}, //7
  {0, 0, 0, 0, 0, 0, 0}, //8
  {0, 0, 0, 0, 1, 0, 0} //9
};

Now here in this function we use a nested loop to light the segments for each number, one at a time.

void count() {
  digitalWrite(digit, HIGH);
  for ( int j = 0; j < sizeof(numbers) / sizeof(numbers[0]); j++) {
    for (int i = 0; i < sizeof(numbers[0]) / sizeof(numbers[0][0]); i++) {
      digitalWrite(segments[i], numbers[j][i]);
    }
    delay(200);
  }
}

No comments :