Controlling a tiny 7-segment display

As I was leaving the shop this evening (morning?), I noticed this neat, tiny display thingie in one of the drawers I was returning components to. It had what looked like a row of tiny 7-segment LED displays on it, behind magnifying lenses, and was clearly a pull from some long gone piece of equipment. Not to be one to pass on a good reverse engineering challenge, I decided to hook it up and write a little driver for it.

At about 2″ long, and maybe 3/4″ tall, it seems like the perfect thing to adorn some suspicious baggage or unattended luggage cool project. Anyone have a good idea about what to do with it? It might end up as the display end of an agitator machine, as part of an automated PCB etching setup.

Source code (which could be used to drive any array of 7-segment displays) follows after the break.

// Arduino driver code for a tiny 7 segment display
// By Matt Mets, May 2010
// Public domain
 
// *** Change these to match your system ******************************************
 
// Define which Arduino pins the digit select lines are connected to.
// Note that you can add or subtract pins to match the number of digits your display has.
const uint8_t digitPins[] = {11, 9, 7, 5, 3, 14, 16};
 
 
// Define which Arduino pins the segment select lines are connected to
//     a
//    ___
// f |   | b
//   |___|
//   | g |
// e |___| c  oP
//     d
// {a, b, c, d, e, f, g}
const uint8_t segmentPins[] = {8, 15, 12, 4, 6, 17, 2};
 
// Dot pin
const uint8_t dotPin = 10;
 
 
// *** Display driver code ********************************************************
 
// Lookup table to translate numbers into segment pins.
// This is basically our seven segment 'font'
const uint8_t segmentLookup[] =
                          {0x7e, // 0
                           0x30, // 1
                           0x6d, // 2
                           0x79, // 3
                           0x33, // 4
                           0x5b, // 5
                           0x5f, // 6
                           0x70, // 7
                           0x7f, // 8
                           0x73, // 9
                           0x77, // a
                           0x1f, // b
                           0x4e, // c
                           0x3d, // d
                           0x4f, // e
                           0x47, // f
                           0x00, //   (space)
                           0x01};// - (negative)
 
#define SEGMENT_SPACE segmentLookup[16];
#define SEGMENT_SIGN segmentLookup[17];
 
// Look-up table that maps the bits in the font to display segments
// For example, to determine if segment A should be drawn in a font character,
// logical and (&) the character with segmentPositions[0]
const uint8_t segmentPositions[] = {1<<6, 1<<5, 1<<4, 1<<3, 1<<2, 1<<1, 1};
 
// Buffer to store the current number that is being displayed
uint8_t displayBuffer[sizeof(digitPins)];
 
// Variable that keeps track of which digit is currently being displayed
uint8_t currentDigit = 0;
 
// Draw the next digit in the display
// This function is called when timer2 overflows
ISR(TIMER2_OVF_vect)
{ 
  // Turn off the current digit pin
  digitalWrite(digitPins[currentDigit], HIGH);
 
  // Increment the digit pin
  currentDigit = (currentDigit + 1) % sizeof(digitPins);
 
  // Update the segments to show the proper number for this digit
  for (uint8_t seg = 0; seg < sizeof(segmentPins); seg++) {
    digitalWrite(segmentPins[seg], displayBuffer[currentDigit] & segmentPositions[seg]);
  }
 
  // Turn on the new digit pin
  digitalWrite(digitPins[currentDigit], LOW);
}
 
 
// Display initialization
void setupDisplay() {
 
  // Initialize all of the pins
  for (uint8_t i = 0; i < sizeof(segmentPins); i++) {
    pinMode(segmentPins[i], OUTPUT);
    digitalWrite(segmentPins[i], LOW);
  }
 
  for (uint8_t i = 0; i < sizeof(digitPins); i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], HIGH);
  }
 
  // Clear the display buffer
  for (uint8_t i = 0; i < sizeof(digitPins); i++) {
    displayBuffer[i] = SEGMENT_SPACE;
  }
 
  // Set up Timer 2 to generate interrupts on overflow, and start it.
  // The display is updated in the interrupt routine
  TCCR2A = 0;
  TCCR2B = (1<<CS22)|(0<<CS21)|(0<<CS21);
  TIMSK2 = (1<<TOIE2);
}
 
 
// Display a (signed) number
// Returns false if the number couldn't fit
boolean displayNumber(long number) {
  // Temporary buffer to store our results
  uint8_t outputBuffer[sizeof(digitPins)];
  for (uint8_t i = 0; i < sizeof(digitPins); i++) {
    outputBuffer[i] = SEGMENT_SPACE;
  }
 
  // Store off the sign of the number
  boolean isNegative = (number < 0);
  number = abs(number);
 
  // Start filling from the right of the display
  int8_t bufferLocation = sizeof(digitPins) - 1;
 
  // Fill the output buffer from the right by dividing by ten and storing the
  // remainder to the display.
  while (bufferLocation >= 0 && number > 0) {
    uint8_t temp = number % 10;
    number = number / 10;
 
    // Pre-compute the segment value to save time during the interrupt
    outputBuffer[bufferLocation] = segmentLookup[temp];
 
    // and decrement the buffer location
    bufferLocation -= 1;
  }
 
  // We've filled as much of the buffer as we can by now.  If there is a remainder,
  // stop now and return false.
  if (number > 0) {
    return false;
  }
 
  // The last thing we need to check is if we need to draw a negative sign.
  if (isNegative) {
    // If there isn't space in the buffer, bail
    if (bufferLocation < 0) {
      return false;
    }
 
    // Otherwise, draw in the negative
    outputBuffer[bufferLocation] = SEGMENT_SIGN;
  }
 
  // We've made it, so copy out the buffer and return success.
  for (uint8_t i = 0; i < sizeof(digitPins); i++) {
    displayBuffer[i] = outputBuffer[i];
  }
 
  return true;
}
 
 
// *** Sample program *************************************************************
 
void setup() {
  setupDisplay();
}
 
long i = -99000;
 
void loop() {
  // For an example, count up from -99000
  displayNumber(i);
  delay(1);
  i++;
}
This entry was posted in tech. Bookmark the permalink.

7 Responses to Controlling a tiny 7-segment display

  1. Hi

    Thanks for posting your code on this display.

    Could you please confirm, is this is a common anode display?

    Thanks

    • mahto says:

      I think it is actually common cathode… I am setting the digit pin (the common one) low to turn it on. To make this work for common anode, you I think you would just need to invert the output logic, so switch the
      digitalWrite(digitPins[currentDigit], HIGH);
      and
      digitalWrite(digitPins[currentDigit], LOW);
      lines,
      and replace:
      digitalWrite(segmentPins[seg], displayBuffer[currentDigit] & segmentPositions[seg]);
      with
      digitalWrite(segmentPins[seg], (~displayBuffer[currentDigit] & segmentPositions[seg]));

      Let me know if that works for you :-)

  2. MHG says:

    This is very amazing display.
    would you please provide the part number or any furthure information, so I can buy some sample.

  3. Wes says:

    That is from the TI mba calculator. I have one!

  4. ubi de feo says:

    so funny
    I was searching for tiny 7digit displays and bumped into this.
    I just scavanged one of those screens from an old Continental 1800a

    they’re really cute, and it was easy to figure out how to drive them, since they keep the standard A-…-G + H(dp)

    I’m quite unhappy with the 9th digit missing, though ;)

    happy hacking
    ubi

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>