""" Author: Tobias Müller Date: 13.09.2023 Version: 1.0 This file contains a class for a LCD. """ ############################## Modules ############################## from machine import Pin, PWM, I2C ############################## Class ############################## class LCD(object): """ Class to control a DOGS104-A LC-Display. """ ############################## Attributes ############################## ROM_A = "ROM A" ROM_B = "ROM B" ROM_C = "ROM C" TWO_LINES = "TWO LINES" THREE_LINES_TOP = "THREE LINES TOP" THREE_LINES_MIDDLE = "THREE LINES MIDDLE" THREE_LINES_BOTTOM = "THREE LINES BOTTOM" FOUR_LINES = "FOUR LINES" STANDARD_MODE = "STANDARD MODE" FAST_MODE = "FAST MODE" __lcd_setting_para = {"LCD_PARA_EXT_FUNC": 0x09, # Extended Function (4 line mode) # type: ignore "LCD_PARA_BIAS_SET": 0x12, # Bias Setting (BS1 = 1) # type: ignore "LCD_PARA_INT_OSC": 0x1B, # Internal OSC (BS0 = 1, Bias = 1/6) "LCD_PARA_FOL_CON": 0x6E, # Follower Control (Devider on, Set Value) "LCD_PARA_DIS_CON": 0x0C} # Display on/off Control (Cursor off, Blink off) __lcd_contrast_para = {"LCD_PARA_POW_CON": 0x54, # Power Control (Booster on) and Contrast (C5, C4) "LCD_PARA_CONTRAST": 0x70} # Contrast (C3 - C0) __lcd_line_mode_para = {"LCD_PARA_LINES": 0x12} # Line Mode __lcd_direction_para = {"LCD_PARA_ENTRY_MODE": 0x04} # Display direction / orientation __lcd_control_para_priv = {"CONTROL_BYTE": 0x00, # Control Byte "CONTROL_BYTE_C0": 0x80, # Control Byte (C0 = 1) "CONTROL_BYTE_RS": 0x40, # Control Byte (RS = 1) "CONTROL_BYTE_C0_RS": 0xC0, # Control Byte (C0 = 1, RS = 1) "FUNCTION_SET": 0x38, # Function Set "FUNCTION_SET_RE": 0x3A, # Function Set (RE = 1) "FUNCTION_SET_IS": 0x39, # Function Set (IS = 1) "CLEAR_DISPLAY": 0x01, # Clear Display "DISPLAY_ROW_1": 0x80, # Display Row 1 "DISPLAY_ROW_2": 0xA0, # Display Row 2 "DISPLAY_ROW_3": 0xC0, # Display Row 3 "DISPLAY_ROW_4": 0xE0, # Display Row 4 "DISPLAY_COLUMN": 0x0A} # Columns per Display Row __lcd_rom_para = {"LCD_PARA_ROM_SEL": 0x72} __lcd_roms = {ROM_A: 0, ROM_B: 1, ROM_C: 2, ROM_A[-1]: 0, ROM_B[-1]: 1, ROM_C[-1]: 2, 1: 0, 2: 1, 3: 2} __lcd_line_modes = {TWO_LINES: 3, FOUR_LINES: 0, THREE_LINES_TOP: 4, THREE_LINES_MIDDLE: 2, THREE_LINES_BOTTOM: 1} __i2c_ports = {"I2C0": {"SDA_PINS": [Pin(0), Pin(4) ,Pin(8) ,Pin(12) ,Pin(16) ,Pin(20)], "SCL_PINS": [Pin(1), Pin(5), Pin(9), Pin(13), Pin(17), Pin(21)]}, "I2C1": {"SDA_PINS": [Pin(2), Pin(6), Pin(10), Pin(14), Pin(18), Pin(26)], "SCL_PINS": [Pin(3), Pin(7), Pin(11), Pin(15), Pin(19), Pin(27)]}} __i2c_frequencies = {STANDARD_MODE: 100000, FAST_MODE: 400000} __i2c_address = 0x3c ############################## Constructor ############################## def __init__(self, i2c_sda_pin: Pin = Pin(2), i2c_scl_pin: Pin = Pin(3), i2c_frequency: int|str = "STANDARD MODE", lcd_backlight_pin: Pin = Pin(28), lcd_brightness: int = 100, lcd_contrast: int = 60, lcd_rom: int|str = "ROM B", lcd_line_mode: str = "FOUR LINES", lcd_direction_top: int|bool = False): """ Initialize LCD. Alls arguments can be changed later as a property. Args: i2c_sda_pin (Pin, optional): Set SDA-Pin for I2C-Bus. Defaults to Pin(2). i2c_scl_pin (Pin, optional): Set SCL-Pin for I2C-Bus. Defaults to Pin(3). i2c_frequency (int | str, optional): Set I2C frequency. Defaults to "STANDARD MODE". lcd_backlight_pin (Pin, optional): Set LCD backlight pin. Defaults to Pin(28). lcd_brightness (int, optional): Set LCD brightness in percent. Defaults to 100. lcd_contrast (int, optional): Set LCD contrast in percent. Defaults to 60. lcd_rom (int | str, optional): Set ASCII-ROM. Defaults to "ROM B". lcd_line_mode (str, optional): Set LCD line mode for 2-, 3- or 4-lines. Defaults to "FOUR LINES". lcd_direction_top (int | bool, optional): Set LCD direction to top. Defaults to False. """ # Check and store input values self.__i2c_bus, self.__i2c_sda_pin, self.__i2c_scl_pin = self.__check_i2c_ports(i2c_sda_pin, i2c_scl_pin) self.__i2c_frequency = self.__check_i2c_frequency(i2c_frequency) self.__lcd_backlight_pin = self.__check_lcd_backlight_pin(lcd_backlight_pin) self.__lcd_brightness = self.__check_lcd_brightness(lcd_brightness) self.__lcd_contrast = self.__check_lcd_contrast(lcd_contrast) self.__lcd_rom = self.__check_lcd_rom(lcd_rom) self.__lcd_line_mode = self.__check_lcd_line_mode(lcd_line_mode) self.__lcd_direction_top = self.__check_lcd_direction_top(lcd_direction_top) # init i2c and backlight self.__init_i2c() self.__init_backlight_pwm() ############################## Properties private ############################## @property def __lcd_control_para(self): lcd_control_para = self.__lcd_control_para_priv.copy() if self.__lcd_line_modes[self.__lcd_line_mode]: lcd_control_para["FUNCTION_SET"] = 0x3C if self.__lcd_direction_top: lcd_control_para["DISPLAY_ROW_1"] = 0x8A lcd_control_para["DISPLAY_ROW_2"] = 0xAA lcd_control_para["DISPLAY_ROW_3"] = 0xCA lcd_control_para["DISPLAY_ROW_4"] = 0xEA return lcd_control_para ############################## Properties ############################## @property def lcd_brightness(self): return self.__lcd_brightness @lcd_brightness.setter def lcd_brightness(self, lcd_brightness: int): """ lcd_brightness: Set LCD brightness in percent. Args: lcd_brightness (int): Value from 0-100. """ self.__lcd_brightness = self.__check_lcd_brightness(lcd_brightness) self.__set_lcd_brightness() @property def lcd_rom(self): return self.__lcd_rom @lcd_rom.setter def lcd_rom(self, lcd_rom: int|str): """ lcd_rom: Set ROM for ASCII-Table. Check available ROMs at: https://www.lcd-module.com/fileadmin/eng/pdf/doma/dogs104e.pdf Args: lcd_rom (int | str): 1 or "A" or "ROM A" for ROM A, 2 or "B" or "ROM B" for ROM B, 3 or "C" or "ROM C" for ROM C. """ self.__lcd_rom = self.__check_lcd_rom(lcd_rom) self.__set_lcd_rom() @property def lcd_contrast(self): return self.__lcd_contrast @lcd_contrast.setter def lcd_contrast(self, lcd_contrast: int): """ lcd_contrast: Set LCD contrast in percent. Args: lcd_contrast (int): Value from 0-100. """ self.__lcd_contrast = self.__check_lcd_contrast(lcd_contrast) self.__set_lcd_contrast() @property def lcd_direction_top(self): return self.__lcd_direction_top @lcd_direction_top.setter def lcd_direction_top(self, lcd_direction_top: int|bool): """ lcd_direction_top: Set LCD direction to top. Args: lcd_direction_top (int | bool): 0 or False for LCD direction to bottom, 1 or True for LCD direction to top. """ buffer = self.read() self.__lcd_direction_top = self.__check_lcd_direction_top(lcd_direction_top) self.clear() self.__set_lcd_direction() self.clear() self.print(str(buffer)) @property def lcd_line_mode(self): return self.__lcd_line_mode @lcd_line_mode.setter def lcd_line_mode(self, lcd_line_mode: str): """ lcd_line_mode: Set LCD line mode to 2-, 3- or 4-lines. For 3-lines are three additional modes available. Args: lcd_line_mode (str): "TWO LINES" to set the display in two line mode, "THREE LINES TOP" to set the display in three line mode with one bigger line on top position, "THREE LINES MIDDLE" to set the display in three line mode with one bigger line on middle position, "THREE LINES BOTTOM" to set the display in three line mode with one bigger line on bottom position, "FOUR LINES" to set the display in four line mode. """ self.__check_lcd_line_mode(lcd_line_mode) if (self.__lcd_line_modes[lcd_line_mode] and self.__lcd_line_modes[self.__lcd_line_mode] == 0): self.clear(row=4) if (self.__lcd_line_modes[lcd_line_mode] == 3 and self.__lcd_line_modes[self.__lcd_line_mode] != 3): self.clear(row=3) self.__lcd_line_mode = lcd_line_mode self.__set_lcd_line_mode() @property def lcd_backlight_pin(self): return self.__lcd_backlight_pin @lcd_backlight_pin.setter def lcd_backlight_pin(self, lcd_backlight_pin: Pin): """ lcd_backlight_pin: Set LCD backlight pin. Args: lcd_backlight_pin (Pin): Value of class Pin. """ self.__check_lcd_backlight_pin(lcd_backlight_pin) self.__deinit_backlight_pwm() self.lcd_backlight_pin = lcd_backlight_pin self.__init_backlight_pwm() @property def i2c_frequency(self): return self.__i2c_frequency @i2c_frequency.setter def i2c_frequency(self, i2c_frequency: int|str): """ i2c_frequency: Set I2C frequency. Args: i2c_frequency (int | str): "STANDARD MODE" or 100000 for a clock frequency of 100 kHz, "FAST MODE" or 400000 for a clock frequency of 400 kHz. """ self.__check_i2c_frequency(i2c_frequency) self.__deinit_i2c() self.__i2c_frequency = i2c_frequency self.__init_i2c() @property def i2c_sda_pin(self): return self.__i2c_sda_pin @i2c_sda_pin.setter def i2c_sda_pin(self, i2c_sda_pin: Pin): """ i2c_sda_pin: Set SDA-Pin for I2C-Bus. Args: i2c_sda_pin (Pin): Value of class Pin. """ self.change_i2c_port(i2c_sda_pin, self.__i2c_scl_pin) @property def i2c_scl_pin(self): return self.__i2c_scl_pin @i2c_scl_pin.setter def i2c_scl_pin(self, i2c_scl_pin: Pin): """ i2c_scl_pin: Set SCL-Pin for I2C-Bus. Args: i2c_scl_pin (Pin): Value of class Pin. """ self.change_i2c_port(self.__i2c_sda_pin, i2c_scl_pin) ############################## Methods private ############################## @staticmethod def __reset_pin(pin: Pin): pin.init(mode=Pin.IN) @staticmethod def __check_lcd_brightness(lcd_brightness: int): if not isinstance(lcd_brightness, int): raise ValueError(f"Value \"{lcd_brightness}\" of \"lcd_brightness\" is not type \"int\"!") elif lcd_brightness < 0 or lcd_brightness > 100: raise ValueError(f"Value \"{lcd_brightness}\" of \"lcd_brightness\" is out of range!") else: return lcd_brightness @staticmethod def __check_lcd_backlight_pin(lcd_backlight_pin: Pin): if not isinstance(lcd_backlight_pin, Pin): raise ValueError(f"Value \"{lcd_backlight_pin}\" of \"lcd_backlight_pin\" is not type \"Pin\"!") else: return lcd_backlight_pin def __check_lcd_line_mode(self, lcd_line_mode: str): if not isinstance(lcd_line_mode, str): raise ValueError(f"Value \"{lcd_line_mode}\" of \"lcd_line_mode\" is not type \"str\"!") elif lcd_line_mode.upper() not in self.__lcd_line_modes: raise ValueError(f"Value \"{lcd_line_mode}\" of \"lcd_line_mode\" is not supported!") else: return lcd_line_mode @staticmethod def __check_lcd_direction_top(lcd_direction_top: int|bool): if not isinstance(lcd_direction_top, int) and not isinstance(lcd_direction_top, bool): raise ValueError(f"Value \"{lcd_direction_top}\" of \"lcd_direction_top\" is not type" + " \"int\" or \"bool\"!") elif isinstance(lcd_direction_top, int) and (lcd_direction_top < 0 or lcd_direction_top > 1): raise ValueError(f"Value \"{lcd_direction_top}\" of \"lcd_direction_top\" is out of range!") else: return lcd_direction_top @staticmethod def __check_lcd_contrast(lcd_contrast: int): if not isinstance(lcd_contrast, int): raise ValueError(f"Value \"{lcd_contrast}\" of \"lcd_contrast\" is not type \"int\"!") elif lcd_contrast < 0 or lcd_contrast > 100: raise ValueError(f"Value \"{lcd_contrast}\" of \"lcd_contrast\" is out of range!") else: return lcd_contrast def __check_lcd_rom(self, lcd_rom: int|str): if not isinstance(lcd_rom, int) and not isinstance(lcd_rom, str): raise ValueError(f"Value \"{lcd_rom}\" of \"lcd_rom\" is not type" + " \"int\" or \"str\"!") elif((isinstance(lcd_rom, int) and lcd_rom not in self.__lcd_roms.keys()) or (isinstance(lcd_rom, str) and lcd_rom.upper() not in self.__lcd_roms.keys())): raise ValueError(f"Value \"{lcd_rom}\" of \"lcd_rom\" is not supported!") else: return lcd_rom def __check_i2c_ports(self, i2c_sda_pin: Pin, i2c_scl_pin: Pin): if not isinstance(i2c_sda_pin, Pin): raise ValueError(f"Value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" is not type \"Pin\"!") elif not isinstance(i2c_scl_pin, Pin): raise ValueError(f"Value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" is not type \"Pin\"!") elif (not i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"] and not i2c_sda_pin in self.__i2c_ports["I2C1"]["SDA_PINS"]): raise ValueError(f"Value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" is not an I2C SDA-Pin!") elif (not i2c_scl_pin in self.__i2c_ports["I2C0"]["SCL_PINS"] and not i2c_scl_pin in self.__i2c_ports["I2C1"]["SCL_PINS"]): raise ValueError(f"Value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" is not an I2C SCL-Pin!") elif ((i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"] and not i2c_scl_pin in self.__i2c_ports["I2C0"]["SCL_PINS"]) or (i2c_sda_pin in self.__i2c_ports["I2C1"]["SDA_PINS"] and not i2c_scl_pin in self.__i2c_ports["I2C1"]["SCL_PINS"])): raise ValueError(f"Value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" and " + f"Value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" " + "are not part of the same I2C Bus!") else: if i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"]: return 0, i2c_sda_pin, i2c_scl_pin else: return 1, i2c_sda_pin, i2c_scl_pin def __check_i2c_frequency(self, i2c_frequency: int|str): if not isinstance(i2c_frequency, int) and not isinstance(i2c_frequency, str): raise ValueError(f"Value \"{i2c_frequency}\" of \"i2c_frequency\" is not type \"int\"" + " or \"str\"!") elif (isinstance(i2c_frequency, int) and not i2c_frequency in self.__i2c_frequencies.values() or isinstance(i2c_frequency, str) and not i2c_frequency in self.__i2c_frequencies.keys()): raise ValueError(f"Value \"{i2c_frequency}\" of \"i2c_frequency\" is not supported!") else: return i2c_frequency def __init_i2c(self): self.__i2c = I2C(self.__i2c_bus, sda=self.__i2c_sda_pin, scl=self.__i2c_scl_pin, freq=(self.__i2c_frequency if isinstance(self.__i2c_frequency, int) else self.__i2c_frequencies[self.__i2c_frequency])) buffer = (self.__lcd_control_para["CONTROL_BYTE"], self.__lcd_control_para["FUNCTION_SET_RE"], self.__lcd_setting_para["LCD_PARA_EXT_FUNC"], self.__lcd_setting_para["LCD_PARA_BIAS_SET"], self.__lcd_control_para["FUNCTION_SET_IS"], self.__lcd_setting_para["LCD_PARA_INT_OSC"], self.__lcd_setting_para["LCD_PARA_FOL_CON"], self.__lcd_control_para["FUNCTION_SET"], self.__lcd_setting_para["LCD_PARA_DIS_CON"]) self.__i2c.writeto(self.__i2c_address, bytes(buffer)) self.__set_lcd_line_mode() self.__set_lcd_rom() self.__set_lcd_contrast() self.__set_lcd_direction() self.clear() def __deinit_i2c(self): self.__reset_pin(self.__i2c_scl_pin) self.__reset_pin(self.__i2c_sda_pin) def __init_backlight_pwm(self): self.__backlight_pwm = PWM(self.__lcd_backlight_pin) self.__backlight_pwm.freq(1000) self.__set_lcd_brightness() def __deinit_backlight_pwm(self): self.__backlight_pwm.deinit() self.__reset_pin(self.__lcd_backlight_pin) def __set_lcd_brightness(self): self.__backlight_pwm.duty_u16(round(65635 * (self.__lcd_brightness / 100))) def __set_lcd_rom(self): if isinstance(self.__lcd_rom, str): lcd_rom = self.__lcd_rom.upper() else: lcd_rom = self.__lcd_rom buffer = (self.__lcd_control_para["CONTROL_BYTE_C0"], self.__lcd_control_para["FUNCTION_SET_RE"], self.__lcd_control_para["CONTROL_BYTE_C0"], self.__lcd_rom_para["LCD_PARA_ROM_SEL"], self.__lcd_control_para["CONTROL_BYTE_C0_RS"], self.__lcd_roms[lcd_rom] << 0x02, self.__lcd_control_para["CONTROL_BYTE"], self.__lcd_control_para["FUNCTION_SET"]) self.__i2c.writeto(self.__i2c_address, bytes(buffer)) def __set_lcd_contrast(self): contrast = round(63 * (self.__lcd_contrast / 100)) buffer = (self.__lcd_control_para["CONTROL_BYTE"], self.__lcd_control_para["FUNCTION_SET_IS"], self.__lcd_contrast_para["LCD_PARA_POW_CON"] | (contrast >> 0x04), self.__lcd_contrast_para["LCD_PARA_CONTRAST"] | (contrast & 0x0F), self.__lcd_control_para["FUNCTION_SET"]) self.__i2c.writeto(self.__i2c_address, bytes(buffer)) def __set_lcd_direction(self): buffer = [self.__lcd_control_para["CONTROL_BYTE"], self.__lcd_control_para["FUNCTION_SET_RE"]] if self.__lcd_direction_top: buffer.append(self.__lcd_direction_para["LCD_PARA_ENTRY_MODE"] | 0x01) else: buffer.append(self.__lcd_direction_para["LCD_PARA_ENTRY_MODE"] | 0x02) buffer.append(self.__lcd_control_para["FUNCTION_SET"]) self.__i2c.writeto(self.__i2c_address, bytes(buffer)) def __set_lcd_line_mode(self): buffer = [self.__lcd_control_para["CONTROL_BYTE"], self.__lcd_control_para["FUNCTION_SET_RE"]] lcd_line_mode = self.__lcd_line_modes[self.__lcd_line_mode] if lcd_line_mode: buffer.append(self.__lcd_line_mode_para["LCD_PARA_LINES"] | ((lcd_line_mode - 1) << 0x02)) else: buffer.append(self.__lcd_line_mode_para["LCD_PARA_LINES"]) buffer.append(self.__lcd_control_para["FUNCTION_SET"]) self.__i2c.writeto(self.__i2c_address, bytes(buffer)) def __check_keywords(self, keywords: dict[str,int|bool], keys: list[str]): lcd_line_mode = self.__lcd_line_modes[self.__lcd_line_mode] rows = 0x04 if lcd_line_mode == 0x00 else 0x02 if lcd_line_mode == 0x03 else 0x03 output = {"rows": rows, "row": 0x01, "column": 0x01, "auto_line_break": True, "separate": False} for key, val in keywords.items(): if key not in keys: raise KeyError(f"Keyword \"{key}\" is unknown!") elif key == "row": if not isinstance(val, int): raise ValueError(f"Value \"{val}\" of keyword \"{key}\" is not type \"int\"!") elif val > rows or val < 1: raise ValueError(f"Value \"{val}\" of keyword \"{key}\" is out of range!") else: output.update({key: val}) elif key == "column": if not isinstance(val, int): raise ValueError(f"Value \"{val}\" of keyword \"{key}\" is not type \"int\"!") elif val > self.__lcd_control_para["DISPLAY_COLUMN"] or val < 0x01: raise ValueError(f"Value \"{val}\" of keyword \"{key}\" is out of range!") else: output.update({key: val}) elif key == "auto_line_break": if not isinstance(val, int) and not isinstance(val, bool): raise ValueError(f"Value \"{val}\" of keyword \"{key}\" is not type" + " \"int\" or \"bool\"!") elif isinstance(val, int) and (val < 0 or val > 1): raise ValueError(f"Value \"{val}\" of keyword \"{key}\" is out of range!") else: output.update({key: val}) elif key == "separate": if not isinstance(val, int) and not isinstance(val, bool): raise ValueError(f"Value \"{val}\" of keyword \"{key}\" is not type" + " \"int\" or \"bool\"!") elif isinstance(val, int) and (val < 0 or val > 1): raise ValueError(f"Value \"{val}\" of keyword \"{key}\" is out of range!") else: output.update({key: val}) return output.copy() ############################## Methods public ############################## def change_i2c_port(self, i2c_sda_pin: Pin, i2c_scl_pin: Pin): """ Used to change I2C port. Args: i2c_sda_pin (int | str): SDA-Pin of I2C Port i2c_scl_pin (int | str): SCL-Pin of I2C Port """ self.__check_i2c_ports(i2c_sda_pin, i2c_scl_pin) self.__deinit_i2c() (self.__i2c_bus, self.__i2c_sda_pin, self.__i2c_scl_pin) = self.__check_i2c_ports(i2c_sda_pin, i2c_scl_pin) self.__init_i2c() def print(self, text: str, **keywords): """ Used to print text on the LCD. Args: text (str): Text, which is printed on the LCD. Keywords: row (int): Row to start printing. Defaults to 1. column (int): Column to start printing. Defaults to 1. auto_line_break (int | bool): Breaks the line automatically. Defaults to True. """ def check_text(text: str): if not isinstance(text, str): raise ValueError(f"Value \"{text}\" of \"text\" is not type \"str\"!") elif len(text) == 0: raise ValueError(f"Value \"{text}\" of \"text\" is out of range!") keys = ["row", "column", "auto_line_break"] keys = self.__check_keywords(keywords, keys) rows = keys["rows"] row = keys["row"] column = keys["column"] auto_line_break = keys["auto_line_break"] check_text(text) linefeed = ("\n","\r") buffer = [] for line in range(row,rows + 0x01): if len(text) == 0x00 or (not auto_line_break and line > row): break buffer.append(self.__lcd_control_para["CONTROL_BYTE_C0"]) buffer.append(self.__lcd_control_para["DISPLAY_ROW_" + str(line)] + (column - 0x01)) for char in range(0x00, (self.__lcd_control_para["DISPLAY_COLUMN"] - (column - 0x01)) if len(text) > (self.__lcd_control_para["DISPLAY_COLUMN"] - (column - 0x01)) else len(text)): if text[char] in linefeed: text = text[char + 0x01:] for _ in range(char, (self.__lcd_control_para["DISPLAY_COLUMN"] - (column - 0x01)) if len(text) > (self.__lcd_control_para["DISPLAY_COLUMN"] - (column - 0x01)) else len(text)): buffer.append(self.__lcd_control_para["CONTROL_BYTE_C0_RS"]) buffer.append(ord(" ")) break buffer.append(self.__lcd_control_para["CONTROL_BYTE_C0_RS"]) buffer.append(ord(text[char])) else: text = text[self.__lcd_control_para["DISPLAY_COLUMN"] - (column - 0x01):] column = 0x01 self.__i2c.writeto(self.__i2c_address, bytes(buffer)) def clear(self, **keywords): """ Used to clear the LCD. If the keywords row or column are not used, the method will clear the whole display. Keywords: row (int): Row to start printing. Defaults to 1. column (int): Column to start printing. Defaults to 1. """ buffer = [] if len(keywords) == 0: buffer.append(self.__lcd_control_para["CONTROL_BYTE"]) buffer.append(self.__lcd_control_para["CLEAR_DISPLAY"]) else: keys = ["row", "column"] keys = self.__check_keywords(keywords, keys) row = keys["row"] column = keys["column"] buffer.append(self.__lcd_control_para["CONTROL_BYTE_C0"]) buffer.append(self.__lcd_control_para["DISPLAY_ROW_" + str(row)] + (column - 0x01)) for _ in range(0x00, self.__lcd_control_para["DISPLAY_COLUMN"]): buffer.append(self.__lcd_control_para["CONTROL_BYTE_C0_RS"]) buffer.append(ord(" ")) if "column" in keywords.keys(): break self.__i2c.writeto(self.__i2c_address, bytes(buffer)) def read(self, **keywords): """ Used to read from the LCD. Keywords: row (int): Row to start reading from. Defaults to 1. column (int): Column to start reading from. Defaults to 1. separate (int | bool): Separate each line into a list. Defaults to False. Returns: list: (separate=True) Return each line into a list of separated strings. str: (separate=False) Return all lines as one string. """ def remove_whitespace(text: str): textlen = len(text) endpos = textlen for char in range(0x00, textlen): if text[textlen - char - 0x01] == " ": endpos -= 0x01 else: break return text[:endpos] keys = ["row", "column", "separate"] keys = self.__check_keywords(keywords, keys) rows = keys["rows"] row = keys["row"] column = keys["column"] separate = keys["separate"] buffer = [] for line in range(0x01, rows + 0x01): tmp = (self.__lcd_control_para["CONTROL_BYTE_C0"], self.__lcd_control_para["DISPLAY_ROW_" + str(line)], self.__lcd_control_para["CONTROL_BYTE_RS"]) self.__i2c.writeto(self.__i2c_address,bytes(tmp)) tmp = self.__i2c.readfrom(self.__i2c_address,11) tmp = list(tmp[1:]) tmp = [chr(tmp[i]) for i in range(0, len(tmp))] if ("row" in keywords.keys() or "column" in keywords.keys()) and line != row: tmp = [""] if "column" in keywords.keys() and line == row: tmp = tmp[column - 0x01] buffer.append("".join(tmp)) if not separate: return remove_whitespace("".join(buffer)) else: for pos in range(0, len(buffer)): buffer[pos] = remove_whitespace(buffer[pos]) return buffer if __name__ == "__main__": lcd = LCD(lcd_line_mode=LCD.TWO_LINES) lcd.print("Hochschule Anhalt") lcd.lcd_brightness = 50