码疯窝

树莓派学习之 – 驱动四位数码管

2014/12/28 00:13:12    分类: 日志连载    0人评论 次浏览

20141228001118

最近迷上了树莓派, 因为一直都比较喜欢低层的东西. 无奈, 对电器元件一窍不通, 只停留在”正极 + 灯泡 + 负极”就会亮的状态. 面对手上的一个四位数码管, 12根针脚, 就完全糊涂了.
度娘是最好的老师, 她告诉了我四位数码管的显示原理.
一位数字可以看成由8个发光二极管组成. A-H. H 代码 数字旁边的小数点. 如下图.

#     __A_
#    |     |  
#  F |     | B
#    |__G__|  
#    |     |   
#  E |     | C
#    |__D__|   H

两根针脚通电好, 可以使其中一个二极管发光.
因此要8个二极管全亮要多少呢? 8 * 2 = 16? 错, 事实上只需要9根, 一个正极 + 八个负极 或者 一个负极 + 八个正极.
这就是共阳数码管与共阴数码管的区别.
4位数码管就是 8 + 4阳或4阴 = 12根线.
而我手上的这款 HS4105616-32 正好是一款共阳数码管.

接下来就是需要研究哪两根针控制哪两个灯.

于是我把12 个针脚分为:

a, b, c, d, e, f
g, h, i, j, k, l

用万用表蜂鸣档一一测试. 得出以下结论.

# a/d/e/l      b, f, j, h, g, c, k, i
#      	       A, B, C, D, E, F, G, H

这表示 a+b=A1, a+f=B1, d+b=A2
也就是 a为高电平, b 为低电平时, 一号位数字8的A灯亮, a,f控制 一号位B灯亮, d,b 控制二号位A灯亮.
但是, 因为4位数字都是用的同样的8个阴极. 那么在显示的时候就会有冲突啊?
是的, 因此我们需要动态驱动显示.
每次点亮一位数字, 再关掉, 再点亮第二个. 因为人的视觉停留导致你觉得4数字是同时出现的.
原理通了, 接下来就是接线了

# a/d/e/l      b, f, j, h, g, c, k, i
#      	       A, B, C, D, E, F, G, H
# 29/31/33/35 (7,11,12,13,15,16,18,22)

对应的12个针脚我接的是以下几个GPIO, 全是按板是的位置来的.
接下来就是代码部分.
因为一个数字8个灯, 正好用一字节表示. 如上图我们需要显示数字3. 就要ABCDG亮, 其它不亮. 亮为1, 不亮为0.
也就是 3 = 11110010 = 0xF2
我们再通过移位算法来决定, 哪些针脚要置为高电平, 哪些针脚要置为低电平.

以下为显示分钟和秒针的Python代码:


#!/usr/bin/env python
# -*- coding: utf-8 -*-  
# @Author: Gcaufy
# @Link: www.madcoder.cn
# @Date:   2014-12-20 10:02:21  


import RPi.GPIO as GPIO
import time
import sys

# 针脚编号:
# a,b,c,d,e,f
# g,h,i,j,k,l
#


# 灯编号:
#     __A_
#    |     |  
#  F |     | B
#    |__G__|  
#    |     |   
#  E |     | C
#    |__D__|   H
#

# 接线:
# a/d/e/l      b, f, j, h, g, c, k, i
#      		   A, B, C, D, E, F, G, H
# 29/31/33/35 (7,11,12,13,15,16,18,22)


# 0 -> 1111 1100 -> 0xfc
# 1 -> 0110 0000 -> 0x60
# 2 -> 1101 1010 -> 0xda
# 3 -> 1111 0010 -> 0xf2
# 4 -> 0110 0110 -> 0x66
# 5 -> 1011 0110 -> 0xb6
# 6 -> 1011 1110 -> 0xbe
# 7 -> 1110 0000 -> 0xe0
# 8 -> 1111 1110 -> 0xfe
# 9 -> 1111 0110 -> 0xf6
pins = [7,11,12,13,15,16,18,22]
bits = [29,31,33,35]
nums = [0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6]
init = False

def setup():
	init = True
	GPIO.setwarnings(False)
	GPIO.setmode(GPIO.BOARD)
	for i in pins + bits:
	    GPIO.setup(i, GPIO.OUT)
	    GPIO.output(i, GPIO.LOW)


def flush(bit, n):
    n = nums[n]
    for i in bits:
    	#print 'BIT: ' + str(i) + ' was ' + str(GPIO.HIGH if (i == bits[bit]) else GPIO.LOW)
    	GPIO.output(i, GPIO.HIGH if (i == bits[bit]) else GPIO.LOW)

    for i in range(8):
    	#print 'haltPIN: ' + str(i) + ' was ' + str(GPIO.LOW if (n & (1 << i)) else GPIO.HIGH) + ' value is ' + str(n & (1 << (7 - i)))
		GPIO.output(pins[i], GPIO.LOW if (n & (1 << (7 - i))) else GPIO.HIGH)

    for i in range(8):
    	#print 'PIN: ' + str(i) + ' was ' + str(GPIO.LOW if (n & (1 << i)) else GPIO.HIGH) + ' value is ' + str(n & (1 << (7 - i)))
    	if (n & (1 << (7 - i))):
    		GPIO.output(pins[i], GPIO.HIGH)

def display(num, showAll = False):
	if (init == False):
		setup()
	b0 = num % 10
	b1 = num % 100 / 10 
	b2 = num % 1000 / 100
	b3 = num / 1000
	if (num >= 1000 or showAll):
		flush(0, b3)
	if (num >= 100 or showAll):
		flush(1, b2)
	if (num >= 10 or showAll):
		flush(2, b1)
	if (num >= 0):
		flush(3, b0)
if __name__ == '__main__':
	try:
	    while True:
	        t = time.gmtime()
	    	display(t.tm_min * 100 + t.tm_sec, True)
	except:
	    GPIO.cleanup()
继续查看有关 日志连载的文章

0个访客评论