#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"
程序的主要部分包括数据类型的定义、宏定义、数码管显示数据的数组定义以及主函数的实现。
-
数据类型定义:
typedef unsigned int u16; // 将unsigned int类型简写为u16
typedef unsigned char u8; // 将unsigned char类型简写为u8
这里使用了typedef关键字来定义新的数据类型别名,使得代码更加简洁易读。
-
宏定义:
#define SMG_A_DP_PORT P0 // 定义数码管段码口为P0口
通过宏定义,将数码管的段码口定义为P0口,这样在程序中就可以直接使用SMG_A_DP_PORT来代表P0口,提高了代码的可读性和可维护性。
-
数码管显示数据数组定义:
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
这是一个包含了0到F共16个数字的段码数组。每个数字对应一个段码值,这些值是数码管显示相应数字时需要设置的段选信号。
-
主函数实现:
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)循环仍然是一个常用的结构,用于确保程序的持续运行和响应外部事件。