|
37 | 37 | """
|
38 | 38 | import time
|
39 | 39 | import math
|
| 40 | + |
40 | 41 | import digitalio
|
41 | 42 | from board import *
|
42 | 43 |
|
| 44 | + |
43 | 45 | # Commands
|
44 | 46 | LCD_CLEARDISPLAY = const(0x01)
|
45 | 47 | LCD_RETURNHOME = const(0x02)
|
|
81 | 83 | # Offset for up to 4 rows.
|
82 | 84 | LCD_ROW_OFFSETS = (0x00, 0x40, 0x14, 0x54)
|
83 | 85 |
|
| 86 | +# MCP23008 I2C backpack pin mapping from LCD logical pin to MCP23008 pin. |
| 87 | +_MCP23008_LCD_RS = const(1) |
| 88 | +_MCP23008_LCD_EN = const(2) |
| 89 | +_MCP23008_LCD_D4 = const(3) |
| 90 | +_MCP23008_LCD_D5 = const(4) |
| 91 | +_MCP23008_LCD_D6 = const(5) |
| 92 | +_MCP23008_LCD_D7 = const(6) |
| 93 | +_MCP23008_LCD_BACKLIGHT = const(7) |
| 94 | + |
| 95 | +# 74LS595 SPI backpack pin mapping from LCD logical pin to 74LS595 pin. |
| 96 | +_74LS595_LCD_RS = const(1) |
| 97 | +_74LS595_LCD_EN = const(2) |
| 98 | +_74LS595_LCD_D4 = const(6) |
| 99 | +_74LS595_LCD_D5 = const(5) |
| 100 | +_74LS595_LCD_D6 = const(4) |
| 101 | +_74LS595_LCD_D7 = const(3) |
| 102 | +_74LS595_LCD_BACKLIGHT = const(7) |
| 103 | + |
| 104 | + |
| 105 | +def _set_bit(byte_value, position, val): |
| 106 | + # Given the specified byte_value set the bit at position to the provided |
| 107 | + # boolean value val and return the modified byte. |
| 108 | + if val: |
| 109 | + return byte_value | (1 << position) |
| 110 | + else: |
| 111 | + return byte_value & ~(1 << position) |
| 112 | + |
| 113 | + |
84 | 114 | class Character_LCD(object):
|
85 | 115 | """ Interfaces with a character LCD
|
86 | 116 | :param ~digitalio.DigitalInOut rs: The reset data line
|
@@ -280,3 +310,119 @@ def create_char(self, location, pattern):
|
280 | 310 | self._write8(LCD_SETCGRAMADDR | (location << 3))
|
281 | 311 | for i in range(8):
|
282 | 312 | self._write8(pattern[i], char_mode=True)
|
| 313 | + |
| 314 | + |
| 315 | +class Character_LCD_I2C(Character_LCD): |
| 316 | + """Character LCD connected to I2C/SPI backpack using its I2C connection. |
| 317 | + This is a subclass of Character_LCD and implements all of the same |
| 318 | + functions and functionality. |
| 319 | + """ |
| 320 | + |
| 321 | + def __init__(self, i2c, cols, lines): |
| 322 | + """Initialize character LCD connectedto backpack using I2C connection |
| 323 | + on the specified I2C bus and of the specified number of columns and |
| 324 | + lines on the display. |
| 325 | + """ |
| 326 | + # Import the MCP23008 module here when the class is used |
| 327 | + # to keep memory usage low. If you attempt to import globally at the |
| 328 | + # top of this file you WILL run out of memory on the M0, even with |
| 329 | + # MPY files. The amount of code and classes implicitly imported |
| 330 | + # by all the SPI and I2C code is too high. Thus import on demand. |
| 331 | + import adafruit_character_lcd.mcp23008 as mcp23008 |
| 332 | + self._mcp = mcp23008.MCP23008(i2c, address) |
| 333 | + # Setup pins for I2C backpack, see diagram: |
| 334 | + # https://learn.adafruit.com/assets/35681 |
| 335 | + rs = self._mcp.DigitalInOut(_MCP23008_LCD_RS, self._mcp) |
| 336 | + en = self._mcp.DigitalInOut(_MCP23008_LCD_EN, self._mcp) |
| 337 | + d4 = self._mcp.DigitalInOut(_MCP23008_LCD_D4, self._mcp) |
| 338 | + d5 = self._mcp.DigitalInOut(_MCP23008_LCD_D5, self._mcp) |
| 339 | + d6 = self._mcp.DigitalInOut(_MCP23008_LCD_D6, self._mcp) |
| 340 | + d7 = self._mcp.DigitalInOut(_MCP23008_LCD_D7, self._mcp) |
| 341 | + backlight = self._mcp.DigitalInOut(_MCP23008_LCD_BACKLIGHT, self._mcp) |
| 342 | + # Call superclass initializer with MCP23008 pins. |
| 343 | + super().__init__(rs, en, d4, d5, d6, d7, cols, lines, |
| 344 | + backlight=backlight) |
| 345 | + |
| 346 | + def _write8(self, value, char_mode=False): |
| 347 | + # Optimize a command write by changing all GPIO pins at once instead |
| 348 | + # of letting the super class try to set each one invidually (far too |
| 349 | + # slow with overhead of I2C communication). |
| 350 | + gpio = self._mcp.gpio |
| 351 | + # Make sure enable is low. |
| 352 | + gpio = _set_bit(gpio, _MCP23008_LCD_EN, False) |
| 353 | + # Set character/data bit. (charmode = False). |
| 354 | + gpio = _set_bit(gpio, _MCP23008_LCD_RS, char_mode) |
| 355 | + # Set upper 4 bits. |
| 356 | + gpio = _set_bit(gpio, _MCP23008_LCD_D4, ((value >> 4) & 1) > 0) |
| 357 | + gpio = _set_bit(gpio, _MCP23008_LCD_D5, ((value >> 5) & 1) > 0) |
| 358 | + gpio = _set_bit(gpio, _MCP23008_LCD_D6, ((value >> 6) & 1) > 0) |
| 359 | + gpio = _set_bit(gpio, _MCP23008_LCD_D7, ((value >> 7) & 1) > 0) |
| 360 | + self._mcp.gpio = gpio |
| 361 | + # Send command. |
| 362 | + self._pulse_enable() |
| 363 | + # Now repeat for lower 4 bits. |
| 364 | + gpio = self._mcp.gpio |
| 365 | + gpio = _set_bit(gpio, _MCP23008_LCD_EN, False) |
| 366 | + gpio = _set_bit(gpio, _MCP23008_LCD_RS, char_mode) |
| 367 | + gpio = _set_bit(gpio, _MCP23008_LCD_D4, (value & 1) > 0) |
| 368 | + gpio = _set_bit(gpio, _MCP23008_LCD_D5, ((value >> 1) & 1) > 0) |
| 369 | + gpio = _set_bit(gpio, _MCP23008_LCD_D6, ((value >> 2) & 1) > 0) |
| 370 | + gpio = _set_bit(gpio, _MCP23008_LCD_D7, ((value >> 3) & 1) > 0) |
| 371 | + self._mcp.gpio = gpio |
| 372 | + self._pulse_enable() |
| 373 | + |
| 374 | + |
| 375 | +class Character_LCD_SPI(Character_LCD): |
| 376 | + """Character LCD connected to I2C/SPI backpack using its SPI connection. |
| 377 | + This is a subclass of Character_LCD and implements all of the same |
| 378 | + functions and functionality. |
| 379 | + """ |
| 380 | + |
| 381 | + def __init__(self, spi, latch, cols, lines): |
| 382 | + """Initialize character LCD connectedto backpack using SPI connection |
| 383 | + on the specified SPI bus and latch line with the specified number of |
| 384 | + columns and lines on the display. |
| 385 | + """ |
| 386 | + # See comment above on I2C class for why this is imported here: |
| 387 | + import adafruit_character_lcd.shift_reg_74ls595 as shift_reg_74ls595 |
| 388 | + self._sr = shift_reg_74ls595.ShiftReg74LS595(spi, latch) |
| 389 | + # Setup pins for SPI backpack, see diagram: |
| 390 | + # https://learn.adafruit.com/assets/35681 |
| 391 | + rs = self._sr.DigitalInOut(_74LS595_LCD_RS, self._sr) |
| 392 | + en = self._sr.DigitalInOut(_74LS595_LCD_EN, self._sr) |
| 393 | + d4 = self._sr.DigitalInOut(_74LS595_LCD_D4, self._sr) |
| 394 | + d5 = self._sr.DigitalInOut(_74LS595_LCD_D5, self._sr) |
| 395 | + d6 = self._sr.DigitalInOut(_74LS595_LCD_D6, self._sr) |
| 396 | + d7 = self._sr.DigitalInOut(_74LS595_LCD_D7, self._sr) |
| 397 | + backlight = self._sr.DigitalInOut(_74LS595_LCD_BACKLIGHT, self._sr) |
| 398 | + # Call superclass initializer with shift register pins. |
| 399 | + super().__init__(rs, en, d4, d5, d6, d7, cols, lines, |
| 400 | + backlight=backlight) |
| 401 | + |
| 402 | + def _write8(self, value, char_mode=False): |
| 403 | + # Optimize a command write by changing all GPIO pins at once instead |
| 404 | + # of letting the super class try to set each one invidually (far too |
| 405 | + # slow with overhead of SPI communication). |
| 406 | + gpio = self._sr.gpio |
| 407 | + # Make sure enable is low. |
| 408 | + gpio = _set_bit(gpio, _74LS595_LCD_EN, False) |
| 409 | + # Set character/data bit. (charmode = False). |
| 410 | + gpio = _set_bit(gpio, _74LS595_LCD_RS, char_mode) |
| 411 | + # Set upper 4 bits. |
| 412 | + gpio = _set_bit(gpio, _74LS595_LCD_D4, ((value >> 4) & 1) > 0) |
| 413 | + gpio = _set_bit(gpio, _74LS595_LCD_D5, ((value >> 5) & 1) > 0) |
| 414 | + gpio = _set_bit(gpio, _74LS595_LCD_D6, ((value >> 6) & 1) > 0) |
| 415 | + gpio = _set_bit(gpio, _74LS595_LCD_D7, ((value >> 7) & 1) > 0) |
| 416 | + self._sr.gpio = gpio |
| 417 | + # Send command. |
| 418 | + self._pulse_enable() |
| 419 | + # Now repeat for lower 4 bits. |
| 420 | + gpio = self._sr.gpio |
| 421 | + gpio = _set_bit(gpio, _74LS595_LCD_EN, False) |
| 422 | + gpio = _set_bit(gpio, _74LS595_LCD_RS, char_mode) |
| 423 | + gpio = _set_bit(gpio, _74LS595_LCD_D4, (value & 1) > 0) |
| 424 | + gpio = _set_bit(gpio, _74LS595_LCD_D5, ((value >> 1) & 1) > 0) |
| 425 | + gpio = _set_bit(gpio, _74LS595_LCD_D6, ((value >> 2) & 1) > 0) |
| 426 | + gpio = _set_bit(gpio, _74LS595_LCD_D7, ((value >> 3) & 1) > 0) |
| 427 | + self._sr.gpio = gpio |
| 428 | + self._pulse_enable() |
0 commit comments