Created
January 6, 2022 22:05
-
-
Save eparadis/5ffcd920b11b259eacee89d834c77dc3 to your computer and use it in GitHub Desktop.
ESP8266 MicroPython to work with a common-anode TM1638
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file is executed on every boot (including wake-boot from deepsleep) | |
#import esp | |
#esp.osdebug(None) | |
import gc | |
import webrepl | |
webrepl.start() | |
gc.collect() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# clk 2, dio 0, stb 3 | |
import tm1638 | |
from machine import Pin | |
tm = tm1638.TM1638(stb=Pin(3), dio=Pin(0), clk=Pin(2)) | |
def write_digit(segments, digit, pos): | |
for i in range(0, 7): | |
segments[i] = segments[i] | (((digit >> i) & 0x1) << pos) | |
# print(segments) | |
tm.segments(segments, 0) | |
def write(d): | |
tm.clear() | |
c = [0, 0, 0, 0, 0, 0, 0, 0] | |
i = len(c) - 1 | |
for seg in d: | |
write_digit(c, seg, i) | |
i -= 1 | |
d=[] | |
def putd(x): | |
if len(d) == 8: | |
d.pop(0) | |
if x == '-': | |
d.append(0b1000000) | |
elif x == ' ': | |
d.append(0) | |
else: | |
s=[0b111111,0b110,0b1011011,0b1001111,0b1100110,0b1101101,0b1111100,0b111,0b1111111,0b1100111] | |
d.append(s[x]) | |
write(d) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# MicroPython TM1638 LED display driver for 8x 7-segment decimal LED modules with 8x individual LEDs and 8x switches | |
# 8x push buttons | |
from micropython import const | |
from machine import Pin | |
from time import sleep_us, sleep_ms | |
TM1638_CMD1 = const(64) # 0x40 data command | |
TM1638_CMD2 = const(192) # 0xC0 address command | |
TM1638_CMD3 = const(128) # 0x80 display control command | |
TM1638_DSP_ON = const(8) # 0x08 display on | |
TM1638_READ = const(2) # 0x02 read key scan data | |
TM1638_FIXED = const(4) # 0x04 fixed address mode | |
# 0-9, a-z, blank, dash, star | |
_SEGMENTS = bytearray(b'\x3F\x06\x5B\x4F\x66\x6D\x7D\x07\x7F\x6F\x77\x7C\x39\x5E\x79\x71\x3D\x76\x06\x1E\x76\x38\x55\x54\x3F\x73\x67\x50\x6D\x78\x3E\x1C\x2A\x76\x6E\x5B\x00\x40\x63') | |
class TM1638(object): | |
"""Library for the TM1638 LED display driver.""" | |
def __init__(self, stb, clk, dio, brightness=7): | |
self.stb = stb | |
self.clk = clk | |
self.dio = dio | |
if not 0 <= brightness <= 7: | |
raise ValueError("Brightness out of range") | |
self._brightness = brightness | |
self._on = TM1638_DSP_ON | |
self.clk.init(Pin.OUT, value=1) | |
self.dio.init(Pin.OUT, value=0) | |
self.stb.init(Pin.OUT, value=1) | |
self.clear() | |
self._write_dsp_ctrl() | |
def _write_data_cmd(self): | |
# data command: automatic address increment, normal mode | |
self._command(TM1638_CMD1) | |
def _set_address(self, addr=0): | |
# address command: move to address | |
self._byte(TM1638_CMD2 | addr) | |
def _write_dsp_ctrl(self): | |
# display command: display on, set brightness | |
self._command(TM1638_CMD3 | self._on | self._brightness) | |
def _command(self, cmd): | |
self.stb(0) | |
self._byte(cmd) | |
self.stb(1) | |
def _byte(self, b): | |
for i in range(8): | |
self.clk(0) | |
self.dio((b >> i) & 1) | |
self.clk(1) | |
def _scan_keys(self): | |
"""Reads one of the four bytes representing which keys are pressed.""" | |
pressed = 0 | |
self.dio.init(Pin.IN, Pin.PULL_UP) | |
for i in range(8): | |
self.clk(0) | |
if self.dio.value(): | |
pressed |= 1 << i | |
self.clk(1) | |
self.dio.init(Pin.OUT) | |
return pressed | |
def power(self, val=None): | |
"""Power up, power down or check status""" | |
if val is None: | |
return self._on == TM1638_DSP_ON | |
self._on = TM1638_DSP_ON if val else 0 | |
self._write_dsp_ctrl() | |
def brightness(self, val=None): | |
"""Set the display brightness 0-7.""" | |
# brightness 0 = 1/16th pulse width | |
# brightness 7 = 14/16th pulse width | |
if val is None: | |
return self._brightness | |
if not 0 <= val <= 7: | |
raise ValueError("Brightness out of range") | |
self._brightness = val | |
self._write_dsp_ctrl() | |
def clear(self): | |
"""Write zeros to each address""" | |
self._write_data_cmd() | |
self.stb(0) | |
self._set_address(0) | |
for i in range(16): | |
self._byte(0x00) | |
self.stb(1) | |
def write(self, data, pos=0): | |
"""Write to all 16 addresses from a given position. | |
Order is left to right, 1st segment, 1st LED, 2nd segment, 2nd LED etc.""" | |
if not 0 <= pos <= 15: | |
raise ValueError("Position out of range") | |
self._write_data_cmd() | |
self.stb(0) | |
self._set_address(pos) | |
for b in data: | |
self._byte(b) | |
self.stb(1) | |
def led(self, pos, val): | |
"""Set the value of a single LED""" | |
self.write([val], (pos << 1) + 1) | |
def leds(self, val): | |
"""Set all LEDs at once. LSB is left most LED. | |
Only writes to the LED positions (every 2nd starting from 1)""" | |
self._write_data_cmd() | |
pos = 1 | |
for i in range(8): | |
self.stb(0) | |
self._set_address(pos) | |
self._byte((val >> i) & 1) | |
pos += 2 | |
self.stb(1) | |
def segments(self, segments, pos=0): | |
"""Set one or more segments at a relative position. | |
Only writes to the segment positions (every 2nd starting from 0)""" | |
if not 0 <= pos <= 7: | |
raise ValueError("Position out of range") | |
self._write_data_cmd() | |
for seg in segments: | |
self.stb(0) | |
self._set_address(pos << 1) | |
self._byte(seg) | |
pos += 1 | |
self.stb(1) | |
def keys(self): | |
"""Return a byte representing which keys are pressed. LSB is SW1""" | |
keys = 0 | |
self.stb(0) | |
self._byte(TM1638_CMD1 | TM1638_READ) | |
for i in range(4): | |
keys |= self._scan_keys() << i | |
self.stb(1) | |
return keys | |
def encode_digit(self, digit): | |
"""Convert a character 0-9, a-f to a segment.""" | |
return _SEGMENTS[digit & 0x0f] | |
def encode_string(self, string): | |
"""Convert an up to 8 character length string containing 0-9, a-z, | |
space, dash, star to an array of segments, matching the length of the | |
source string excluding dots, which are merged with previous char.""" | |
segments = bytearray(len(string.replace('.',''))) | |
j = 0 | |
for i in range(len(string)): | |
if string[i] == '.' and j > 0: | |
segments[j-1] |= (1 << 7) | |
continue | |
segments[j] = self.encode_char(string[i]) | |
j += 1 | |
return segments | |
def encode_char(self, char): | |
"""Convert a character 0-9, a-z, space, dash or star to a segment.""" | |
o = ord(char) | |
if o == 32: | |
return _SEGMENTS[36] # space | |
if o == 42: | |
return _SEGMENTS[38] # star/degrees | |
if o == 45: | |
return _SEGMENTS[37] # dash | |
if o >= 65 and o <= 90: | |
return _SEGMENTS[o-55] # uppercase A-Z | |
if o >= 97 and o <= 122: | |
return _SEGMENTS[o-87] # lowercase a-z | |
if o >= 48 and o <= 57: | |
return _SEGMENTS[o-48] # 0-9 | |
raise ValueError("Character out of range: {:d} '{:s}'".format(o, chr(o))) | |
def hex(self, val): | |
"""Display a hex value 0x00000000 through 0xffffffff, right aligned, leading zeros.""" | |
string = '{:08x}'.format(val & 0xffffffff) | |
self.segments(self.encode_string(string)) | |
def number(self, num): | |
"""Display a numeric value -9999999 through 99999999, right aligned.""" | |
# limit to range -9999999 to 99999999 | |
num = max(-9999999, min(num, 99999999)) | |
string = '{0: >8d}'.format(num) | |
self.segments(self.encode_string(string)) | |
#def float(self, num): | |
# # needs more work | |
# string = '{0:>9f}'.format(num) | |
# self.segments(self.encode_string(string[0:9])) | |
def temperature(self, num, pos=0): | |
"""Displays 2 digit temperature followed by degrees C""" | |
if num < -9: | |
self.show('lo', pos) # low | |
elif num > 99: | |
self.show('hi', pos) # high | |
else: | |
string = '{0: >2d}'.format(num) | |
self.segments(self.encode_string(string), pos) | |
self.show('*C', pos + 2) # degrees C | |
def humidity(self, num, pos=4): | |
"""Displays 2 digit humidity followed by RH""" | |
if num < -9: | |
self.show('lo', pos) # low | |
elif num > 99: | |
self.show('hi', pos) # high | |
else: | |
string = '{0: >2d}'.format(num) | |
self.segments(self.encode_string(string), pos) | |
self.show('rh', pos + 2) # relative humidity | |
def show(self, string, pos=0): | |
"""Displays a string""" | |
segments = self.encode_string(string) | |
self.segments(segments[:8], pos) | |
def scroll(self, string, delay=250): | |
"""Display a string, scrolling from the right to left, speed adjustable. | |
String starts off-screen right and scrolls until off-screen left.""" | |
segments = string if isinstance(string, list) else self.encode_string(string) | |
data = [0] * 16 | |
data[8:0] = list(segments) | |
for i in range(len(segments) + 9): | |
self.segments(data[0+i:8+i]) | |
sleep_ms(delay) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PASS = 'webrepl' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment