数码管显示

罗大富 BigRich大约 8 分钟ESP32Python

现阶段,无论 LCD 和 OLED 显示技术有多好,都无法替代这个古老的显示方式 - 数码管。直到现在,很多领域都离不开数码管。最主要的原因是他便宜有稳定,而且控制简单。

实验原理

数码管是一种半导体发光器件,其基本单元依然是 LED。 数码管按段数可分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元,也就是多一个小数点(DP),这个小数点可以更精确的表示数码管想要显示的内容。

按照能显示的位数可分为 1 位、2 位、3 位、4 位、5 位、6 位、7 位等数码管。

按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管:

  1. 共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管,共阳数码管在应用时应将公共极 COM 接到 +5V ,当某一字段发光二极管的阴极为低电平时,相应字段就点亮,当某一字段的阴极为高电平时,相应字段就不亮。
  2. 共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码管,共阴数码管在应用时应将公共极 COM 接到地线 GND 上,当某一字段发光二极管的阳极为高电平时,相应字段就点亮,当某一字段的阳极为低电平时,相应字段就不亮。

原理图如下:

引脚图中间的两个 COM,是公共端,共阴数码管要将其接地,共阳数码管将其接电源。a,b,c,d,e,f,g,dp 被称为段选线。

如何判断是共阴还是共阳?

如果你不清楚你的数码管到底是共阴还是共阳,可以使用下面三种方法测试。

  1. 一般在数码管的侧面会标注该数码管的型号,可以在浏览器中搜索该型号,获取对应的原理图
  1. 用 ESP32 单片机给面包板通电(3.3V 引脚),公共端通过一个限流电阻接电源, 用跳线连通电源和数码管的 LED 引脚,如果亮了说明是共阳型数码管;反之,说明是共阳型数码管
  1. 使用万用表的二极管档,红表笔接公共端,黑表笔接任一引脚,亮了说明是共阳型数码管,反之,则说明是共阴型数码管

提示

建议把所有引脚测试一遍,也可以检查出是否有坏了的 LED。

硬件电路设计

物料清单(BOM 表):

材料名称数量
1 位 8 段数码管1
1kΩ 电阻1
杜邦线(跳线)若干
面包板1

将材料按照下图相连:

软件程序设计

设计这个程序时,我们需要使用的 Python 中的 字典 dict函数 function

如果我们想让这个数码管某一引脚亮起来,那么我们需要给对应的引脚设置一个低电平。如果我们想要显示一个数字时,就需要让多个 LED 同时亮,比如数字 1 需要 b、c 引脚给低电平,其余引脚给高电平。程序可以这样写:

from machine import Pin

# 定义不同引脚对应不同的 Pin 对象
a = Pin(4, Pin.OUT)
b = Pin(5, Pin.OUT)
c = Pin(19, Pin.OUT)
d = Pin(21, Pin.OUT)
e = Pin(22, Pin.OUT)
f = Pin(2, Pin.OUT)
g = Pin(15, Pin.OUT)
dp = Pin(18, Pin.OUT)

# 将所有引脚对象存入列表中
led_list = [a, b, c, d, e, f, g, dp]

# 将所有引脚初始值设为 1 高电平
for led in led_list:
    led.value(1)

# 显示数字 1,将 b,c 设置为低电平
b.value(0)
c.value(0)

这样写的话,我们不仅需要在使用前先把所有引脚逻辑电平拉高,而且如果我们想要显示数字 2,就需要修改多行代码:

# 显示数字 2,将 a, b, d, e, g 设置为低电平
a.value(0)
b.value(0)
d.value(0)
e.value(0)
g.value(0)

这样写的话非常麻烦,因此,我们可以使用字典来存储数字对应的所有引脚的逻辑值,再封装一个函数将字典中的值转换并应用到每个引脚中,代码如下:


import time
from machine import Pin

# 定义不同引脚对应不同的 Pin 对象
a = Pin(4, Pin.OUT)
b = Pin(5, Pin.OUT)
c = Pin(19, Pin.OUT)
d = Pin(21, Pin.OUT)
e = Pin(22, Pin.OUT)
f = Pin(2, Pin.OUT)
g = Pin(15, Pin.OUT)
dp = Pin(18, Pin.OUT)

# 将所有引脚对象存入列表中
led_list = [a, b, c, d, e, f, g, dp]

# 把所有数字对应的逻辑电平存入字典中,逻辑值依次为 abcdefgh
number_dict = {
    0: [0, 0, 0, 0, 0, 0, 1, 1],
    1: [1, 0, 0, 1, 1, 1, 1, 1],
    2: [0, 0, 1, 0, 0, 1, 0, 1],
    3: [0, 0, 0, 0, 1, 1, 0, 1],
    4: [1, 0, 0, 1, 1, 0, 0, 1],
    5: [0, 1, 0, 0, 1, 0, 0, 1],
    6: [0, 1, 0, 0, 0, 0, 0, 1],
    7: [0, 0, 0, 1, 1, 1, 1, 1],
    8: [0, 0, 0, 0, 0, 0, 0, 1],
    9: [0, 0, 0, 0, 1, 0, 0, 1],
}


# 创建在数码管上显示数字的函数
def display_number(number):
    logic_list = number_dict.get(number)

    if logic_list:
        for i in range(len(logic_list)):
            if logic_list[i] == 1:
                led_list[i].value(1)
            else:
                led_list[i].value(0)


# 显示 0~9 十个数字
for i in range(10):
    display_number(i)
    time.sleep(0.5)

虽然说,咱们这个程序能够正常运行了,但是有两个小毛病,第一点就是不具备通用性,我们把所有代码都写在了同一个文件中,不够规范,尤其是声明数码管引脚对象,和显示数字的函数。如果下次实验,我依然用到了数码管,难不成我还要再把这些代码写一遍?

因此,我们要避免这样的问题,我们在 MicroPython 设备的根目录创建两个新的文件夹 commonlibs:

  • common:存放自己写的公共常量、函数、类等等。
  • libs:存放第三方的代码,内容与 common 一致,唯一的区别就是 libs 中的文件都不是自己手写的。

我们,在 common 目录下,创建 seg.py,并把以下代码剪切到该文件中:

from machine import Pin

# 定义不同引脚对应不同的 Pin 对象
a = Pin(4, Pin.OUT)
b = Pin(5, Pin.OUT)
c = Pin(19, Pin.OUT)
d = Pin(21, Pin.OUT)
e = Pin(22, Pin.OUT)
f = Pin(2, Pin.OUT)
g = Pin(15, Pin.OUT)
dp = Pin(18, Pin.OUT)

# 将所有引脚对象存入列表中
led_list = [a, b, c, d, e, f, g, dp]

# 把所有数字对应的逻辑电平存入字典中,逻辑值依次为 abcdefgh
number_dict = {
    0: [0, 0, 0, 0, 0, 0, 1, 1],
    1: [1, 0, 0, 1, 1, 1, 1, 1],
    2: [0, 0, 1, 0, 0, 1, 0, 1],
    3: [0, 0, 0, 0, 1, 1, 0, 1],
    4: [1, 0, 0, 1, 1, 0, 0, 1],
    5: [0, 1, 0, 0, 1, 0, 0, 1],
    6: [0, 1, 0, 0, 0, 0, 0, 1],
    7: [0, 0, 0, 1, 1, 1, 1, 1],
    8: [0, 0, 0, 0, 0, 0, 0, 1],
    9: [0, 0, 0, 0, 1, 0, 0, 1],
}


# 创建在数码管上显示数字的函数
def display_number(number):
    if number_dict.get(number):
        i = 0
        for bit in number_dict.get(number):
            if bit == 1:
                led_list[i].value(1)
            else:
                led_list[i].value(0)
            i += 1

把以上代码复制过来以后,我们就要明白我们这个代码的第二个毛病:变量与函数之前关联性太弱。因此,我们可以通过面向对象的方法来加强变量与函数之间的联系:

from machine import Pin


# 创建共阳型数码管对象
class Seg:
    # 要求用户在调用的时候,填写所有段选管
    def __init__(self, a, b, c, d, e, f, g, dp):
        # 定义不同引脚对应不同的 Pin 对象
        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)

        # 将所有引脚对象存放在 led_list 中
        self.led_list = [self.a, self.b, self.c, self.d, self.e, self.f, self.g, self.dp]

        # 把所有数字对应的逻辑电平存入字典中,逻辑值依次为 abcdefgh
        self.number_dict = {
            0: [0, 0, 0, 0, 0, 0, 1, 1],
            1: [1, 0, 0, 1, 1, 1, 1, 1],
            2: [0, 0, 1, 0, 0, 1, 0, 1],
            3: [0, 0, 0, 0, 1, 1, 0, 1],
            4: [1, 0, 0, 1, 1, 0, 0, 1],
            5: [0, 1, 0, 0, 1, 0, 0, 1],
            6: [0, 1, 0, 0, 0, 0, 0, 1],
            7: [0, 0, 0, 1, 1, 1, 1, 1],
            8: [0, 0, 0, 0, 0, 0, 0, 1],
            9: [0, 0, 0, 0, 1, 0, 0, 1],
        }

        # 初始化所有引脚
        self.clean()

    def clean(self):
        # 初始化状态
        for i in self.led_list:
            i.value(1)

    def display_number(self, number):
        # 显示数字
        logic_list = self.number_dict.get(number)
        if logic_list:
            for i in range(len(logic_list)):
                if logic_list[i] == 1:
                    self.led_list[i].value(1)
                else:
                    self.led_list[i].value(0)

接着,我们在主文件中把该模块导入,并调用:

import time
from common.seg import Seg


if __name__ == '__main__':
    # 创建共阳极数码管对象
    seg_object = Seg(a=4, b= 5, c=19, d=21, e=22, f=2, g=15, dp=18)
    
    # 显示 0 - 9
    for i in range(10):
        seg_object.display_number(i)
        time.sleep(0.5)
上次编辑于:
贡献者: Luo