5.动态数码管实验

时间:2024-04-13 19:38:03

#include "reg52.h"

typedef unsigned int u16;    //对系统默认数据类型进行重定义
typedef unsigned char u8;

#define SMG_A_DP_PORT    P0    //使用宏定义数码管段码口

//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void main()
{    
    SMG_A_DP_PORT=gsmg_code[0];//将数组第1个数据赋值给数码管段选口
    while(1)
    {
           
    }        
}

代码解析

#include"reg52.h"

程序的主要部分包括数据类型的定义、宏定义、数码管显示数据的数组定义以及主函数的实现。

  1. 数据类型定义:

typedef unsigned int u16; // 将unsigned int类型简写为u16

typedef unsigned char u8;   // 将unsigned char类型简写为u8

这里使用了typedef关键字来定义新的数据类型别名,使得代码更加简洁易读。

  1. 宏定义:

#define SMG_A_DP_PORT P0 // 定义数码管段码口为P0口

通过宏定义,将数码管的段码口定义为P0口,这样在程序中就可以直接使用SMG_A_DP_PORT来代表P0口,提高了代码的可读性和可维护性。

  1. 数码管显示数据数组定义:

u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

这是一个包含了0到F共16个数字的段码数组。每个数字对应一个段码值,这些值是数码管显示相应数字时需要设置的段选信号。

  1. 主函数实现:

void main(){     SMG_A_DP_PORT=gsmg_code[0]; // 将数组第1个数据(数字0的段码)赋值给数码管段选口    

while(1) // 无限循环  

  {        // 这里可以添加其他代码,用于实现动态显示或其他功能    

}

}

在主函数中,首先将数组中第一个元素(即数字0的段码)赋值给数码管段选口P0。然后进入一个无限循环,这个循环中可以添加其他代码来实现更复杂的功能,比如动态显示不同的数字或者其他控制逻辑。

注意事项:

  • 该程序是基于静态显示设计的,如果要实现动态显示,需要添加相应的动态扫描逻辑。
  • 该程序只显示数字0,如果需要显示其他数字或字符,需要修改赋给SMG_A_DP_PORT的数组索引值。
  • 该程序没有考虑数码管的位选信号,如果数码管有多位,需要添加位选信号控制逻辑。
  • 在实际应用中,可能需要考虑消抖和延时等处理,以确保数码管显示稳定。

数码段的计算原理 

    在实际编程中,基本采用一种类型数码管显示即可,默认都是选择共阴数码管,也就是我们需要让开发板输出电压为高电平,点亮对应的数码管。

    在上面的字母对应的七段数码管中,要显示0-9,需要的电平如下所示:

a

b

c

d

e

f

g

字形

所需字母数码段

1

1

1

1

1

1

0

0

abcdef

0

1

1

0

0

0

0

1

bc

1

1

0

1

1

0

1

2

abdeg

1

1

1

1

0

0

1

3

abcdg

0

1

1

0

0

1

1

4

bcfg

1

0

1

1

0

1

1

5

acdfg

1

0

1

1

1

1

1

6

acdefg

1

1

1

0

0

0

0

7

abc

1

1

1

1

1

1

1

8

abcdefg

1

1

1

1

0

1

1

9

abcdfg

    光这个表,看不出要怎么设置引脚的电平高低,但是我们可以通过代码中的值来反推这个表,一般我们的代码中可能有这样一个表示显示数字的数组:

unsigned char led[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

    这一组数据,其实对应上面共阴数码管表,可以这么理解,把数码管的g,f,e,d,c,b,a七个段,外加一个0位,正好组成八位二进制,其中0对应0x3f,就是0011 1111,正好对应上面表格中的按照顺序1111 110反过来的表示。1对应0x06,也就是0000 0110,同样对应上面表格0110 000反过来的表示。后面都是类似的规律。显示数字8,全部点亮,也就是1111 111,反过来二进制表示就是0111 1111,正好对应十六进制0x7f。

理解了这些规律,再反过来理解数码管的显示,其实就不难了。

注意:当这个程序中没有while(1)时,这个0会迅速闪到其他数码管上然后消失

、经过询问chatgpt后发现确实,如果没有while(1)循环,显示在8051单片机程序中通常也是持续的。这是因为在大多数嵌入式系统中,一旦某个输出(如数码管的段选信号)被设置,它会保持该状态,除非程序再次改变它。

在您的代码中,SMG_A_DP_PORT = gsmg_port[0];这行代码将数码管的段选信号设置为显示数字0的状态。如果没有while(1)循环,这个状态会被设置一次,然后程序结束。由于没有其他代码去改变这个状态,数码管会继续显示数字0,直到程序被重置或者单片机被关闭。

然而,即使显示是持续的,while(1)循环仍然有其用处:

稳定性while(1)循环确保了程序的持续运行状态,即使在某些情况下(如看门狗定时器溢出或程序错误)导致程序跳过了某些部分,循环仍然可以保持程序的执行。

响应外部事件:在实际应用中,您可能希望程序能够响应外部事件,如按键输入、传感器读数或其他中断。while(1)循环使得程序可以不断检查这些事件,并在必要时做出响应。

动态更新:如果您希望数码管显示动态变化的内容,如计时器、滚动文本或其他变化的数据,while(1)循环是实现这些功能的基础。

程序结构while(1)循环为程序提供了一个明确的结构,使得程序的逻辑更加清晰,便于维护和扩展。

因此,即使没有while(1)循环,显示可以是持续的,但在实际的嵌入式系统编程中,while(1)循环仍然是一个常用的结构,用于确保程序的持续运行和响应外部事件。