HexOut (3/3)

A 16 bit hexadecimal display module.


This is part 3 of a three-part series. You can find part 1 here, and part 2 here.

We’ve arrived at the conclusion of the HexOut series. Here we look at the bottommost layer, which handles input. If you’ve read the first two articles, you’ll know that the top layer is Display, and the middle layer is Output. The Input layer takes the (up to) 16-bit wide signal from any source you like, and encodes it into a pattern of bits that will illuminate the segments on the displays that represent that bit pattern in hexadecimal. That bit pattern is then sent serially up to the upper layers for display. So let’s see what makes the Input layer tick.

Here again is the final product. It takes an 8-bit or 16-bit wide binary input, and translates that into a hexadecimal value. The top Display layer is just four seven-segment displays connected to a header. The middle Output layer takes an encoded stream of bits from the Input layer and pushes them up to the displays on top.


The Input layer is the most interesting, I think. This is where the brains of the operation are, so to speak. Here’s the schematic (and Eagle file):

Look! It's my favorite little chip of all. The ATTiny 13A. Is there anything it can't do?

You may recall from the previous articles that I went to quite a few lengths to save signal pins. Now you can see why- this device is driven by an ATTiny13A, and pins are precious indeed on this little guy. It does a bang-up job for us here, though, so it’s a small price to pay. You’ll also notice two chips that you don’t see much of in most hacks- the 74HC597. The sexy supermodel sister of this chip is the 74HC595; it gets all the attention because it’s useful for driving blinky lights.The 74HC597 is essentially the opposite- it takes a wide parallel input, and shifts it serially into a single bit output. It can do a couple of other tricks that the 595 can’t, but for our purposes, this is just the thing.

The basic operation here is simple. The 16-bit wide input bus is connected to the 597 shift registers. The microcontroller regularly reads the input bus by latching the registers, then shifting the contents into itself. The software then processes these bits into hexadecimal letters represented by seven-segment displays. Those display bits are then sent back out, and up to the Output layer above. This cycle is repeated at around 8Mhz. At this frequency, changes on the input bus can be detected faster than data changes on stuff I ever build (for now, anyway). That gives the illusion of sniffing changes on the bus instantly, when in fact we’re actually just sampling it at a high rate.

Okay, so does this all work? Let’s go to the breadboard to find out:

Looking good! On the breadboard there, you can see the ATTiny and one of the 74HC597 shift registers. Like the other layers, I only simulated half of this one, since the other half is identical. At the point this photo was taken, I had already completed the upper two layers, and only the Input layer remains on the breadboard, ready to be built for real. I tested the Input layer using a bank of pull-up resistors on DIP switches, which you can see on the smaller outboard breadboard. Outboard breadboard? That's a mouthful.


With the basic design ready to go on the breadboard, it was time for some software. As usual, I busted out the USBtinyISP programmer, my BreadHead programming header, and got to work. Here’s the code I came up with:

[iframe_loader src=”http://pastebin.com/embed_iframe.php?i=7i7HqwyT” height=”600″ scrolling=”yes” marginheight=”50″]


The main loop reads the bits from the input registers, clocking them as many times as needed. Those bits are stored in an accumulator. Once that’s done, the accumulator is broken out into four nibbles, which are used as an index into the hexadecimal “font” used on the displays. This lookup gives the output bit pattern, which is then sent serially to the Output layer.

At the end of this cycle, there’s one extra clock pulse. That pulse is needed to finish the shifting of the Output bits. You may recall from part 2 that I’m using a trick with the 74HC595s whereby I tie the two clock signals together to save a pin. This means that an extra pulse is needed at the end to finish displaying, since the latch clock is one pulse behind the shift clock. This might have been tricky to handle in the logic, but in code it’s a trivial fix! That’s one of the great things about straddling the software/hardware boundary in projects like this. You can solve each problem in whichever domain is easiest.

Similarly, you’ll note that the function to push the font bits to the display is reversing them. This is because, as you may recall, I’m using common-anode displays driven by 74HC595 shift registers on the output. This makes them effectively active-low. That’s easy to compensate for here in the software. Again- solving each problem in whichever domain is easiest.

Okay, it’s PCB time!

Pretty straightfoward stuff here. As always, the red traces are topside jumpers. The big header on the left is the input bus. The little header up top (JP3) is power for the whole device. The middle header (JP4) connects up to the Output layer. The switch is for powering the device on and off.

I used that Eagle file to generate photo-developer masks:

The Input layer is the middle pair of masks. I always make two of each and overlap them during exposure to compensate for any flaws in the printing.

Then I exposed the presensitized PCB, developed it, and etched it with my usual process:


Next, it’s drilling and jumper time. Sometimes I can’t get a contiguous ground plane on my PCB, so I bridge the chunks with some bare jumpers.

I get a little better at the drilling each time I do this.
Here we are, fully populated and ready for ICs.
Well, almost ready. I somehow always manage to forget one jumper somewhere when laying out the PCB. A little underside hackery to the rescue, once again.

With the board all built, it’s time for final test. No problem, right? It worked on the breadboard, and the PCB has no errors, so it will surely work, right? Right?

Bzzzzt. Fail.  With the complete board stack all hooked up, the display was not responding properly to inputs. It was outputting ‘0000’, no matter what the inputs given. This is where the modular design approach that I took really paid off. The upper two boards had been tested in isolation, and were known to work. So the problem had to lie in this new one. There were two possible problems- either the input bus was not being read properly, or the microcontroller was sending the wrong bits out to the display.

I eliminated the latter possibility by commenting out all the input processing code, and hard-coding a known bit pattern into the accumulator. When I did this, everything seemed to work perfectly. That narrowed the problem to the bits coming from the 74HC597 shift registers into the microcontroller. It’s logic analyzer time!


This was a great excuse to use this bad boy, which I got for a great deal on eBay. You may mock me for building what is essentially a very primitive logic analyzer, when I have a real one on my bench, but remember folks- it's the journey, not the destination.

The logic analyzer revealed that the correct data was coming out of the shift registers and going into the microcontroller, but the bit patterns coming out the other side were always the ‘0’ in the font. The green line on the scope is the output pattern. You can see one whole nibble, plus a bit of the next one. That’s the pattern to show a zero on the display. The red line is the input bits from the 74HC597 registers, and you can see that is clearly not a string of 0 bits. That could mean only one thing- the microcontroller was ignoring the input data! A quick look at my pin configuration in the source code revealed that I had neglected to set that data pin on the ATTiny as an input! How did this ever work on the breadboard? Well, just before programming the final chip, I did a little “clean up” on the code, and messed up one of the C macros which label the I/O pins. Whoops!

Here's a final test of the whole unit, once again showing the most delicious of all bit patterns, 1011111011101111
Here's a close-up showing the relationship of the three layers. One big mistake I made in the design is not allowing room for standoffs in the corners. I put them on the corners where there was room, but I had to rely on clamping force with some washers in one spot (back left corner in this photo). The "missing" corners aren't entirely needed because the header connections between boards hold those areas securely. I'll definitely fix this in the next version, though.

That’s HexOut! I have a feeling it will come in quite handy in my upcoming digital design projects. Thoughts? Snide remarks? Head on down to the comments below.






37 thoughts on “HexOut (3/3)

  1. bEEF! I appreciate that you showed the whole process, including the mistakes. Do you think you’ll put it in an enclosure, or will you use it as-is?

    1. I think I’ll use this version as-is for now. Most things I build seem to need a couple revisions before they really settle down into something really robust and useful. I don’t want to spend the time to polish it up until I know how it performs long term.

  2. Aren’t there any direct binary-to-7-segment-decoders? Single Board Computers like the KIM and the AIM must have used them, one would think, for their hex displays. With google I find lots of BCD-to-7-segement decoders (74LS47, 4511) and some solutions with PICs for binary. For 1010-1111 they display either blanks or weird characters. However, it would be relative simple (but tedious) to re-create a proper decoder in some 2-level AND/OR logic, with the desired outputs for 1010-1111.
    (Actually, looking at the source code of the KIM-1 monitor, kim_mon.asm, it appears that the display conversion is done in software too…)

    1. That was my thought also- there MUST be a one-chip solution to this problem. There are tons of them for displaying decimal. However I only found one chip that does hexadecimal-on-seven-segment-display decoding, but it was no longer available anywhere, and looks like it hadn’t been manufactured in 15 years. I’d love to hear if there’s a simpler way to do this, because while my way was fun to build and educational, it was more work than it seems like it should be. A big microcontroller with enough pins could do this directly, but that seems like massive overkill. Most of the hardware in my design is just to compensate for the lack of I/O pins on the ATtiny.

        1. That’s a really good idea! Effectively a permanent remapping table. I’m not tooled up for using EEPROMs, but maybe I should be.

          1. I’ve actually designed some glue logic that bridges straight from a nibble to a seven segment digit display, and includes hex characters. The 4511 is actually pretty simple to reverse engineer. You could load four of the logic sets onto a 90 cent PLD (i’m thinking maybe an Altera Max V) and have a straight 16 bit to hex converter on only a single board.

      1. I was thinking of solutions to this problem (which is how I came across your page) and have settled on using multiple PIC 16F54 chips, one per digit, to do tbe decode. It seems over the top but each chip is 50p (~70 cents) so its the cheap and simple option, and it fits in with the ‘retro’ look i’m going for, but it does grate using a computer to replace what is in essence a 16 byte prom!

        1. I know just what you mean- I often find myself using a uC for something trivial because they’re so darn cheap and effective, then feeling guilty about it. 🙂

  3. There is another “brute force” method to do this too, and I’m guilty of it. You can use a 4 line to 16 line decoder (or a pair of 3 to 8 decoders) and a bunch of diodes to form a ROM matrix. It will need quite a few 1n4148’s or 1n914’s but they are only pennies each.

    1. I like that- a hardware lookup table! I actually want to try that now. 🙂 it’s arguably simpler than what I did.

      1. Simpler maybe if you don’t have an eprom burner or any way to program a small micro. But it would probably take up more board space.
        I remember back in the ’70s a friend of mine built a clone of the Altair/Imsai S100 computer and did most of the front panel using “Diode Logic” to eliminate many of the redundant gates. Good for low speed but would have failed above a few mhz.

  4. wow, cool… interesting way to do it.
    I made some code to build rom tables, I have a rom image that will take 8 bits in and output them, multiplexed, to two 7 segment displays… I think it might take up less board space… not sure… I’m playing with FSMs… I should mod my code to be able to make the 2M images that would be needed to turn 16bits+2select into 4 way muxed 7 segment… then again, could just use a 16bit rom, 1M would do it… dip40?

  5. I wonder if using an ATtiny24 for each digit would work. Those are 14-pin devices, and aside from Vcc, GND and Reset, you’d have exactly enough pins for 4 inputs and 7 outputs.

  6. Why ‘597 shift registers instead of ‘165s? Any particular reason, or you just happened to have ‘597s on hand?

    1. The answer to that would normally be “because I had them”, but in this case I did actually buy those for the project. Not sure why I chose the ‘597s- it’s probably what came up when searching for parallel-in shift registers on DigiKey or Mouser. Glancing at the data sheets, the ‘597s do have a more convenient pin layout than the ‘165s do, but the ‘597s might be obsolete? I’m not sure what the other differences off hand.

  7. Should PB5/RESET be pulled up with a resistor, rather than directly to VCC? Won’t there be a short (even if just a momentary one) when the programmer tries to pull RESET low without one?

  8. Yah, there probably should be a resistor there. The chip was never programmed in this circuit, it was just stuck in there after it was done, so it wasn’t an issue. I think the data sheet says you can leave RESET floating when not needed. Not certain about that though- haven’t looked in a while.

    1. I wasn’t so much worried about floating RESET as I was shorting VCC to GND through the programmer when the programmer tried to pull RESET low. This, of course, may be an unfounded fear, as the programmer may be pulling it low through some magical means that I don’t understand.

      1. Yep, I hear ya. What I meant to say is that it wasn’t a problem because the programmer wasn’t attached to this circuit. The chip was programmed on its own.

  9. Was reading Hardware Interfacing with the Apple II Plus by John E Uffenbeck. On Page 42 he talks about using DM9368’s (for common cathode displays) which are a 4bit latch and hex decoder all in one package (16pin dip) . These are available on eBay for 5 beans a piece.

    1. Working on a project of my own and needed a binary input hex display. Fortunately I have a few DM9368 units lying around. Made it with an 8 bit input and a jumper to slect dynamic display or triggered(latched). Displays are easy enough to get, but socketed the binHEX decoders just in case I want to use them elsewhere. Green wires are inputs, red/black are power, and yellow are display drivers. Simple to build and works like a charm. Downside is that these are TTL parts and draw lots of power. I left some space on the board in case I want to add a buffer later. The board is one of the simple prefab pieces with lengthwise traces running through. Drilled the traces where I needed them to stop. Plenty for this project.



  10. The TIL-311 (available from Jameco) is an LED display and binary to 7-segment decoder all in 1. The big downside is that they are $20 each. They are also power hungry and can get hot to the touch.

    1. Those are very cool units, but as you say, the price is a little nuts. Too bad, because I’d like to give those a try.

    1. At a glance, I’d say probably not. That seems to be a binary-coded-decimal driver, whereas we need hexadecimal here. Thanks for the thought, though!

  11. Oh really? That’s interesting! The chip in the diagram is described as a BCD converter, so I assumed it was only handling bit patterns 0000 – 1001. I’ll take a closer look at that.

    1. Yeah, I guess that does sound a little misleading. Sorry. Anyway, it’s a pretty simple program;

      Good luck. Have fun. Cheerful regards, Mike

      ; // psuedo C code program example
      ; char segdata [] = { 0b00111111, // “0” -|-|F|E|D|C|B|A
      ; 0b00000110, // “1” -|-|-|-|-|C|B|-
      ; 0b01011011, // “2” -|G|-|E|D|-|B|A
      ; 0b01001111, // “3” -|G|-|-|D|C|B|A
      ; 0b01100110, // “4” -|G|F|-|-|C|B|-
      ; 0b01101101, // “5” -|G|F|-|D|C|-|A
      ; 0b01111101, // “6” -|G|F|E|D|C|-|A
      ; 0b00000111, // “7” -|-|-|-|-|C|B|A
      ; 0b01111111, // “8” -|G|F|E|D|C|B|A
      ; 0b01101111, // “9” -|G|F|-|D|C|B|A
      ; 0b01110111, // “A” -|G|F|E|-|C|B|A
      ; 0b01111100, // “b” -|G|F|E|D|C|-|-
      ; 0b00111001, // “C” -|-|F|E|D|-|-|A
      ; 0b01011110, // “d” -|G|-|E|D|C|B|-
      ; 0b01111001, // “E” -|G|F|E|D|-|-|A
      ; 0b01110001 }; // “F” -|G|F|E|-|-|-|A
      ; void Main()
      ; { static unsigned char digsel = 0; // digit select, 0 or 128
      ; CMCON = 7; // turn comparator off
      ; TRISA = 255; // Port A all inputs
      ; TRISB = 0; // Port B all outputs
      ; while(1) // loop forever
      ; { unsigned char work = porta; // sample inputs
      ; if(digsel) // if left (hi) digit
      ; work /= 16; // use hi nibble, 0..F
      ; else // otherwise
      ; work &= 15; // use lo nibble, 0..F
      ; work = segdata[work]; // get segment data
      ; work |= digsel; // pick up digit select bit
      ; PORTB = work; // update the display
      ; DelayMS(8); // ~60 Hz refresh rate
      ; digsel ^= 128; // toggle digit select bit
      ; } //
      ; } //

      1. Yup, that’s how the current code works as well- it just has the extra house-keeping needed because I’m shifting the bits in and out of the ATtiny serially to conserve pins.

        1. Yes ma’am, I saw that.

          Anyway, just for fun I made a paper silkscreen for the two chip solution on a Radio Shack prototype board (sku 276-149). The displays are some non-mux’d dual-digit 0.56″ units I have laying around. http://forum.allaboutcircuits.com/attachment.php?attachmentid=52095&d=1360830164

          If anyone is wondering what a paper silkscreen looks like, here’s an example; http://forum.allaboutcircuits.com/attachment.php?attachmentid=42495&d=1335897391

          Cheerful regards, Mike

    1. I think it could be implemented in a lot fewer parts, frankly, and if I were to redesign this, I think version 2 would be a lot better. Nevertheless, it does work as shown, and I use it very often.

      One thing to note- I think there’s a power switch marked in the schematics. I would leave that out, because it is having no effect in the circuit. This was an early design for me, and I didn’t understand how to properly control power in a digital logic circuit connected to another circuit. If you turn the power switch off, the chips just power themselves internally from the input signals, and the HexOut continues to operate. I’d need to rethink the way that switch is wired.

  12. Very useful, thanks for the idea. I made my own:


    Massively overkill, it uses an atmega1284p since I had some lying around, but it works well. I needed it to debug my Z80 project.

Comments are closed.

Mini Cart 0

Your cart is empty.