16x2 LCD Display
LCD Displays can be configured for I2C or Parallel communication with a microcontroller. When configured with an I2C driver, much of the following is abstracted away for the user. Contrast, brightness, and pinouts are much less complicated in this approach at the cost of price and speed.
Using parallel communication, the LCD is wired to the microcontroller with either four-bit or eight bit communication 1. A potentiometer should be connected for contrast control of the LCD, and a 500 ohm resistor for brightness control. If the user desires adaptive brightness control, a photoresistor and 1k-ohm resistor can be connected in parallel.
Using 4-bit parallel communication, a nibble of data is sent to the display simultaneously. 8-bit parallel will communicate a full byte simultaneously. Regardless of method, a full byte of data is then sent to the device in a process called bit-banging. This splits a byte of data to send two nibbles in series for 4-bit communication, ordered by the upper four bits and then the lower four bits.
- class src.pico_devboard.LCD.LCD(enable_pin: int, reg_select_pin: int, data_pins: list)
The LCD class is meant to abstract the LCD driver further and streamline development.
- CMD_MODE = 0
- DATA_MODE = 1
- blink()
Have the cursor start blinking.
- clear()
Clears the LCD Screen.
Good to perform on occasion but produces flashing on screen when triggered consistently.
- cursor_off()
Turn the cursor off.
- cursor_on()
Have the cursor on, Good for debugging.
- go_to(column, row)
Move the cursor to a specific column and row.
- Parameters
column (int) – Column index, 0-15. May be higher on different size LCDs
row (int) – Row index, 0-1. May be higher on different size LCDs
- Returns
None
- home()
Return the Cursor to the starting position.
Functionally the same as using the go_to function and specifying (0, 0) coordinates.
- init()
Initializes the LCD for communication.
- print(string)
Write a string on to the LCD.
Wrapper of the string function with more descriptive naming.
- Parameters
string (str) – String desired to be written.
- strobe()
Flashes the enable line and provides wait period.
- write(command, mode)
Sends data to the LCD module.
- Parameters
command (str) – Information packet being sent to the LCD.
mode (int) – Mode of operation for the LCD, either command mode (1) or data mode (0)
- Returns
None
Code
1# -----------------------------------------
2# NOTES
3# -----------------------------------------
4"""
5Dieter Steinhauser
65/2023
7Parallel LCD functions, Configured for 4-bit communication.
8"""
9
10# -----------------------------------------
11# IMPORTS
12# -----------------------------------------
13
14from machine import Pin
15import time
16utime = time
17
18# -----------------------------------------
19# CONSTANTS AND VARIABLES
20# -----------------------------------------
21
22# CONSTANTS
23# ----------------------
24
25LCD_CMD = 0
26LCD_DATA = 1
27
28# ----------------------
29# GPIO Wiring: Legacy Structure
30# ----------------------
31
32# EN = Pin(0, Pin.OUT) # Enable Pin
33# RS = Pin(1, Pin.OUT) # Register Select
34
35# PINS = [2, 3, 4, 5]
36# Pin numbers for the upper nibble, does the below assignment in configure method.
37# D4 = Pin(2, Pin.OUT)
38# D5 = Pin(3, Pin.OUT)
39# D6 = Pin(4, Pin.OUT)
40# D7 = Pin(5, Pin.OUT)
41
42# list that gets populated with pinout objects for data line.
43# DATA_BUS = []
44
45# -----------------------------------------
46# METHODS
47# -----------------------------------------
48
49# def Configure():
50# """Creates the data bus object from the pin list"""
51
52# for index in range(4):
53# DATA_BUS.append(Pin(PINS[index], Pin.OUT))
54
55# # -----------------------------------------
56
57# def lcd_strobe():
58# """Flashes the enable line and provides wait period."""
59
60# EN.value(1)
61# utime.sleep_ms(1)
62
63# EN.value(0)
64# utime.sleep_ms(1)
65
66# # -----------------------------------------
67
68# def lcd_write(command, mode):
69# """Sends data to the LCD module. """
70
71# # determine if writing a command or data
72# data = command if mode == 0 else ord(command)
73
74# # need upper nibble for first loop. lower nibble can use data directly.
75# upper = data >> 4
76
77# # write the upper nibble
78# for index in range(4):
79# bit = upper & 1
80# DATA_BUS[index].value(bit)
81# upper = upper >> 1
82
83# # strobe the LCD, sending the nibble
84# RS.value(mode)
85# lcd_strobe()
86
87# # write the lower nibble
88# for index in range(4):
89# bit = data & 1
90# DATA_BUS[index].value(bit)
91# data = data >> 1
92
93# # Strobe the LCD, sending the nibble
94# RS.value(mode)
95# lcd_strobe()
96# utime.sleep_ms(1)
97# RS.value(1)
98
99# # -----------------------------------------
100
101# def lcd_clear():
102# """Clear the LCD Screen."""
103
104# lcd_write(0x01, 0)
105# utime.sleep_ms(5)
106
107# # -----------------------------------------
108
109# def lcd_home():
110# """Return the Cursor to the starting position."""
111
112# lcd_write(0x02, 0)
113# utime.sleep_ms(5)
114
115# # -----------------------------------------
116
117
118# def lcd_cursor_blink():
119# """Have the cursor start blinking."""
120
121# lcd_write(0x0D, 0)
122# utime.sleep_ms(1)
123
124# # -----------------------------------------
125
126# def lcd_cursor_on():
127# """Have the cursor on, Good for debugging."""
128
129# lcd_write(0x0E, 0)
130# utime.sleep_ms(1)
131
132# # -----------------------------------------
133
134# def lcd_cursor_off():
135# """Turn the cursor off."""
136
137# lcd_write(0x0C, 0)
138# utime.sleep_ms(1)
139
140# # -----------------------------------------
141
142# def lcd_puts(string):
143# """Write a string on to the LCD."""
144
145# for element in string:
146# lcd_putch(element)
147
148# # -----------------------------------------
149
150# def lcd_putch(c):
151# """Write a character on to the LCD."""
152# lcd_write(c, 1)
153
154# # -----------------------------------------
155
156# def lcd_goto(column, row):
157
158
159# if row == 0:
160# address = 0
161
162# if row == 1:
163# address = 0x40
164
165# if row == 2:
166# address = 0x14
167
168# if row == 3:
169# address = 0x54
170
171# address = address + column
172# lcd_write(0x80 | address, 0)
173
174# # -----------------------------------------
175
176# def lcd_init():
177
178# # Configure the pins of the device.
179# Configure()
180# utime.sleep_ms(120)
181
182# # clear values on data bus.
183# for index in range(4):
184# DATA_BUS[index].value(0)
185# utime.sleep_ms(50)
186
187# # initialization sequence.
188# DATA_BUS[0].value(1)
189# DATA_BUS[1].value(1)
190# lcd_strobe()
191# utime.sleep_ms(10)
192
193# lcd_strobe()
194# utime.sleep_ms(10)
195
196# lcd_strobe()
197# utime.sleep_ms(10)
198
199# DATA_BUS[0].value(0)
200# lcd_strobe()
201# utime.sleep_ms(5)
202
203# lcd_write(0x28, 0)
204# utime.sleep_ms(1)
205
206# lcd_write(0x08, 0)
207# utime.sleep_ms(1)
208
209# lcd_write(0x01, 0)
210# utime.sleep_ms(10)
211
212# lcd_write(0x06, 0)
213# utime.sleep_ms(5)
214
215# lcd_write(0x0C, 0)
216# utime.sleep_ms(10)
217
218
219# -----------------------------------------
220# LCD Class:
221# -----------------------------------------
222
223
224class LCD:
225 """The LCD class is meant to abstract the LCD driver further and streamline development."""
226
227 CMD_MODE = 0
228 DATA_MODE = 1
229
230 def __init__(self, enable_pin: int, reg_select_pin: int, data_pins: list) -> None:
231 """
232 Object initialization.
233
234 :param enable_pin: integer value of the enable pin desired.
235 :type enable_pin: int
236 :param reg_select_pin: integer value of the reg_select pin desired.
237 :type reg_select_pin: int
238 :param data_pins: list of integer values for the data pins desired in communication.
239 :type data_pins: list[int]
240 """
241
242 self.enable_pin = Pin(enable_pin, Pin.OUT)
243 self.reg_select_pin = Pin(reg_select_pin, Pin.OUT)
244 self._data_pins = data_pins
245 self.data_bus = []
246
247 # Configure the pins of the device.
248 self._configure()
249 utime.sleep_ms(120)
250
251 # -----------------------------------------
252
253 def _configure(self):
254 """Creates the data bus object from the pin list. """
255
256 # Configure the pins of the device.
257 for element in self._data_pins:
258 self.data_bus.append(Pin(element, Pin.OUT))
259
260 # -----------------------------------------
261
262 def init(self):
263 """Initializes the LCD for communication."""
264
265 # clear values on data bus.
266 for index in range(4):
267 self.data_bus[index].value(0)
268 utime.sleep_ms(50)
269
270 # initialization sequence.
271 self.data_bus[0].value(1)
272 self.data_bus[1].value(1)
273 self.strobe()
274 utime.sleep_ms(10)
275
276 self.strobe()
277 utime.sleep_ms(10)
278
279 self.strobe()
280 utime.sleep_ms(10)
281
282 self.data_bus[0].value(0)
283 self.strobe()
284 utime.sleep_ms(5)
285
286 self.write(0x28, 0)
287 utime.sleep_ms(1)
288
289 self.write(0x08, 0)
290 utime.sleep_ms(1)
291
292 self.write(0x01, 0)
293 utime.sleep_ms(10)
294
295 self.write(0x06, 0)
296 utime.sleep_ms(5)
297
298 self.write(0x0C, 0)
299 utime.sleep_ms(10)
300
301 # -----------------------------------------
302
303 def strobe(self):
304 """
305 Flashes the enable line and provides wait period.
306 """
307
308 self.enable_pin.value(1)
309 utime.sleep_ms(1)
310
311 self.enable_pin.value(0)
312 utime.sleep_ms(1)
313
314 # -----------------------------------------
315
316 def write(self, command, mode):
317 """
318 Sends data to the LCD module.
319
320 :param command: Information packet being sent to the LCD.
321 :type command: str
322 :param mode: Mode of operation for the LCD, either command mode (1) or data mode (0)
323 :type mode: int
324 :return: None
325 """
326
327 # determine if writing a command or data
328 data = command if mode == 0 else ord(command)
329
330 # need upper nibble for first loop. lower nibble can use data directly.
331 upper = data >> 4
332
333 # write the upper nibble
334 for index in range(4):
335 bit = upper & 1
336 self.data_bus[index].value(bit)
337 upper = upper >> 1
338
339 # strobe the LCD, sending the nibble
340 self.reg_select_pin.value(mode)
341 self.strobe()
342
343 # write the lower nibble
344 for index in range(4):
345 bit = data & 1
346 self.data_bus[index].value(bit)
347 data = data >> 1
348
349 # Strobe the LCD, sending the nibble
350 self.reg_select_pin.value(mode)
351 self.strobe()
352 utime.sleep_ms(1)
353 self.reg_select_pin.value(1)
354
355 # -----------------------------------------
356
357 def clear(self):
358 """
359 Clears the LCD Screen.
360
361 Good to perform on occasion but produces flashing on screen when triggered consistently.
362 """
363
364 self.write(0x01, 0)
365 utime.sleep_ms(5)
366
367 # -----------------------------------------
368
369 def home(self):
370 """
371 Return the Cursor to the starting position.
372
373 Functionally the same as using the go_to function and specifying (0, 0) coordinates.
374 """
375
376 self.write(0x02, 0)
377 utime.sleep_ms(5)
378
379 # -----------------------------------------
380
381
382 def blink(self):
383 """
384 Have the cursor start blinking.
385 """
386
387 self.write(0x0D, 0)
388 utime.sleep_ms(1)
389
390 # -----------------------------------------
391
392 def cursor_on(self):
393 """
394 Have the cursor on, Good for debugging.
395 """
396
397 self.write(0x0E, 0)
398 utime.sleep_ms(1)
399
400 # -----------------------------------------
401
402 def cursor_off(self):
403 """
404 Turn the cursor off.
405 """
406
407 self.write(0x0C, 0)
408 utime.sleep_ms(1)
409
410 # -----------------------------------------
411
412 def print(self, string):
413 """
414 Write a string on to the LCD.
415
416 Wrapper of the string function with more descriptive naming.
417
418 :param string: String desired to be written.
419 :type string: str
420
421 """
422
423 for element in string:
424 self._putch(element)
425
426 # -----------------------------------------
427
428 def _putch(self, c):
429 """
430 Write a character on to the LCD.
431
432 Protected because the method is less intuitive compared to the print.
433
434 :param c: ASCII character.
435 :type c: str
436 :return: None
437 """
438 self.write(c, 1)
439
440 # -----------------------------------------
441
442 def _puts(self, string):
443 """
444 Write a string on to the LCD.
445
446 :param string: String desired to be written.
447 :type string: str
448 :return: None
449 """
450
451 for element in string:
452 self._putch(element)
453
454 # -----------------------------------------
455 def go_to(self, column, row):
456 """
457 Move the cursor to a specific column and row.
458
459 :param column: Column index, 0-15. May be higher on different size LCDs
460 :type column: int
461 :param row: Row index, 0-1. May be higher on different size LCDs
462 :type row: int
463 :return: None
464 """
465 if row == 0:
466 address = 0
467
468 if row == 1:
469 address = 0x40
470
471 if row == 2:
472 address = 0x14
473
474 if row == 3:
475 address = 0x54
476
477 address = address + column
478 self.write(0x80 | address, 0)
479
480
481# -----------------------------------------
482# END OF FILE
483# -----------------------------------------
References
- 1
“Sitronix ST7066U - Crystalfontz,” crystalfontz. [Online]. Available: https://www.crystalfontz.com/controllers/Sitronix/ST7066U/438. [Accessed: 03-Oct2022].