4 位数码管显示

罗大富 BigRich大约 8 分钟ESP32Python

实验原理

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

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

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

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

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

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

硬件电路设计

物料清单(BOM 表):

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

将材料按照下图相连:

软件程序设计

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

import time
from machine import Pin


# 定义位选线对象
seg_1 = Pin(5, Pin.OUT)
seg_2 = Pin(18, Pin.OUT)
seg_3 = Pin(19, Pin.OUT)
seg_4 = Pin(21, Pin.OUT)

# 定义位选线列表
seg_list = [seg_1, seg_2, seg_3, seg_4]

# 定义段选线对象
a = Pin(32, Pin.OUT)
b = Pin(25, Pin.OUT)
c = Pin(27, Pin.OUT)
d = Pin(12, Pin.OUT)
e = Pin(13, Pin.OUT)
f = Pin(33, Pin.OUT)
g = Pin(26, Pin.OUT)
dp = Pin(14, Pin.OUT)

# 定义段选线对象
led_list = [a, b, c, d, e, f, g, dp]

number_dict = {
    #  [a, b, c, d, e, f, g, dp]
    0: [1, 1, 1, 1, 1, 1, 0, 0],
    1: [0, 1, 1, 0, 0, 0, 0, 0],
    2: [1, 1, 0, 1, 1, 0, 1, 0],
    3: [1, 1, 1, 1, 0, 0, 1, 0],
    4: [0, 1, 1, 0, 0, 1, 1, 0],
    5: [1, 0, 1, 1, 0, 1, 1, 0],
    6: [1, 0, 1, 1, 1, 1, 1, 0],
    7: [1, 1, 1, 0, 0, 0, 0, 0],
    8: [1, 1, 1, 1, 1, 1, 1, 0],
    9: [1, 1, 1, 1, 0, 1, 1, 0],
}

# 清空位选线函数
def clear_seg():
    # 清空所有的位选线,将所有位选线设置为高电平
    for seg in seg_list:
        seg.on()

# 清空段选线函数
def clear_led():
    # 清空所有的段选线,将所有段选线设置为低电平
    for led in led_list:
        led.off()

# 清屏函数
def clear():
    clear_seg()
    clear_led()


# 显示数字的函数
def display_number(order, number):
    # 逻辑电平列表
    logic_list = number_dict.get(number)

    if logic_list and 0 <= order < 4:
        # 清屏
        clear()
        # 指定要显示的位置,把电平拉低
        seg_list[order].off()
        # 显示数字
        for i in range(len(logic_list)):
            led_list[i].value(logic_list[i])


# 第 3 位显示数字 1
# display_number(3, 1)

# 按顺序让所有位置显示0~9
for i in range(4):
    for j in range(10):
        display_number(i, j)
        time.sleep(0.2)

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

什么是动态扫描

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

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

# 定义位置管脚
seg_1 = Pin(5, Pin.OUT)
seg_2 = Pin(18, Pin.OUT)
seg_3 = Pin(19, Pin.OUT)
seg_4 = Pin(21, Pin.OUT)

seg_list = [seg_1, seg_2, seg_3, seg_4]

# 定义段选线对象
a = Pin(32, Pin.OUT)
b = Pin(25, Pin.OUT)
c = Pin(27, Pin.OUT)
d = Pin(12, Pin.OUT)
e = Pin(13, Pin.OUT)
f = Pin(33, Pin.OUT)
g = Pin(26, Pin.OUT)
dp = Pin(14, Pin.OUT)

# 将对应的引脚对象存储到列表
led_list = [a, b, c, d, e, f, g, dp]

# 共阴极数码管不同数字对应的逻辑电平
number_dict = {
    #  [a, b, c, d, e, f, g, dp]
    0: [1, 1, 1, 1, 1, 1, 0, 0],
    1: [0, 1, 1, 0, 0, 0, 0, 0],
    2: [1, 1, 0, 1, 1, 0, 1, 0],
    3: [1, 1, 1, 1, 0, 0, 1, 0],
    4: [0, 1, 1, 0, 0, 1, 1, 0],
    5: [1, 0, 1, 1, 0, 1, 1, 0],
    6: [1, 0, 1, 1, 1, 1, 1, 0],
    7: [1, 1, 1, 0, 0, 0, 0, 0],
    8: [1, 1, 1, 1, 1, 1, 1, 0],
    9: [1, 1, 1, 1, 0, 1, 1, 0],
}


# 显示数字的函数
def display_number(number):
    # 逻辑电平列表
    logic_list = number_dict.get(number)

    if logic_list:
        for i in range(len(logic_list)):
            led_list[i].value(logic_list[i])

        
# 清空位选线函数
def clear_seg():
    # 清空所有的位选线,将所有位选线设置为高电平
    for seg in seg_list:
        seg.on()

# 清空段选线函数
def clear_led():
    # 清空所有的段选线,将所有段选线设置为低电平
    for led in led_list:
        led.off()

# 清空函数
def clear():
    clear_seg()
    clear_led()


if __name__ == '__main__':
    # 清空显示内容
    clear()
    
    # 延时时间,初始为 355ms
    count = 355
        
    while True:
        # seg_1 显示数字 1
        clear_seg()
        seg_1.off()
        display_number(1)
        time.sleep_ms(count)
    
        # seg_2 显示数字 2
        clear_seg()
        seg_2.off()
        display_number(2)
        time.sleep_ms(count)
        
        # seg_3 显示数字 3
        clear_seg()
        seg_3.off()
        display_number(3)
        time.sleep_ms(count)
    
        # seg_4 显示数字 4
        clear_seg()
        seg_4.off()
        display_number(4)
        time.sleep_ms(count)
        
        # 逐渐缩短延时时间
        if count > 10:
            if count > 110:
                count -= 50
            else:
                count -= 10

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

# 显示函数
def display_4_number(number):
    # 获取格式化的数字列表
    # 判断参数是否超过 9999
    if number <= 9999:
        # 获取每一位对应的数字
#         # 获取第四位
#         seg_4_number = number % 10
#         number //= 10
#         print(seg_4_number)
#         # 获取第三位
#         seg_3_number = number % 10
#         number //= 10
#         print(seg_3_number)
#         # 获取第二位
#         seg_2_number = number % 10
#         number //= 10
#         print(seg_2_number)
#         # 获取第一位
#         seg_1_number = number % 10
#         number //= 10
#         print(seg_1_number)
        
        # 初始化每个位置对应的数字列表
        number_list = []
        # 使用循环的方式获取数字列表
        for i in range(4):
            number_list.insert(0, number % 10)
            number //= 10 
    
    # 显示数字
    for i in range(len(number_list)):
        display_number(i, number_list[i])
        time.sleep_ms(5)

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

为了避免日后用到共阴极 4 位数码管时,需要重写此代码,我们采用面向对象的方式,把驱动代码封装成类,存放在 MicroPython 设备中的 common 目录下 four_digits_seg.py

'''
common/four_digits_seg.py
4 位共阴极数码管公共类
上传到 MicroPython 设备中的 common 文件夹下
'''
import time
from machine import Pin

class Seg4Digit:
    def __init__(self, seg_1, seg_2, seg_3, seg_4, a, b, c, d, e, f, g, dp):
        
        # 定义位选线对象
        self.seg_1 = Pin(seg_1, Pin.OUT)
        self.seg_2 = Pin(seg_2, Pin.OUT)
        self.seg_3 = Pin(seg_3, Pin.OUT)
        self.seg_4 = Pin(seg_4, Pin.OUT)

        # 定义位选线列表
        self.seg_list = [self.seg_1, self.seg_2, self.seg_3, self.seg_4]

        # 定义段选线对象
        self.a = Pin(a, Pin.OUT)
        self.b = Pin(b, Pin.OUT)
        self.c = Pin(c, Pin.OUT)
        self.d = Pin(d, Pin.OUT)
        self.e = Pin(e, Pin.OUT)
        self.f = Pin(f, Pin.OUT)
        self.g = Pin(g, Pin.OUT)
        self.dp = Pin(dp, Pin.OUT)

        # 定义段选线对象
        self.led_list = [self.a, self.b, self.c, self.d, self.e, self.f, self.g, self.dp]

        self.number_dict = {
            #  [a, b, c, d, e, f, g, dp]
            0: [1, 1, 1, 1, 1, 1, 0, 0],
            1: [0, 1, 1, 0, 0, 0, 0, 0],
            2: [1, 1, 0, 1, 1, 0, 1, 0],
            3: [1, 1, 1, 1, 0, 0, 1, 0],
            4: [0, 1, 1, 0, 0, 1, 1, 0],
            5: [1, 0, 1, 1, 0, 1, 1, 0],
            6: [1, 0, 1, 1, 1, 1, 1, 0],
            7: [1, 1, 1, 0, 0, 0, 0, 0],
            8: [1, 1, 1, 1, 1, 1, 1, 0],
            9: [1, 1, 1, 1, 0, 1, 1, 0],
        }


    # 清屏函数
    def clear(self):
        # 清空所有的位选线,将所有位选线设置为高电平
        for seg in self.seg_list:
            seg.on()
            
        # 清空所有的段选线,将所有段选线设置为低电平
        for led in self.led_list:
            led.off()


    # 显示数字的函数
    def display_number(self, order, number):
        # 逻辑电平列表
        logic_list = self.number_dict.get(number)

        if logic_list and 0 <= order < 4:
            # 清屏
            self.clear()
            # 指定要显示的位置,把电平拉低
            self.seg_list[order].off()
            # 显示数字
            for i in range(len(logic_list)):
                self.led_list[i].value(logic_list[i])


    # 显示函数
    def display_4_number(self, number):
        # 判断参数是否超过 9999
        if number <= 9999:            
            # 初始化每个位置对应的数字列表
            number_list = []
            # 使用循环的方式获取数字列表
            for i in range(4):
                number_list.insert(0, number % 10)
                number //= 10  
        
        for i in range(len(number_list)):
            self.display_number(i, number_list[i])
            time.sleep_ms(5)

在主程序中,以下面几行代码的方式调用:

'''
该程序作用是使用面向对象的方法让四位数码管显示数字
在线文档:https://docs.geeksman.com/
'''

from common.four_digits_seg import Seg4Digit


if __name__ == '__main__':
    # 初始化 4 位数码管对象
    seg_object = Seg4Digit(seg_1=5, seg_2=18, seg_3=19, seg_4=21, a=32, b=25, c=27, d=12, e=13, f=33, g=26, dp=14)
    
    while True:
        seg_object.display_4_number(1234)
上次编辑于:
贡献者: Luo