Calculating hexadecimal values for 7-segment LED on MDA-8086
Asked Answered
W

2

5

I was trying to display 7-segment LED on MDA-8086 kit, but I am stuck at calculating the hexadecimal values for respective digits. I have the code with me, but I don't understand how it actually works. For example, 0 is represented by hexadecimal value 0xc0 [I guess]. I am wondering, how the values have been calculated here?

C Code for 7-segment LED display:

#include"mde8086.h"

int data[11] = { 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x00 };

void wait(long del)
{
    while( del-- );
}

void main(void)
{
    int *data1;

    /* 8255 -1 Initialization */
    outportb( PPI1_CR, 0x80 );
    outportb( PPI1_B, 0xf0 );
    outportb( PPI1_C, 0x00 );

    //main loop
    do {
        data1 = data;
        while( *data1 != 0x00 )
        {
            outportb( PPI1_A, *data1 );
            wait(30000);
            data1++;
        }
    } while(1);
}

The output has been generated from here:

7-Segment display

Woolcott answered 26/8, 2020 at 5:0 Comment(2)
#2671139 check this stackoverflow question. Also check this out #8187465Sommelier
My first thought was that 1 is displayed by lighting only 2 segments total, so we can tell that must be 0xc0 (which only has 2 bits set in its binary representation, so segment b = 0x80, c = 0x40 or vice versa).So looping over this array counts up from 1 to 9 then wraps to 0, I guess. But that doesn't work if you look at the rest; there are other patterns with only 1 or a couple bits set, so it must be that the masks are inverted, and clear bits light up the corresponding segment? Then leaving segment G and the decimal-point unlit could be the top 2 bits.Rambunctious
G
6

This is about how your HW hook-up is, i.e. how the pins of the display is connected to the port and whether it requires a 0 or 1 on the port to turn on a segment.

From your numbers it seems:

  1. The port is connected like g, f, e, d, c, b, a That is: a is LSB.

  2. The "missing" 8th bit shall always be programmed to 1, i.e. as 8 bit it will be port = 1gfedcba

  3. It takes a 0 to turn on a segment in the display.

So

0xc0 -> 1100.000 -> 1    1    0    0    0    0    0    0
                    ^    ^    ^    ^    ^    ^    ^    ^
                    |    |    |    |    |    |    |    |
                unused   g    f    e    d    c    b    a
                        off  on   on   on   on   on   on

which results in a zero on the display.

Now for 0xf9

0xf9 -> 1111.1001

so only segment b and c will turn on and the display will display 1

Check the rest yourself.

EDIT Looking at the sigment picture, it could be that the 8th bit (that I called "unused") is actually controlling the "DP" part of the segment. This is just a guess but maybe if you write 0x40 to the port, you'll see 0. on the display.

When you only display numbers, there are many unused combinations. Some of these look like letters, e.g. H. So for fun (aka an exercise) you can make the display spell words like "HELLO", "CACAO", "BEEF" and many more.

Gainey answered 26/8, 2020 at 5:19 Comment(2)
Wouldn't 0x40 be '0.? Everything lit except for g.Rambunctious
@PeterCordes My bad... yes, it'll be 0. if it's connected as I guess. Thanks for catching and letting me know. :-)Gainey
C
2

I am stuck at calculating the hexadecimal values for respective digits.

Sometime a little macro art is fun and illustrative. It provides a graphical way to define the hex values for data[] rather than doing so by hand.

seven() takes the 3 rows (strings) and looks for -, |, . to form the hex value. When the corresponding segment is off, the value ors in another bit.

#include <stdio.h>

#define seven(r1,r2,r3) (\
/* Seg A */ (r1[1] == '_' ? 0 : 0x01) |  \
/* Seg B */ (r2[2] == '|' ? 0 : 0x02) |  \
/* Seg C */ (r3[2] == '|' ? 0 : 0x04) |  \
/* Seg D */ (r3[1] == '_' ? 0 : 0x08) |  \
/* Seg E */ (r3[0] == '|' ? 0 : 0x10) |  \
/* Seg F */ (r2[0] == '|' ? 0 : 0x20) |  \
/* Seg G */ (r2[1] == '_' ? 0 : 0x40) |  \
/* Seg DP*/ (r3[3] == '.' ? 0 : 0x80) \
)

int datax[11] = { //
    seven( // Zero
    " _ ",//
    "| |",//
    "|_| "),//
    seven( // One
    "   ",//
    "  |",//
    "  | "),//
    seven( // Two
    " _ ",//
    " _|",//
    "|_  "),//
    };

// Remaining digits left for OP


int main(/*int argc, char *argv[]*/) {
  for (int i = 0; i < 3; i++)
    printf("%02X\n", data[i]);
  return 0;
}

Output

C0
F9
A4
Campanology answered 26/8, 2020 at 9:7 Comment(6)
I might have compacted my representations to 3 rows instead of 5, e.g. top row of zero as "|-|". That looks nice for 0 but maybe a lot worse for 2. Still, it keeps the source more compact and is still pretty visually intuitive. (Overall really neat idea, +1)Rambunctious
@PeterCordes Good idea. Maybe "|_|" to push the horizontal segment visually down. What I like about the graphical approach is that it is easy to extend to other 7-segment characters figure 2.Campanology
@PeterCordes Re-coded with a slight variation on you idea. Thanks for the tip.Campanology
Nice, that's even better. The macros could also be r1[1] != ' ' so it's the same character every time, without having to match up the right shape to the right position. It would even be possible to write (r1[1] != ' ') << 0 and so on, but the ternary is probably better for readability than shifting a boolean->int result.Rambunctious
@PeterCordes Re: r1[1] != ' ', I thought of that too, yet with 2 coding choices: with/without negation, I have found the negation-less code easier to maintain. and understandCampanology
Interesting point, that's probably worth the pain of having to get the right symbol for each position.Rambunctious

© 2022 - 2024 — McMap. All rights reserved.