1. 四位数码管介绍
上一节
里面介绍了数码管的分类以及初步学习了一位数码管的驱动方式,一位8段数码管就需要有8个IO接口来分别驱动每个段位的led灯,这次咱们升级到4位8段数码管来学习,那是不是就需要4*8=32个IO口来驱动呢?
显然这么做就太蠢了,从上图也能看出来,这个HS420361K-32数码管只引出12个引脚出来,上下各6个。这个数码管是共阴型的,后面的学习都是按共阴模式来的(公共端接地),如果是共阳型的只要反过来控制就行,所以咱们要好好学习一下原理图及驱动逻辑。
2. 四位数码管原理及驱动方式
2.1. 电路原理图
这个数码管我没找到厂家及官方电路原理图,只能在淘宝上查这个型号,然后一家家看商品宣传里面有没有资料,只找到一个类似的其他型号的原理图,但实际结构是一致的。
老规矩,咱们分析一下这个原理图:
1) 同一位数码管一样,规格尺寸先不管,只看右边三幅。右上是单位数码管各个段位的名称示意,这跟上节课是一致的;
2 )右中是引脚图,也是正面俯视的话从左下角开始逆时针依次是1~12号引脚;
3 )最下边的走线图就比较重要了,依次排了32个led二极管以及对接的走线。这个要认真看下:
3-1)只看最左边那8个二极管,对应的就是四位数码管的第一位,单看这个的话,跟上节那个单位的数码管也是一样的,只不过不同的是这里标12呈引脚的地方都是接到了led二极管的负极,正极按A~DP这8个段位来看,依次接到了11/7/4/2/1/10/5/3这几个引脚上。上节文章里面最后的实验部分,我就是接了这几个地方的连接来展示效果的,就是共阳和共极处理时,十六进制的编码部分要取反一下。
3-2)向右延伸,后面三组各8个led二极管,同名的段位都是并联在一起的,接到了同一个引脚上。每一位数码管只是共阴的那个公共端各自对应一个引脚。这样下来8个段对应8个引脚,外加4位有4个引脚,所以外观上看该四位数码管下面一共长了12只脚。
2.2. 驱动原理分析
电路结构已经清楚了,那就看如果驱动四位数码管显示了,因为每一位的同名段led是并联在一起的,也就意味着,如果按上节课学过的十六进制方式控制段位引脚的高低电平时,这4位显示的数值是一样的(前提是这4位的公共端都接地了)
那下来就要解决两个问题:1是怎样控制每一位是否开启(公共端与esp8266之间加个能控制的开关);2是怎样让这四位能同时显示不同的数值,毕竟都显示一样的话也就失去多位的意义了。
2.2.1. 每个位独立开关的方式
电路原理图上数码管的12/9/8/6这四个引脚是各个管位的公共端,接到单片机负极,然后段位引脚上给高电平就可以点亮对应的led段。四个公共端都接负极,那四个管位都显示一样的内部,哪个不接负极哪个就不显示。
是不是需要个开关的意思呀,那就需要借助三极管来实现了,这里只贴一下三极管使用的接线原理,具体为何能用三极管控制,三极管又是通过什么原理去控制的,这都够展示个专题来写了。我对数模电这些的不精通,就不献丑了。
采用S9013三极管来做为开关,用一个io口控制三极管的基极,io口输出高电平时,右侧竖向线路就通了,相应的led也就能点亮。
ESP8266的IO口的输出电压是3.3V,所以咱们测试时就不用考虑加电阻了,简化一下能更好地理解原理。
2.2.2. 各位数码管显示不同数值的方式(动态扫描)
由于各位数码管的同名段位led是并联在一起的,所以在各位上显示的数值是一样的,如果想要不一样,其实利用到的是人的视觉暂留机制。
比如我刚好要在这四位上显示0361,实际的做法其实是做个死循环,然后先控制段码显示第一个数字0同时只打开第一个三极管,保持一定时间后关闭它;再控制段码显示第二个数字3同时只打开第二个三极管,然后保持一下再关闭这个三极管;再如此显示6并打开第三个三极管、以及显示1并打开第四个三极管。
这样显示一轮以后,再从头开始不断循环。就跟放电影一样,不断往复地在不同位上显示不同数字,又以较高的频率不断刷新就能让人眼看起来以为这四位数码管会显示4个不同的数值。
人眼视觉暂留的频率是24帧,每帧40多毫秒。咱们有数码管有4位,每一位都要兼顾到,所以每一位的刷新速度要在10毫秒以下,具体用多少速度可以后面实测一下。
3. 实验:四位数码管显示不断增长的数字
3.1. 接线图
根据前面原理及驱动的分析,咱们可以把数码管跟ESP8266开发板连接起来了,需要用到12个GPIO口来控制8个段+4个管位,还需要借助4个NPN小型三极管来做各个位的开关。
傻了,遇到事儿了。
当我兴致冲冲按上面的接线图部好了线,又一气呵成写下驱动代码,put代码到板子上后,板子直接死机。。。
这时候用ampy操作任何指令都是卡死状态
我是按照图上GPIO口的顺序来接线的呀,几个意思~
重要烧录固件包,还好esptool工具还能正常操作,过程不表。顺便刷了最新的esp8266-20210902-v1.17.bin固件。
回到micropython官网查查,汗~ 只有9个IO口能用,咱还指望着用12个来动态扫描呢。。。。
既然只有9个GPIO能用,那将就一下,段位里面用7个(不显示小数点了)+ 控制管位用2个。也就是实际效果只能点亮两位数码管,显示不带小数点的数字。最终接线如下:
3.2. 测试代码
这测试代码算是阉割版了,只能驱动两位数码管。
from machine import Pin
import utime
leds = []
# 需要根据实际接线,依次放入A/B/C/D/E/F/G/DP这8个段位led灯对应到esp8266的GPIO引脚
for p in [4,0,12,14,2,5,16,13]:
_pin = Pin(p, Pin.OUT)
leds.append(_pin)
digs = []
# 根据实际接线,依次控制1~4四个位置的数码管
for p in [13,15]: # 实际目前只控制两位,还借用了原DP引脚的接线
_pin = Pin(p, Pin.OUT)
digs.append(_pin)
mapper = {
'0': 0xC0, '1': 0xF9, '2': 0xA4, '3': 0xB0,
'4': 0x99, '5': 0x92, '6': 0x82, '7': 0xF8,
'8': 0x80, '9': 0x90, 'A': 0x88, 'B': 0x83,
'C': 0xA7, 'D': 0xA1, 'E': 0x86, 'F': 0x8E,
}
def show_num(num, has_point=False):
'写入显示字符,转换为十六进制数值并按位点亮'
value = mapper.get(num, 0)
if not value: return
# value = value & 0x7F if has_point else value # 共阳方式
value = (~value | 0x80) if has_point else ~value # 共阴方式
for i,led in enumerate(leds):
if i==7: continue # !!!临时屏蔽最高位(转为控制管位开关)
led.value((value >> i) & 0x01)
num = 0
while True:
if num>99: num=0
for i in range(50):
# 显示十位
show_num(str(int(num/10)))
digs[0].on()
utime.sleep_ms(5)
digs[0].off()
utime.sleep_ms(5)
# 显示个位
show_num(str(num%10))
digs[1].on()
utime.sleep_ms(5)
digs[1].off()
utime.sleep_ms(5)
num += 1
3.2.1. 消抖与消影
show_num(str(num%10))digs[1].on()utime.sleep_ms(5)digs[1].off()utime.sleep_ms(5) 最后面的while循环里面,用法比较怪异,看上面的片段:
1)先是按待显示数字驱动段位led二极管
2)然后把要将数字显示到的管位三极管打开,这样数字就会显示出来了,且只在指定的一个管位上显示
3)保持一段时间(这里用了5毫秒)
4)然后关闭刚才的管位,并且再保持一段时间(又是用了5毫秒)
其实这里这样写,是使用到了消抖和消影的手法,先保持一段时间是为了让人产生视觉暂留,但时间又不能长,我原来写的10毫秒,都会有抖动的现象。后面关闭管位后,又保持了一段时间,其实这也是利用了视觉暂留,不加这一段时间而直接显示下一轮数字时,后面出现的数字还有叠加上一轮数字的轮廓,看起来像是上一轮数字有影子一样的。
大家拿到代码,把sleep_ms里面的参数调一调,自己体会一下。调得不好,要不就是数字在抖动,要不就是有重影。
3.3. 实验效果
唉,这效果只能看到两位管,太打击人了,不过正好,也为咱们下一节学习由两片595位移寄存器驱动的数码管打下基础,到时候就不用为IO口不够用发愁了。