From f050d5398719468fb2334b350cc03096f308152d Mon Sep 17 00:00:00 2001 From: Brennen Bearnes Date: Thu, 25 Oct 2018 16:49:10 -0600 Subject: [PATCH 1/5] enable non-PWM pins for backlight color, add pi-specific simpletest Rationale: pulseio isn't available on CPython Linux systems (i.e. the Pi), this mimics the design of the original Adafruit_Python_CharLCD. Adds `enable_pwm` parameter to Character_LCD_RGB constructor, and conditionalizes handling of the color pins on this value. It's entirely possible I've messed something up here, so close review is appreciated. --- adafruit_character_lcd/character_lcd_rgb.py | 80 ++++++++++++--------- examples/rpi_rgb.py | 48 +++++++++++++ 2 files changed, 96 insertions(+), 32 deletions(-) create mode 100644 examples/rpi_rgb.py diff --git a/adafruit_character_lcd/character_lcd_rgb.py b/adafruit_character_lcd/character_lcd_rgb.py index 25421f6..d20d098 100755 --- a/adafruit_character_lcd/character_lcd_rgb.py +++ b/adafruit_character_lcd/character_lcd_rgb.py @@ -90,7 +90,7 @@ _LCD_5X8DOTS = const(0x00) # Offset for up to 4 rows. -LCD_ROW_OFFSETS = (0x00, 0x40, 0x14, 0x54) +LCD_ROW_OFFSETS = (0x00, 0x40, 0x14, 0x54) #pylint: enable-msg=bad-whitespace @@ -117,9 +117,9 @@ class Character_LCD_RGB(object): :param ~digitalio.DigitalInOut d7: The data line 7 :param cols: The columns on the charLCD :param lines: The lines on the charLCD - :param ~pulseio.PWMOut red: Red RGB Anode - :param ~pulseio.PWMOut green: Green RGB Anode - :param ~pulseio.PWMOut blue: Blue RGB Anode + :param ~pulseio.PWMOut, ~digitalio.DigitalInOut red: Red RGB Anode + :param ~pulseio.PWMOut, ~digitalio.DigitalInOut green: Green RGB Anode + :param ~pulseio.PWMOut, ~digitalio.DigitalInOut blue: Blue RGB Anode :param ~digitalio.DigitalInOut backlight: The backlight pin, usually the last pin. Consult the datasheet. Note that Pin value 0 means backlight is lit. @@ -129,50 +129,57 @@ def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, red, green, blue, - backlight=None #, - #enable_pwm = False, - #initial_backlight = 1.0 + backlight=None, + enable_pwm=True ): - # define columns and lines self.cols = cols self.lines = lines - # define pin params + + # define pin params self.reset = rs self.enable = en self.dl4 = d4 self.dl5 = d5 self.dl6 = d6 self.dl7 = d7 - # define color params - self.red = red - self.green = green - self.blue = blue - # define rgb led - self.rgb_led = [red, green, blue] + # define backlight pin self.backlight = backlight - # self.pwn_enabled = enable_pwm + self.pwm_enabled = enable_pwm + # set all pins as outputs for pin in(rs, en, d4, d5, d6, d7): pin.direction = digitalio.Direction.OUTPUT - # setup backlight + + # setup backlight if backlight is not None: self.backlight.direction = digitalio.Direction.OUTPUT self.backlight.value = 0 # turn backlight on - # initialize the display + + # define color params + self.red = red + self.green = green + self.blue = blue + self.rgb_led = [red, green, blue] + + if not self.pwm_enabled: + for pin in self.rgb_led: + pin.direction = digitalio.Direction.OUTPUT + + # initialize the display self._write8(0x33) self._write8(0x32) - # init. display control + # init. display control self.displaycontrol = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF - # init display function + # init display function self.displayfunction = _LCD_4BITMODE | _LCD_1LINE | _LCD_2LINE | _LCD_5X8DOTS - # init display mode + # init display mode self.displaymode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT - # write to display control + # write to display control self._write8(_LCD_DISPLAYCONTROL | self.displaycontrol) - # write displayfunction + # write displayfunction self._write8(_LCD_FUNCTIONSET | self.displayfunction) - # set the entry mode + # set the entry mode self._write8(_LCD_ENTRYMODESET | self.displaymode) self.clear() #pylint: enable-msg=too-many-arguments @@ -259,25 +266,34 @@ def set_backlight(self, lighton): self.backlight.value = 1 def set_color(self, color): - """ Method to set the duty cycle of the RGB LED - :param color: list of 3 integers in range(100). ``[R,G,B]`` 0 is no - color, 100 it maximum color + """Method to set the duty cycle or the on/off value of the RGB LED + :param color: list of 3 integers in range(100). ``[R,G,B]`` 0 is no + color, 100 is maximum color. If PWM is disabled, 0 is off and + non-zero is on. """ - self.rgb_led[0].duty_cycle = int(_map(color[0], 0, 100, 65535, 0)) - self.rgb_led[1].duty_cycle = int(_map(color[1], 0, 100, 65535, 0)) - self.rgb_led[2].duty_cycle = int(_map(color[2], 0, 100, 65535, 0)) + if self.pwm_enabled: + self.rgb_led[0].duty_cycle = int(_map(color[0], 0, 100, 65535, 0)) + self.rgb_led[1].duty_cycle = int(_map(color[1], 0, 100, 65535, 0)) + self.rgb_led[2].duty_cycle = int(_map(color[2], 0, 100, 65535, 0)) + else: + # If we don't have PWM enabled, all we can do is turn each color + # on / off. Assume a DigitalInOut and write 0 (on) to pin for any + # value greater than 0, or 1 (off) for 0: + self.rgb_led[0].value = 0 if color[0] > 0 else 1 + self.rgb_led[1].value = 0 if color[1] > 0 else 1 + self.rgb_led[2].value = 0 if color[2] > 0 else 1 def message(self, text): """Write text to display, can include \n for newline :param text: string to display """ line = 0 - # iterate thru each char + # iterate thru each char for char in text: # if character is \n, go to next line if char == '\n': line += 1 - # move to left/right depending on text direction + # move to left/right depending on text direction col = 0 if self.displaymode & _LCD_ENTRYLEFT > 0 else self.cols-1 self.set_cursor(col, line) # Write character to display diff --git a/examples/rpi_rgb.py b/examples/rpi_rgb.py new file mode 100644 index 0000000..fe428e5 --- /dev/null +++ b/examples/rpi_rgb.py @@ -0,0 +1,48 @@ +import time +import board +import digitalio +import adafruit_character_lcd + +# Character LCD Config: +# modify this if you have a different sized charlcd +lcd_columns = 16 +lcd_rows = 2 + +# Raspberry Pi Pin Config: +lcd_rs = digitalio.DigitalInOut(board.D26) # pin 4 +lcd_en = digitalio.DigitalInOut(board.D19) # pin 6 +lcd_d7 = digitalio.DigitalInOut(board.D27) # pin 14 +lcd_d6 = digitalio.DigitalInOut(board.D22) # pin 13 +lcd_d5 = digitalio.DigitalInOut(board.D24) # pin 12 +lcd_d4 = digitalio.DigitalInOut(board.D25) # pin 11 +lcd_backlight = digitalio.DigitalInOut(board.D4) + +red = digitalio.DigitalInOut(board.D21) +green = digitalio.DigitalInOut(board.D12) +blue = digitalio.DigitalInOut(board.D18) + +# Init the lcd class +lcd = adafruit_character_lcd.Character_LCD_RGB(lcd_rs, lcd_en, lcd_d4, lcd_d5, + lcd_d6, lcd_d7, lcd_columns, lcd_rows, + red, green, blue, lcd_backlight, + enable_pwm=False) + +RED = [1, 0, 0] +GREEN = [0, 1, 0] +BLUE = [0, 0, 1] + +while True: + lcd.clear() + lcd.message('CircuitPython\nRGB Test: RED') + lcd.set_color(RED) + time.sleep(1) + + lcd.clear() + lcd.message('CircuitPython\nRGB Test: GREEN') + lcd.set_color(GREEN) + time.sleep(1) + + lcd.clear() + lcd.message('CircuitPython\nRGB Test: BLUE') + lcd.set_color(BLUE) + time.sleep(1) From 238dbf0c58ceaa9fb9fdb566590ddd423b9050c0 Mon Sep 17 00:00:00 2001 From: Brennen Bearnes Date: Thu, 25 Oct 2018 23:11:39 -0600 Subject: [PATCH 2/5] remove enable_pwm, check attrs of pin objects instead --- adafruit_character_lcd/character_lcd_rgb.py | 37 ++++++++++--------- ...i_rgb.py => rpi_charlcd_rgb_simpletest.py} | 3 +- 2 files changed, 21 insertions(+), 19 deletions(-) rename examples/{rpi_rgb.py => rpi_charlcd_rgb_simpletest.py} (94%) diff --git a/adafruit_character_lcd/character_lcd_rgb.py b/adafruit_character_lcd/character_lcd_rgb.py index d20d098..a35c58d 100755 --- a/adafruit_character_lcd/character_lcd_rgb.py +++ b/adafruit_character_lcd/character_lcd_rgb.py @@ -129,8 +129,7 @@ def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, red, green, blue, - backlight=None, - enable_pwm=True + backlight=None ): self.cols = cols self.lines = lines @@ -145,7 +144,6 @@ def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, # define backlight pin self.backlight = backlight - self.pwm_enabled = enable_pwm # set all pins as outputs for pin in(rs, en, d4, d5, d6, d7): @@ -162,9 +160,16 @@ def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, self.blue = blue self.rgb_led = [red, green, blue] - if not self.pwm_enabled: - for pin in self.rgb_led: + for pin in self.rgb_led: + if hasattr(pin, 'direction'): + # Assume a digitalio.DigitalInOut or compatible interface: pin.direction = digitalio.Direction.OUTPUT + else: + if not hasattr(pin, 'duty_cycle'): + raise TypeError( + 'RGB LED objects must be instances of digitalio.DigitalInOut' + ' or pulseio.PWMOut, or provide a compatible interface.' + ) # initialize the display self._write8(0x33) @@ -268,20 +273,18 @@ def set_backlight(self, lighton): def set_color(self, color): """Method to set the duty cycle or the on/off value of the RGB LED :param color: list of 3 integers in range(100). ``[R,G,B]`` 0 is no - color, 100 is maximum color. If PWM is disabled, 0 is off and + color, 100 is maximum color. If PWM is unavailable, 0 is off and non-zero is on. """ - if self.pwm_enabled: - self.rgb_led[0].duty_cycle = int(_map(color[0], 0, 100, 65535, 0)) - self.rgb_led[1].duty_cycle = int(_map(color[1], 0, 100, 65535, 0)) - self.rgb_led[2].duty_cycle = int(_map(color[2], 0, 100, 65535, 0)) - else: - # If we don't have PWM enabled, all we can do is turn each color - # on / off. Assume a DigitalInOut and write 0 (on) to pin for any - # value greater than 0, or 1 (off) for 0: - self.rgb_led[0].value = 0 if color[0] > 0 else 1 - self.rgb_led[1].value = 0 if color[1] > 0 else 1 - self.rgb_led[2].value = 0 if color[2] > 0 else 1 + for number, pin in enumerate(self.rgb_led): + if hasattr(pin, 'duty_cycle'): + # Assume a pulseio.PWMOut or compatible interface and set duty cycle: + pin.duty_cycle = int(_map(color[number], 0, 100, 65535, 0)) + elif hasattr(pin, 'value'): + # If we don't have a PWM interface, all we can do is turn each color + # on / off. Assume a DigitalInOut (or compatible interface) and write + # 0 (on) to pin for any value greater than 0, or 1 (off) for 0: + pin.value = 0 if color[number] > 0 else 1 def message(self, text): """Write text to display, can include \n for newline diff --git a/examples/rpi_rgb.py b/examples/rpi_charlcd_rgb_simpletest.py similarity index 94% rename from examples/rpi_rgb.py rename to examples/rpi_charlcd_rgb_simpletest.py index fe428e5..3acadd2 100644 --- a/examples/rpi_rgb.py +++ b/examples/rpi_charlcd_rgb_simpletest.py @@ -24,8 +24,7 @@ # Init the lcd class lcd = adafruit_character_lcd.Character_LCD_RGB(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_columns, lcd_rows, - red, green, blue, lcd_backlight, - enable_pwm=False) + red, green, blue, lcd_backlight) RED = [1, 0, 0] GREEN = [0, 1, 0] From 2719125e75a418b1adfbd5547e52d53cd145a15e Mon Sep 17 00:00:00 2001 From: Brennen Bearnes Date: Thu, 25 Oct 2018 23:20:02 -0600 Subject: [PATCH 3/5] make pylint happy about indentation and inheriting from object --- adafruit_character_lcd/character_lcd_rgb.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/adafruit_character_lcd/character_lcd_rgb.py b/adafruit_character_lcd/character_lcd_rgb.py index a35c58d..6a6f9e4 100755 --- a/adafruit_character_lcd/character_lcd_rgb.py +++ b/adafruit_character_lcd/character_lcd_rgb.py @@ -107,7 +107,7 @@ def _map(xval, in_min, in_max, out_min, out_max): #pylint: disable-msg=too-many-instance-attributes -class Character_LCD_RGB(object): +class Character_LCD_RGB: """ Interfaces with a character LCD :param ~digitalio.DigitalInOut rs: The reset data line :param ~digitalio.DigitalInOut en: The enable data line @@ -166,10 +166,10 @@ def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, pin.direction = digitalio.Direction.OUTPUT else: if not hasattr(pin, 'duty_cycle'): - raise TypeError( - 'RGB LED objects must be instances of digitalio.DigitalInOut' - ' or pulseio.PWMOut, or provide a compatible interface.' - ) + raise TypeError( + 'RGB LED objects must be instances of digitalio.DigitalInOut' + ' or pulseio.PWMOut, or provide a compatible interface.' + ) # initialize the display self._write8(0x33) From a90e624bd759012e5e484d1d0f3c3def8ef1e18f Mon Sep 17 00:00:00 2001 From: Brennen Bearnes Date: Fri, 26 Oct 2018 12:08:14 -0600 Subject: [PATCH 4/5] else: if -> elif --- adafruit_character_lcd/character_lcd_rgb.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/adafruit_character_lcd/character_lcd_rgb.py b/adafruit_character_lcd/character_lcd_rgb.py index 6a6f9e4..c587845 100755 --- a/adafruit_character_lcd/character_lcd_rgb.py +++ b/adafruit_character_lcd/character_lcd_rgb.py @@ -164,8 +164,7 @@ def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, if hasattr(pin, 'direction'): # Assume a digitalio.DigitalInOut or compatible interface: pin.direction = digitalio.Direction.OUTPUT - else: - if not hasattr(pin, 'duty_cycle'): + elif not hasattr(pin, 'duty_cycle'): raise TypeError( 'RGB LED objects must be instances of digitalio.DigitalInOut' ' or pulseio.PWMOut, or provide a compatible interface.' From 8750a95034247d2438bc5bea6025973747076ef8 Mon Sep 17 00:00:00 2001 From: Brennen Bearnes Date: Fri, 26 Oct 2018 12:11:47 -0600 Subject: [PATCH 5/5] fix indentation in elif block --- adafruit_character_lcd/character_lcd_rgb.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_character_lcd/character_lcd_rgb.py b/adafruit_character_lcd/character_lcd_rgb.py index c587845..d0e4fa6 100755 --- a/adafruit_character_lcd/character_lcd_rgb.py +++ b/adafruit_character_lcd/character_lcd_rgb.py @@ -165,10 +165,10 @@ def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, # Assume a digitalio.DigitalInOut or compatible interface: pin.direction = digitalio.Direction.OUTPUT elif not hasattr(pin, 'duty_cycle'): - raise TypeError( - 'RGB LED objects must be instances of digitalio.DigitalInOut' - ' or pulseio.PWMOut, or provide a compatible interface.' - ) + raise TypeError( + 'RGB LED objects must be instances of digitalio.DigitalInOut' + ' or pulseio.PWMOut, or provide a compatible interface.' + ) # initialize the display self._write8(0x33)