-
Notifications
You must be signed in to change notification settings - Fork 6
/
ssd1306_7seg.py
109 lines (94 loc) · 3.19 KB
/
ssd1306_7seg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# I2C OLED 7-segment emulator library for the micro:bit
from microbit import i2c, sleep
# LCD Control constants
ADDR = 0x3C
# Holds the segments on in each of the four digits
display = []
# Segments to set to on for each of the 10 digits. 10 represents empty.
digits = b'\xFC\x60\xDA\xF2\x66\xB6\xBE\xE0\xFE\xF6\x00'
# Position of each of the 8 segments
rects = [[5, 20, 0, 0],
[21, 25, 0, 3],
[21, 25, 4, 6],
[5, 20, 6, 6],
[0, 4, 4, 6],
[0, 4, 0, 3],
[5, 20, 3, 3],
[27, 32, 6, 6]
]
seg_len = [16, 21, 16, 17, 16, 21, 17, 7]
segments = []
with open('segments.bin', 'rb') as f:
for i in seg_len:
segments.append(f.read(i))
dispZeros = 1
def command(c):
i2c.write(ADDR, b'\x00' + bytearray(c))
def initialize(showDots=0, showZeros=1):
global dispZeros, display
cmd = [
[0xAE], # DISPLAYOFF
[0xA4], # DISPLAYALLON_RESUME
[0xD5, 0xF0], # SETDISPLAYCLOCKDIV
[0xA8, 0x3F], # SETMULTIPLEX
[0xD3, 0x00], # SETDISPLAYOFFSET
[0 | 0x0], # SETSTARTLINE
[0x8D, 0x14], # CHARGEPUMP
[0x20, 0x00], # MEMORYMODE horizontal
[0x21, 0, 127], # COLUMNADDR
[0x22, 0, 63], # PAGEADDR
[0xa0 | 0x1], # SEGREMAP
[0xc8], # COMSCANDEC
[0xDA, 0x12], # SETCOMPINS
[0x81, 0xCF], # SETCONTRAST
[0xd9, 0xF1], # SETPRECHARGE
[0xDB, 0x40], # SETVCOMDETECT
[0xA6], # NORMALDISPLAY
[0xd6, 0], # zoom off
]
for c in cmd:
command(c)
clear_oled()
display = [0, 0, 0, 0]
dispZeros = showZeros
disp_number(0)
if showDots == 1:
for i in range(0, 3, 2):
set_rect([61, 66, 2 + i, 2 + i])
i2c.write(ADDR, segments[7])
command([0xaf]) # SSD1306_DISPLAYON
def set_rect(rect):
command([0x21, rect[0], rect[1]])
command([0x22, rect[2], rect[3]])
def clear_oled():
set_rect([0, 127, 0, 7])
screen = bytearray(33)
screen[0] = 0x40
for i in range(0, 32):
i2c.write(ADDR, screen)
def disp_number(n, decPos=0):
global dispZeros
for j in range(0, 4):
v = (n // 10**j) % 10
d = 1 if decPos == j and j > 0 else 0
if v == 0 and dispZeros == 0:
set_digit(j, digits[10] | d)
else:
set_digit(j, digits[v] | d)
def set_digit(dig, d):
global digits, display, segments
c = display[dig]
if c != d:
b1, b2 = c & ~ d, ~c & d
for i in range(0, 8):
r1, r2 = b1 >> (7 - i) & 1, b2 >> (7 - i) & 1
if r2 or r1:
offset = 34 * (3 - dig)
# avoid too much recursion
command([0x21, rects[i][0]+offset, rects[i][1]+offset])
command([0x22, rects[i][2], rects[i][3]])
if r2: # d and not c:
i2c.write(ADDR, segments[i])
elif r1: # not d and c:
i2c.write(ADDR, b'\x40' + bytearray(seg_len[i] - 1))
display[dig] = d