forked from dhylands/python_lcd
-
Notifications
You must be signed in to change notification settings - Fork 2
/
onion_lcd_gpio.py
163 lines (143 loc) · 6.17 KB
/
onion_lcd_gpio.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
"""Implements a HD44780 character LCD connected via Onion Omega GPIO pins."""
from lcd_api import LcdApi
from time import sleep
# https://docs.onion.io/omega2-docs/gpio-python-module.html#gpio-python-module
# requires a python3 modification of the current standard onionGpio (as of 2021-11-20)
from onionGpio import OnionGpio
class GpioLcd(LcdApi):
"""Implements a HD44780 character LCD connected via ESP32 GPIO pins."""
def __init__(self, rs_pin, enable_pin, d0_pin=None, d1_pin=None,
d2_pin=None, d3_pin=None, d4_pin=None, d5_pin=None,
d6_pin=None, d7_pin=None, rw_pin=None, backlight_pin=None,
num_lines=2, num_columns=16):
"""Constructs the GpioLcd object. All of the arguments must be onionGpio.OnionGpio
objects which describe which pin the given line from the LCD is
connected to.
When used in 4-bit mode, only D4, D5, D6, and D7 are physically
connected to the LCD panel. This function allows you call it like
GpioLcd(rs, enable, D4, D5, D6, D7) and it will interpret that as
if you had actually called:
GpioLcd(rs, enable, d4=D4, d5=D5, d6=D6, d7=D7)
The enable 8-bit mode, you need pass d0 through d7.
The rw pin isn't used by this library, but if you specify it, then
it will be set low.
"""
self.rs_pin = rs_pin
self.enable_pin = enable_pin
self.rw_pin = rw_pin
self.backlight_pin = backlight_pin
self._4bit = True
if d4_pin and d5_pin and d6_pin and d7_pin:
self.d0_pin = d0_pin
self.d1_pin = d1_pin
self.d2_pin = d2_pin
self.d3_pin = d3_pin
self.d4_pin = d4_pin
self.d5_pin = d5_pin
self.d6_pin = d6_pin
self.d7_pin = d7_pin
if self.d0_pin and self.d1_pin and self.d2_pin and self.d3_pin:
self._4bit = False
else:
# This is really 4-bit mode, and the 4 data pins were just
# passed as the first 4 arguments, so we switch things around.
self.d0_pin = None
self.d1_pin = None
self.d2_pin = None
self.d3_pin = None
self.d4_pin = d0_pin
self.d5_pin = d1_pin
self.d6_pin = d2_pin
self.d7_pin = d3_pin
self.rs_pin.setOutputDirection(0)
if self.rw_pin:
self.rw_pin.setOutputDirection(0)
self.enable_pin.setOutputDirection(0)
self.d4_pin.setOutputDirection(0)
self.d5_pin.setOutputDirection(0)
self.d6_pin.setOutputDirection(0)
self.d7_pin.setOutputDirection(0)
if not self._4bit:
self.d0_pin.setOutputDirection(0)
self.d1_pin.setOutputDirection(0)
self.d2_pin.setOutputDirection(0)
self.d3_pin.setOutputDirection(0)
if self.backlight_pin is not None:
self.backlight_pin.setOutputDirection(0)
# See about splitting this into begin
sleep(0.020) # Allow LCD time to powerup
# Send reset 3 times
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
sleep(0.005) # need to delay at least 4.1 msec
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
sleep(0.001)
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
sleep(0.001)
cmd = self.LCD_FUNCTION
if not self._4bit:
cmd |= self.LCD_FUNCTION_8BIT
self.hal_write_init_nibble(cmd)
sleep(0.001)
LcdApi.__init__(self, num_lines, num_columns)
if num_lines > 1:
cmd |= self.LCD_FUNCTION_2LINES
self.hal_write_command(cmd)
def hal_pulse_enable(self):
"""Pulse the enable line high, and then low again."""
self.enable_pin.setValue(0)
sleep(1/1E6)
self.enable_pin.setValue(1)
sleep(1/1E6) # Enable pulse needs to be > 450 nsec
self.enable_pin.setValue(0)
sleep(100/1E6) # Commands need > 37us to settle
def hal_write_init_nibble(self, nibble):
"""Writes an initialization nibble to the LCD.
This particular function is only used during initialization.
"""
self.hal_write_4bits(nibble >> 4)
def hal_backlight_on(self):
"""Allows the hal layer to turn the backlight on."""
if self.backlight_pin:
self.backlight_pin.setValue(1)
def hal_backlight_off(self):
"""Allows the hal layer to turn the backlight off."""
if self.backlight_pin:
self.backlight_pin.setValue(0)
def hal_write_command(self, cmd):
"""Writes a command to the LCD.
Data is latched on the falling edge of E.
"""
self.rs_pin.setValue(0)
self.hal_write_8bits(cmd)
if cmd <= 3:
# The home and clear commands require a worst
# case delay of 4.1 msec
sleep(0.005)
def hal_write_data(self, data):
"""Write data to the LCD."""
self.rs_pin.setValue(1)
self.hal_write_8bits(data)
def hal_write_8bits(self, value):
"""Writes 8 bits of data to the LCD."""
if self.rw_pin:
self.rw_pin.setValue(0)
if self._4bit:
self.hal_write_4bits(value >> 4)
self.hal_write_4bits(value)
else:
# unlike machine.Pin, onionGpio.OnionGpio.setValue needs us to convert to 0s & 1s ourselves
self.d3_pin.setValue(int(bool(value & 0x08)))
self.d2_pin.setValue(int(bool(value & 0x04)))
self.d1_pin.setValue(int(bool(value & 0x02)))
self.d0_pin.setValue(int(bool(value & 0x01)))
self.hal_write_4bits(value >> 4)
def hal_write_4bits(self, nibble):
"""Writes 4 bits of data to the LCD."""
self.d7_pin.setValue(int(bool(nibble & 0x08)))
self.d6_pin.setValue(int(bool(nibble & 0x04)))
self.d5_pin.setValue(int(bool(nibble & 0x02)))
self.d4_pin.setValue(int(bool(nibble & 0x01)))
self.hal_pulse_enable()
def hal_sleep_us(self, usecs):
"""Sleep for some time (given in microseconds)."""
time.sleep(usecs/1E6) # Uses the standard python library time module for onion omega