【问题标题】:Calculating hexadecimal values for 7-segment LED on MDA-8086计算 MDA-8086 上 7 段 LED 的十六进制值
【发布时间】:2020-12-14 20:22:25
【问题描述】:

我试图在 MDA-8086 套件上显示 7 段 LED,但我一直在计算各个数字的十六进制值。我有代码,但我不明白它是如何工作的。 例如0用十六进制值表示 0xc0 [我猜]。 我想知道,这里的值是如何计算的?

7段LED显示屏的C代码:

#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);
}

输出是从这里生成的:

【问题讨论】:

  • 我的第一个想法是 1 仅通过点亮 2 个段来显示,所以我们可以看出它必须是 0xc0 (它的二进制表示中只设置了 2 位,所以段 b = 0x80,c = 0x40 或反之亦然)。所以循环这个数组从 1 计数到 9,然后换行到 0,我猜。但是,如果您查看其余部分,那就行不通了。还有其他模式只设置了1个或几个位,所以一定是掩码被反转,清除位点亮相应的段?然后将段 G 和小数点不亮可能是前 2 位。

标签: c x86-16 seven-segment-display


【解决方案1】:

这与您的硬件连接方式有关,即显示器的引脚如何连接到端口以及是否需要端口上的 0 或 1 来打开网段。

从你的数字看来:

  1. 端口像g,f,e,d,c,b,a这样连接,即:a是LSB。

  2. “缺失”的第 8 位应始终编程为 1,即作为 8 位,它将是 port = 1gfedcba

  3. 在显示中打开一个段需要一个 0。

所以

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

这会导致显示为零。

现在0xf9

0xf9 -> 1111.1001

所以只有b段和c段会打开,显示屏会显示1

其余的请自行检查。

编辑 查看 sigment 图片,可能是第 8 位(我称之为“未使用”)实际上控制了该段的“DP”部分。这只是一个猜测,但如果您将 0x40 写入端口,您可能会在显示屏上看到 0.

当您只显示数字时,有许多未使用的组合。其中一些看起来像字母,例如H。因此,为了好玩(又名练习),您可以让显示拼写单词如“HELLO”、“CACAO”、“BEEF”等等。

【讨论】:

  • 0x40 不会是'0. 吗?除了 g 之外,所有东西都亮了。
  • @PeterCordes 我的错......是的,如果它像我猜的那样连接,它将是0.。感谢您捕捉并告诉我。 :-)
【解决方案2】:

我一直在为各个数字计算十六进制值。

有时,一些宏观艺术既有趣又具有说明性。它提供了一种图形方式来定义 data[] 的十六进制值,而不是手动定义。

seven() 获取 3 行(字符串)并查找 -|. 以形成十六进制值。当对应段为off时,值或在另一位。

#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;
}

输出

C0
F9
A4

【讨论】:

  • 我可能已经将我的表示压缩为 3 行而不是 5 行,例如第一行零为"|-|"。这对于 0 来说看起来不错,但对于 2 来说可能更糟。不过,它使源代码更加紧凑,并且在视觉上仍然非常直观。 (总体上非常好的想法,+1)
  • @PeterCordes 好主意。也许"|_|" 可以在视觉上向下推动​​水平段。我喜欢图形方法的地方在于它很容易扩展到其他 7 段字符figure 2
  • @PeterCordes 重新编码,您的想法略有不同。感谢您的提示。
  • 很好,这样更好。宏也可以是r1[1] != ' ',因此每次都是同一个字符,而无需将正确的形状匹配到正确的位置。甚至可以写(r1[1] != ' ') &lt;&lt; 0 等等,但是三元组的可读性可能比转换 boolean->int 结果更好。
  • @PeterCordes 回复:r1[1] != ' ',我也想过,但是有 2 种编码选择:带/不带否定,我发现无否定代码更易于维护。和understand
猜你喜欢
  • 2019-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-29
  • 2012-06-28
  • 2018-08-27
  • 1970-01-01
相关资源
最近更新 更多