数码管显示
现阶段,无论 LCD 和 OLED 显示技术有多好,都无法替代这个古老的显示方式 - 数码管。直到现在,很多领域都离不开数码管。最主要的原因是他便宜有稳定,而且控制简单。
实验原理
数码管是一种半导体发光器件,其基本单元依然是 LED。 数码管按段数可分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元,也就是多一个小数点(DP),这个小数点可以更精确的表示数码管想要显示的内容。
按照能显示的位数可分为 1 位、2 位、3 位、4 位、5 位、6 位、7 位等数码管。
按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管:
共阳数码管
是指将所有发光二极管的阳极
接到一起形成公共阳极(COM)的数码管,共阳数码管在应用时应将公共极 COM 接到+5V
,当某一字段发光二极管的阴极为低电平时,相应字段就点亮,当某一字段的阴极为高电平时,相应字段就不亮。共阴数码管
是指将所有发光二极管的阴极
接到一起形成公共阴极(COM)的数码管,共阴数码管在应用时应将公共极 COM 接到地线 GND
上,当某一字段发光二极管的阳极为高电平时,相应字段就点亮,当某一字段的阳极为低电平时,相应字段就不亮。
原理图如下:
引脚图中间的两个 COM,是公共端,共阴数码管要将其接地,共阳数码管将其接电源。a,b,c,d,e,f,g,dp 被称为段选线。
如何判断是共阴还是共阳?
如果你不清楚你的数码管到底是共阴还是共阳,可以使用下面三种方法测试。
- 一般在数码管的侧面会标注该数码管的型号,可以在浏览器中搜索该型号,获取对应的原理图
- 用 ESP32 单片机给面包板通电(3.3V 引脚),公共端通过一个限流电阻接电源, 用跳线连通电源和数码管的 LED 引脚,如果亮了说明是
共阳型数码管
;反之,说明是共阳型数码管
。
- 使用万用表的二极管档,红表笔接公共端,黑表笔接任一引脚,亮了说明是
共阳型数码管
,反之,则说明是共阴型数码管
。
提示
建议把所有引脚测试一遍,也可以检查出是否有坏了的 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 设备的根目录创建两个新的文件夹 common
,libs
:
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)