Stock Bot – about the 4511 BCD to 7-segment decoder

Not to be trite but you may learn more here wikipedia.org, than here.  This post is intended to fill in some of the background of how the 4511 chip was used in the Stock Bot project.  Let’s dive in and see if it remains coherent.  The chip is designed (I presume) to enable one to use fewer data lines to drive a 7-segment display.  LED displays are common while the one in Stock Bot is a little less so.  A seven segment display has 7 inputs one for each light element.  You would need 7 data lines to drive a single digit and much more to drive additional digits.  This project does not use the data latching features that enables several 4511 chips to drive several digits while keeping the data line count to a minimum.  When you scale the number of digits you really save on data lines and the value of the chip becomes evident quickly.  To be brief, several digits can be managed (like a clock) by locking the currently displayed value into each chip and then unlocking only one digit at a time to effect a change to that digit.  Quickly locking and moving on, unlocking change lock, continue.  If that made any sense you got the idea.  Do this fast enough and large multi-digit displays can be managed – again with 4 data lines and the latch control logic.

Driving the single chip was a fun code experiment.  So let’s look at that.  Like I said on the Stock Bot page I had to learn (re-learn/hack in) C# for this.  When you drive the chip you are essentially sending it a binary code along 4 digital lines.  A 4 line data bus I guess.  Given an integer from 0 to 9 convert, that to binary or otherwise figure out how to set your 4 data pins correctly.

A set of if statements would do that.  A switch statement would do that.  Both I tried as I had to get something started.  Neither felt clean enough to me (don’t get me wrong some of the code is still too ugly to even tell you about yet/ever).  So I worked out what I have below because I knew in my mind something cleaner should exist.  Your improvements are welcome as comments.

    // helper class
    class BCDOutputClass
    {
        byte mask1 = 1;
        byte mask2 = 2;
        byte mask3 = 4;
        byte mask4 = 8;

        OutputPort Bin1 = new OutputPort(Pins.GPIO_PIN_D9, true);   // A
        OutputPort Bin2 = new OutputPort(Pins.GPIO_PIN_D12, true);  // B
        OutputPort Bin3 = new OutputPort(Pins.GPIO_PIN_D11, true);  // C
        OutputPort Bin4 = new OutputPort(Pins.GPIO_PIN_D10, true);  // D
        OutputPort CommaPin = new OutputPort(Pins.GPIO_PIN_D13, false);

        // Constructor
        public BCDOutputClass()
        {
            //
        }

        // Instance Method
        public void Display(byte a)
        {
            a = (a < 10)? a : (byte) 10;
            Bin1.Write((a & mask1) > 0);
            Bin2.Write((a & mask2) > 0);
            Bin3.Write((a & mask3) > 0);
            Bin4.Write((a & mask4) > 0);
        }

        public void Clear()
        {
            Display(10);
            Comma(false);
        }

        public void Comma(bool a)
        {
            CommaPin.Write(a);
        }

        // Destructor
        ~BCDOutputClass()
        {
            // Some resource cleanup routines
        }
    }

Most of this becomes clear if I just talk about the meat of the code in public void Display(byte a).  Maybe not but let’s start there as it is the crux of what makes this (IMHO) better over an if or switch statement.  I have, of course, not tried to figure out if this compiles to smaller code or not – that’s not a concern I have any interest in yet.

The function takes in a byte – the code when running sends in the values zero to 10 when all is normal.  10 is an exception and I should explain that first as the line first executed is a test for values over 10 and if over we revert a to 10. 10 in binary is 1 0 1 0.  Setting the 4 pin data bus to an invalid value.  1 0 1 x (where x means it’s not important) happens to BLANK the display.  This makes the code in the function public void Clear() fairly obvious now why it sends a 10 to Display().

The 4 pins how do they get set?  ok, let us use the digit 9 and now step through the rest of the function.  Pin 9 on the Netduino is connected to A or D0 on the 4511, the lowest order bit (ones). 12 is to B or the twos, 11 is to C or the fours and pin 10 to D the highest order bit the eights.  You can look to the mask declarations to get a feel for the positions too.

9 is binary 1 0 0 1

We need to set line A to true, line B to false, line C to false and line D to true.

(a & mask) what does that do?  “a” is type byte and mask1 is of type byte.  The & says do a bitwise AND of the two values.  What’s a bitwise and – (for now – Google it) but I’ll do the math here and might get it across.

1 0 0 1  (9)
0 0 0 1  (mask1)
-------  bitwise and says 1 only when all are one
0 0 0 1 (1)
Result = 1

1 0 0 1  (9)
0 0 1 0  (mask2)
-------  bitwise and says 1 only when all are one
0 0 0 0 (0)
Result = 0

1 0 0 1  (9)
0 1 0 0  (mask3)
-------  bitwise and says 1 only when all are one
0 0 0 0 (0)
Result = 0

1 0 0 1  (9)
1 0 0 0  (mask4)
-------  bitwise and says 1 only when all are one
1 0 0 0 (8)
Result = 8

Let’s take the results of the first operation.  We got a 1.  There’s more in that line of code (a & mask1) > 0

Greater than zero completes a comparison.  Results in a boolean.  True or False.  The first part will result in a zero when we need a false result and a true value when the result is anything else 1 or above.  In the case, we just ran through, we had a 1 and an 8, both greater than zero, and so had two lines (the first and last) set to true.

By now you’ve either gone Aha! or Duh or are scratching your head.  Either way I am done for now 🙂 enjoy.