forked from adafruit/Adafruit_CircuitPython_74HC595
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsimple_74hc595.py
177 lines (136 loc) · 5.18 KB
/
simple_74hc595.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`simple_74hc595`
====================================================
CircuitPython driver for 74HC595 shift register.
* Author(s): Kattni Rembor, Tony DiCola
Implementation Notes
--------------------
**Hardware:**
"* `74HC595 Shift Register - 3 pack <https://www.adafruit.com/product/450>`_"
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
"""
import digitalio
__version__ = "1.0.0-auto.0"
__repo__ = "https://github.com/LennartPiro/simple_CircuitPython_74HC595"
class simple_74hc595:
def __init__(self, data_pin, clock_pin, latch_pin):
def is_inout_pin(pin):
return hasattr(pin, 'direction') and hasattr(pin, 'value')
if is_inout_pin(data_pin):
self.data_pin = data_pin
else:
self.data_pin = digitalio.DigitalInOut(data_pin)
self.data_pin.direction = digitalio.Direction.OUTPUT
if is_inout_pin(clock_pin):
self.clock_pin = clock_pin
else:
self.clock_pin = digitalio.DigitalInOut(clock_pin)
self.clock_pin.direction = digitalio.Direction.OUTPUT
if is_inout_pin(latch_pin):
self.latch_pin = latch_pin
else:
self.latch_pin = digitalio.DigitalInOut(latch_pin)
self.latch_pin.direction = digitalio.Direction.OUTPUT
self._end_push_values()
def _push_bit(self, value):
self.clock_pin.value = False
self.data_pin.value = value
self.clock_pin.value = True
def _begin_push_values(self):
self.clock_pin.value = False
self.latch_pin.value = False
self.clock_pin.value = True
def _end_push_values(self):
self.clock_pin.value = False
self.latch_pin.value = True
self.clock_pin.value = True
def write_byte(self, value):
assert 0 <= value <= 255
self._begin_push_values()
for i in range(8):
self._push_bit((value >> (7 - i)) & 1)
self._end_push_values()
def write_byte_array(self, values):
assert len(values) == 8
self._begin_push_values()
for v in values:
self._push_bit(v)
self._end_push_values()
class DigitalInOut:
# """Digital input/output of the 74HC595. The interface is exactly the
# same as the ``digitalio.DigitalInOut`` class, however note that by design
# this device is OUTPUT ONLY! Attempting to read inputs or set
# direction as input will raise an exception.
# """
def __init__(self, pin_number, shift_register_74hc595):
# """Specify the pin number of the shift register (0...7) and
# ShiftRegister74HC595 instance.
# """
self._pin = pin_number
self._shift_register = shift_register_74hc595
# kwargs in switch functions below are _necessary_ for compatibility
# with DigitalInout class (which allows specifying pull, etc. which
# is unused by this class). Do not remove them, instead turn off pylint
# in this case.
def switch_to_output(self, value=False, **kwargs):
self.direction = digitalio.Direction.OUTPUT
self.value = value
def switch_to_input(self, **kwargs):
raise RuntimeError("Digital input not supported.")
@property
def value(self):
return self._shift_register.read_bit(self._pin)
@value.setter
def value(self, val):
self._shift_register.write_bit(self._pin, val)
@property
def direction(self):
return digitalio.Direction.OUTPUT
@direction.setter
def direction(self, val):
if val != digitalio.Direction.OUTPUT:
raise RuntimeError("Digital input not supported.")
@property
def pull(self):
return None
@pull.setter
def pull(self, val):
if val is not None:
raise RuntimeError("Pull-up and pull-down not supported.")
class stateful_74hc595(simple_74hc595):
def __init__(self, data_pin, clock_pin, latch_pin, initial_state=0):
assert 0 <= initial_state <= 255
super().__init__(
data_pin, clock_pin, latch_pin
)
self.pin_state = initial_state
self.update()
def update(self):
self.write_byte(self.pin_state)
def write_bit(self, pin_number, value):
assert 0 <= pin_number <= 7
if value:
self.pin_state |= 1 << pin_number
else:
self.pin_state ^= self.pin_state & (1 << pin_number)
self.update()
def read_bit(self, pin_number):
assert 0 <= pin_number <= 7
return (self.pin_state & (1 << pin_number)) > 0
def get_pin(self, pin):
# """Convenience function to create an instance of the DigitalInOut class
# pointing at the specified pin of this 74HC595 device .
# """
assert 0 <= pin <= 7
return DigitalInOut(pin, self)
def write_byte_array(self, values):
super().write_byte_array(values)
self.pin_state = sum((1<<i) if values[7 - i] else 0 for i in range(8))
def write_byte(self, value):
super().write_byte(value)
self.pin_state = value