4 位数码管显示

罗大富 BigRich大约 6 分钟ESP32Arduino

实验原理

4 位数码管,即 4 个 1 位数码管并列集中在一起形成一体的数码管。

当多位数码管一体时,它们内部的公共端是独立的,而负责显示什么数字的段线(a-dp)全部是连接在一起的,独立的公共端可以控制多位一体中的哪一位数码管点亮,而连接在一起的段线可以控制这个能点亮数码管亮什么数字,通常我们把公共端叫做 位选线 ,连接在一起的段线叫做 段选线,有了这两个线后,通过单片机及外部驱动电路就可以控制任意的数码管显示任意的数字了。

4 位数码管与 1 位数码管的原理基本一致,除了引脚不同。

相同的地方是,数码管中的 LED 的分段映射相同,如下图:

有区别的地方首先是 1 位数码管有两个相同的公共(COM)端接地或者接电源,而 4 位数码管没有公共端,有四个控制不同位置显示的选通端。

一般一位数码管有 10 个引脚,四位数码管是12 个引脚,关于具体的引脚及段、位标号大家可以查询相关资料,最简单的办法就是用数字万用表测量,若没有数字万用表也可用 5V 直流电源串接1k 电阻后测量,将测量结果记录,通过统计便可绘制出引脚标号。多位数码管有许多是按一定要求设计的,引脚不完全按照一般规则设定,所以需要在使用时查找手册,最直接的办法就是按照数码管上的标示向生产商要求。

硬件电路设计

物料清单(BOM 表):

材料名称数量
4 位数码管1
1kΩ 电阻4
杜邦线(跳线)若干

将材料按照下图相连:

软件程序设计

我们一步一步的来,先写一个最简单的程序,让任意一位数码管显示任意数字,代码可以这么写:

// 定义位选线引脚
int seg_1 = 5;
int seg_2 = 18;
int seg_3 = 19;
int seg_4 = 21;

// 定义位选线数组
int seg_array[4] = {seg_1, seg_2, seg_3, seg_4};

// 定义段选线引脚;
int a = 32;
int b = 25;
int c = 27;
int d = 12;
int e = 13;
int f = 33;
int g = 26;
int dp = 14;

// 定义位选线引脚
int led_array[8] = {a, b, c, d, e, f, g, dp};

// 定义共阴极数码管不同数字对应的逻辑电平的二维数组
int logic_array[10][8] = {
 //a, b, c, d, e, f, g, dp
  {1, 1, 1, 1, 1, 1, 0, 0}, // 0
  {0, 1, 1, 0, 0, 0, 0, 0}, // 1
  {1, 1, 0, 1, 1, 0, 1, 0}, // 2
  {1, 1, 1, 1, 0, 0, 1, 0}, // 3
  {0, 1, 1, 0, 0, 1, 1, 0}, // 4
  {1, 0, 1, 1, 0, 1, 1, 0}, // 5
  {1, 0, 1, 1, 1, 1, 1, 0}, // 6
  {1, 1, 1, 0, 0, 0, 0, 0}, // 7
  {1, 1, 1, 1, 1, 1, 1, 0}, // 8
  {1, 1, 1, 1, 0, 1, 1, 0}, // 9
  };


// 清屏函数
void clear() {
  for (int i=0;i<4;i++) {
    digitalWrite(seg_array[i], HIGH);
    }

  for (int i=0;i<8;i++) {
    digitalWrite(led_array[i], LOW);
    }
  }

// 显示数字的函数
void display_number(int order, int number) {

  // 清屏
  clear();

  // 把对应位选线的电平拉低
  digitalWrite(seg_array[order], LOW);

  // 显示数字
  for (int i=0;i<8;i++) {
    digitalWrite(led_array[i], logic_array[number][i]);
    }
  }

void setup() {
  // 设置所有位选线引脚为输出模式,初始化所有位选线引脚为高电平
  for (int i=0;i<4;i++) {
    pinMode(seg_array[i], OUTPUT);
    digitalWrite(seg_array[i], HIGH);
    }
    
  // 设置所有段选线引脚为输出模式,初始化所有段选线引脚为低电平
  for (int i=0;i<8;i++) {
    pinMode(led_array[i], OUTPUT);
    digitalWrite(led_array[i], LOW);
    }
}

void loop() {
  // 第三位显示数字 3
  // display_number(2, 3);
  
  // 按顺序让所有位置显示 0~9
  for (int i=0;i<4;i++) {
    for (int j=0;j<10;j++) {
      display_number(i, j);
      delay(200);
      }
    }
}

我们选择多位数码管,肯定是要在不同位置显示不同数字的,这时候,我们需要用到 动态扫描

什么是动态扫描

动态扫描是对位选端扫描,8 个引脚控制每个数码管的段选线,通过刷新位选端和 8 个引脚的状态,来实现显示不同的数字。

我们可以通过运行下面这段代码,更生动形象地理解 动态扫描 的原理:

/*
  该程序的作用是演示动态扫描原理。
  在线文档:https://docs.geeksman.com/esp32/Arduino/08.esp32-arduino-4-digits-7segment.html
*/


// 定义位选线引脚
int seg_1 = 5;
int seg_2 = 18;
int seg_3 = 19;
int seg_4 = 21;

// 定义位选线数组
int seg_array[4] = {seg_1, seg_2, seg_3, seg_4};

// 定义段选线引脚;
int a = 32;
int b = 25;
int c = 27;
int d = 12;
int e = 13;
int f = 33;
int g = 26;
int dp = 14;

// 定义位选线引脚
int led_array[8] = {a, b, c, d, e, f, g, dp};

// 定义共阴极数码管不同数字对应的逻辑电平的二维数组
int logic_array[10][8] = {
 //a, b, c, d, e, f, g, dp
  {1, 1, 1, 1, 1, 1, 0, 0}, // 0
  {0, 1, 1, 0, 0, 0, 0, 0}, // 1
  {1, 1, 0, 1, 1, 0, 1, 0}, // 2
  {1, 1, 1, 1, 0, 0, 1, 0}, // 3
  {0, 1, 1, 0, 0, 1, 1, 0}, // 4
  {1, 0, 1, 1, 0, 1, 1, 0}, // 5
  {1, 0, 1, 1, 1, 1, 1, 0}, // 6
  {1, 1, 1, 0, 0, 0, 0, 0}, // 7
  {1, 1, 1, 1, 1, 1, 1, 0}, // 8
  {1, 1, 1, 1, 0, 1, 1, 0}, // 9
  };

// 延时时间
int count = 355;


// 清屏函数
void clear() {
  for (int i=0;i<4;i++) {
    digitalWrite(seg_array[i], HIGH);
    }

  for (int i=0;i<8;i++) {
    digitalWrite(led_array[i], LOW);
    }
  }

// 显示数字的函数
void display_number(int order, int number) {

  // 清屏
  clear();

  // 把对应位选线的电平拉低
  digitalWrite(seg_array[order], LOW);

  // 显示数字
  for (int i=0;i<8;i++) {
    digitalWrite(led_array[i], logic_array[number][i]);
    }
  }

void setup() {
  // 设置所有位选线引脚为输出模式,初始化所有位选线引脚为高电平
  for (int i=0;i<4;i++) {
    pinMode(seg_array[i], OUTPUT);
    digitalWrite(seg_array[i], HIGH);
    }
    
  // 设置所有段选线引脚为输出模式,初始化所有段选线引脚为低电平
  for (int i=0;i<8;i++) {
    pinMode(led_array[i], OUTPUT);
    digitalWrite(led_array[i], LOW);
    }
}

void loop() {
  display_number(0, 1);
  delay(count);

  display_number(1, 2);
  delay(count);

  display_number(2, 3);
  delay(count);

  display_number(3, 4);
  delay(count);

  if (count > 10) {
    if (count > 110) {
      count -= 50;
    }else {
      count -= 10;  
    }
    }
}

理解了 动态扫描 的原理之后,我们就可以写代码了,先把之前写的这些代码复制过来,然后我们还需要实现通过动态扫描的方法实现 4 位数字显示的功能:

// 4 位数码管显示函数
void display_4_number(int number) {
  // 把输入的数字格式化为 4 位数的数组
  if (number < 10000) {
    // 获取每一位对应的数字
//    // 获取个位
//    int seg_4_number = number % 10;
//    number /= 10;
//
//    // 获取十位
//    int seg_3_number = number % 10;
//    number /= 10;
//
//    // 获取百位
//    int seg_2_number = number % 10;
//    number /= 10;
//
//    // 获取千位
//    int seg_1_number = number % 10;

    // 定义格式化数组
    int number_array[4];

    // 使用循环获取格式化数组
    for (int i=3;i>=0;i--) {
      number_array[i] = number % 10;
      number /= 10;
      }
      
    // 显示数字
    for (int i=0;i<4;i++) {
      display_number(i, number_array[i]);
      delay(5);
      }
    }
}

这样,我们就能通过在 loop 函数中调用 display_4_number 函数,来显示数字内容了。

上次编辑于:
贡献者: Luo