Skip to content

Commit 27f4245

Browse files
authored
Merge pull request #114 from FoamyGuy/nonblocking_marquee
implement non_blocking_marquee
2 parents 9ffd3a2 + 2407c6e commit 27f4245

File tree

2 files changed

+196
-117
lines changed

2 files changed

+196
-117
lines changed

adafruit_ht16k33/segments.py

100755100644
+165-117
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
adafruit_ht16k33.segments
88
=========================
99
"""
10-
11-
from time import sleep
10+
import time
1211
from adafruit_ht16k33.ht16k33 import HT16K33
1312

1413
try:
@@ -17,107 +16,106 @@
1716
except ImportError:
1817
pass
1918

20-
2119
__version__ = "0.0.0+auto.0"
2220
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HT16K33.git"
2321

2422
# fmt: off
2523
CHARS = (
26-
0b00000000, 0b00000000, #
27-
0b01000000, 0b00000110, # !
28-
0b00000010, 0b00100000, # "
29-
0b00010010, 0b11001110, # #
30-
0b00010010, 0b11101101, # $
31-
0b00001100, 0b00100100, # %
32-
0b00100011, 0b01011101, # &
33-
0b00000100, 0b00000000, # '
34-
0b00100100, 0b00000000, # (
35-
0b00001001, 0b00000000, # )
36-
0b00111111, 0b11000000, # *
37-
0b00010010, 0b11000000, # +
38-
0b00001000, 0b00000000, # ,
39-
0b00000000, 0b11000000, # -
40-
0b00000000, 0b00000000, # .
41-
0b00001100, 0b00000000, # /
42-
0b00001100, 0b00111111, # 0
43-
0b00000000, 0b00000110, # 1
44-
0b00000000, 0b11011011, # 2
45-
0b00000000, 0b10001111, # 3
46-
0b00000000, 0b11100110, # 4
47-
0b00100000, 0b01101001, # 5
48-
0b00000000, 0b11111101, # 6
49-
0b00000000, 0b00000111, # 7
50-
0b00000000, 0b11111111, # 8
51-
0b00000000, 0b11101111, # 9
52-
0b00010010, 0b00000000, # :
53-
0b00001010, 0b00000000, # ;
54-
0b00100100, 0b01000000, # <
55-
0b00000000, 0b11001000, # =
56-
0b00001001, 0b10000000, # >
57-
0b01100000, 0b10100011, # ?
58-
0b00000010, 0b10111011, # @
59-
0b00000000, 0b11110111, # A
60-
0b00010010, 0b10001111, # B
61-
0b00000000, 0b00111001, # C
62-
0b00010010, 0b00001111, # D
63-
0b00000000, 0b11111001, # E
64-
0b00000000, 0b01110001, # F
65-
0b00000000, 0b10111101, # G
66-
0b00000000, 0b11110110, # H
67-
0b00010010, 0b00000000, # I
68-
0b00000000, 0b00011110, # J
69-
0b00100100, 0b01110000, # K
70-
0b00000000, 0b00111000, # L
71-
0b00000101, 0b00110110, # M
72-
0b00100001, 0b00110110, # N
73-
0b00000000, 0b00111111, # O
74-
0b00000000, 0b11110011, # P
75-
0b00100000, 0b00111111, # Q
76-
0b00100000, 0b11110011, # R
77-
0b00000000, 0b11101101, # S
78-
0b00010010, 0b00000001, # T
79-
0b00000000, 0b00111110, # U
80-
0b00001100, 0b00110000, # V
81-
0b00101000, 0b00110110, # W
82-
0b00101101, 0b00000000, # X
83-
0b00010101, 0b00000000, # Y
84-
0b00001100, 0b00001001, # Z
85-
0b00000000, 0b00111001, # [
86-
0b00100001, 0b00000000, # \
87-
0b00000000, 0b00001111, # ]
88-
0b00001100, 0b00000011, # ^
89-
0b00000000, 0b00001000, # _
90-
0b00000001, 0b00000000, # `
91-
0b00010000, 0b01011000, # a
92-
0b00100000, 0b01111000, # b
93-
0b00000000, 0b11011000, # c
94-
0b00001000, 0b10001110, # d
95-
0b00001000, 0b01011000, # e
96-
0b00000000, 0b01110001, # f
97-
0b00000100, 0b10001110, # g
98-
0b00010000, 0b01110000, # h
99-
0b00010000, 0b00000000, # i
100-
0b00000000, 0b00001110, # j
101-
0b00110110, 0b00000000, # k
102-
0b00000000, 0b00110000, # l
103-
0b00010000, 0b11010100, # m
104-
0b00010000, 0b01010000, # n
105-
0b00000000, 0b11011100, # o
106-
0b00000001, 0b01110000, # p
107-
0b00000100, 0b10000110, # q
108-
0b00000000, 0b01010000, # r
109-
0b00100000, 0b10001000, # s
110-
0b00000000, 0b01111000, # t
111-
0b00000000, 0b00011100, # u
112-
0b00100000, 0b00000100, # v
113-
0b00101000, 0b00010100, # w
114-
0b00101000, 0b11000000, # x
115-
0b00100000, 0b00001100, # y
116-
0b00001000, 0b01001000, # z
117-
0b00001001, 0b01001001, # {
118-
0b00010010, 0b00000000, # |
119-
0b00100100, 0b10001001, # }
120-
0b00000101, 0b00100000, # ~
24+
0b00000000, 0b00000000, #
25+
0b01000000, 0b00000110, # !
26+
0b00000010, 0b00100000, # "
27+
0b00010010, 0b11001110, # #
28+
0b00010010, 0b11101101, # $
29+
0b00001100, 0b00100100, # %
30+
0b00100011, 0b01011101, # &
31+
0b00000100, 0b00000000, # '
32+
0b00100100, 0b00000000, # (
33+
0b00001001, 0b00000000, # )
34+
0b00111111, 0b11000000, # *
35+
0b00010010, 0b11000000, # +
36+
0b00001000, 0b00000000, # ,
37+
0b00000000, 0b11000000, # -
38+
0b00000000, 0b00000000, # .
39+
0b00001100, 0b00000000, # /
40+
0b00001100, 0b00111111, # 0
41+
0b00000000, 0b00000110, # 1
42+
0b00000000, 0b11011011, # 2
43+
0b00000000, 0b10001111, # 3
44+
0b00000000, 0b11100110, # 4
45+
0b00100000, 0b01101001, # 5
46+
0b00000000, 0b11111101, # 6
47+
0b00000000, 0b00000111, # 7
48+
0b00000000, 0b11111111, # 8
49+
0b00000000, 0b11101111, # 9
50+
0b00010010, 0b00000000, # :
51+
0b00001010, 0b00000000, # ;
52+
0b00100100, 0b01000000, # <
53+
0b00000000, 0b11001000, # =
54+
0b00001001, 0b10000000, # >
55+
0b01100000, 0b10100011, # ?
56+
0b00000010, 0b10111011, # @
57+
0b00000000, 0b11110111, # A
58+
0b00010010, 0b10001111, # B
59+
0b00000000, 0b00111001, # C
60+
0b00010010, 0b00001111, # D
61+
0b00000000, 0b11111001, # E
62+
0b00000000, 0b01110001, # F
63+
0b00000000, 0b10111101, # G
64+
0b00000000, 0b11110110, # H
65+
0b00010010, 0b00000000, # I
66+
0b00000000, 0b00011110, # J
67+
0b00100100, 0b01110000, # K
68+
0b00000000, 0b00111000, # L
69+
0b00000101, 0b00110110, # M
70+
0b00100001, 0b00110110, # N
71+
0b00000000, 0b00111111, # O
72+
0b00000000, 0b11110011, # P
73+
0b00100000, 0b00111111, # Q
74+
0b00100000, 0b11110011, # R
75+
0b00000000, 0b11101101, # S
76+
0b00010010, 0b00000001, # T
77+
0b00000000, 0b00111110, # U
78+
0b00001100, 0b00110000, # V
79+
0b00101000, 0b00110110, # W
80+
0b00101101, 0b00000000, # X
81+
0b00010101, 0b00000000, # Y
82+
0b00001100, 0b00001001, # Z
83+
0b00000000, 0b00111001, # [
84+
0b00100001, 0b00000000, # \
85+
0b00000000, 0b00001111, # ]
86+
0b00001100, 0b00000011, # ^
87+
0b00000000, 0b00001000, # _
88+
0b00000001, 0b00000000, # `
89+
0b00010000, 0b01011000, # a
90+
0b00100000, 0b01111000, # b
91+
0b00000000, 0b11011000, # c
92+
0b00001000, 0b10001110, # d
93+
0b00001000, 0b01011000, # e
94+
0b00000000, 0b01110001, # f
95+
0b00000100, 0b10001110, # g
96+
0b00010000, 0b01110000, # h
97+
0b00010000, 0b00000000, # i
98+
0b00000000, 0b00001110, # j
99+
0b00110110, 0b00000000, # k
100+
0b00000000, 0b00110000, # l
101+
0b00010000, 0b11010100, # m
102+
0b00010000, 0b01010000, # n
103+
0b00000000, 0b11011100, # o
104+
0b00000001, 0b01110000, # p
105+
0b00000100, 0b10000110, # q
106+
0b00000000, 0b01010000, # r
107+
0b00100000, 0b10001000, # s
108+
0b00000000, 0b01111000, # t
109+
0b00000000, 0b00011100, # u
110+
0b00100000, 0b00000100, # v
111+
0b00101000, 0b00010100, # w
112+
0b00101000, 0b11000000, # x
113+
0b00100000, 0b00001100, # y
114+
0b00001000, 0b01001000, # z
115+
0b00001001, 0b01001001, # {
116+
0b00010010, 0b00000000, # |
117+
0b00100100, 0b10001001, # }
118+
0b00000101, 0b00100000, # ~
121119
0b00111111, 0b11111111,
122120
)
123121
# fmt: on
@@ -189,6 +187,10 @@ def __init__(
189187

190188
self._chars = chars_per_display * len(self.i2c_device)
191189
self._bytes_per_char = 2
190+
self._last_nb_scroll_time = -1
191+
self._nb_scroll_text = None
192+
self._nb_scroll_index = -1
193+
self._nb_prev_char_is_dot = False
192194

193195
def print(self, value: Union[str, float], decimal: int = 0) -> None:
194196
"""Print the value to the display.
@@ -367,38 +369,84 @@ def set_digit_raw(
367369
if self._auto_write:
368370
self.show()
369371

370-
def marquee(self, text: str, delay: float = 0.25, loop: bool = True) -> None:
372+
def non_blocking_marquee(
373+
self,
374+
text: str,
375+
delay: float = 0.25,
376+
loop: bool = True,
377+
space_between: bool = False,
378+
) -> bool:
371379
"""
372-
Automatically scroll the text at the specified delay between characters
380+
Scroll the text at the specified delay between characters. Must be called
381+
repeatedly from main loop faster than delay time.
373382
374383
:param str text: The text to display
375384
:param float delay: (optional) The delay in seconds to pause before scrolling
376385
to the next character (default=0.25)
377386
:param bool loop: (optional) Whether to endlessly loop the text (default=True)
378-
387+
:param bool space_between: (optional) Whether to seperate the end and beginning of
388+
the text with a space. (default=False)
379389
"""
390+
# pylint: disable=too-many-nested-blocks
380391
if isinstance(text, str):
381-
self.fill(False)
382-
if loop:
383-
while True:
384-
self._scroll_marquee(text, delay)
392+
now = time.monotonic()
393+
# if text is the same
394+
if text == self._nb_scroll_text:
395+
# if we delayed long enough, and it's time to scroll
396+
if now >= self._last_nb_scroll_time + delay:
397+
# if there are chars left in the text
398+
if self._nb_scroll_index + 1 < len(text):
399+
self._nb_scroll_index += 1
400+
401+
_character = text[self._nb_scroll_index]
402+
403+
if _character != "." or self._nb_prev_char_is_dot:
404+
self._last_nb_scroll_time = now
405+
406+
self.print(text[self._nb_scroll_index])
407+
self._nb_prev_char_is_dot = text[self._nb_scroll_index] == "."
408+
else:
409+
self._nb_scroll_index = -1
410+
if loop:
411+
if space_between:
412+
self._last_nb_scroll_time = now
413+
self.print(" ")
414+
else:
415+
return True
385416
else:
386-
self._scroll_marquee(text, delay)
417+
# different text
418+
self._nb_scroll_index = 0
419+
self.fill(False)
420+
self._nb_scroll_text = text
421+
self._last_nb_scroll_time = now
422+
self.print(text[0])
387423

388-
def _scroll_marquee(self, text: str, delay: float) -> None:
389-
"""Scroll through the text string once using the delay"""
390-
char_is_dot = False
391-
for character in text:
392-
self.print(character)
393-
# Add delay if character is not a dot or more than 2 in a row
394-
if character != "." or char_is_dot:
395-
sleep(delay)
396-
char_is_dot = character == "."
397-
self.show()
424+
return False
425+
426+
def marquee(
427+
self, text: str, delay: float = 0.25, loop: bool = True, space_between=False
428+
) -> None:
429+
"""
430+
Automatically scroll the text at the specified delay between characters
431+
432+
:param str text: The text to display
433+
:param float delay: (optional) The delay in seconds to pause before scrolling
434+
to the next character (default=0.25)
435+
:param bool loop: (optional) Whether to endlessly loop the text (default=True)
436+
:param bool space_between: (optional) Whether to seperate the end and beginning of
437+
the text with a space. (default=False)
438+
"""
439+
if isinstance(text, str):
440+
self.fill(False)
441+
while True:
442+
if self.non_blocking_marquee(
443+
text=text, delay=delay, loop=loop, space_between=space_between
444+
):
445+
return
398446

399447

400448
class _AbstractSeg7x4(Seg14x4):
401-
POSITIONS = (0, 2, 6, 8) # The positions of characters.
449+
POSITIONS = (0, 2, 6, 8) # The positions of characters.
402450

403451
def __init__( # pylint: disable=too-many-arguments
404452
self,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# SPDX-FileCopyrightText: 2023 Tim Cocks for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
"""
4+
Example that uses Non-Blocking Marquee to scroll text on 14x4 segment
5+
while also blinking the on-board neopixel at a different rate from the
6+
marquee scrolling.
7+
"""
8+
9+
import time
10+
import board
11+
import neopixel
12+
import adafruit_ht16k33.segments
13+
14+
15+
i2c = board.I2C()
16+
segment_display = adafruit_ht16k33.segments.Seg14x4(i2c)
17+
18+
pixel_pin = board.NEOPIXEL
19+
pixels = neopixel.NeoPixel(pixel_pin, 1, brightness=0.1, auto_write=True)
20+
21+
pixels[0] = 0xFF0000
22+
last_blink = 0
23+
while True:
24+
now = time.monotonic()
25+
if now > last_blink + 0.3:
26+
if pixels[0] == (255, 0, 255):
27+
pixels[0] = 0x00FF00
28+
else:
29+
pixels[0] = 0xFF00FF
30+
last_blink = now
31+
segment_display.non_blocking_marquee("CircuitPython <3", delay=0.2)

0 commit comments

Comments
 (0)