|
@@ -1,7 +1,7 @@
|
|
|
"""
|
|
|
Author: Tobias Müller
|
|
|
Date: 30.06.2023
|
|
|
-Version: 0.7
|
|
|
+Version: 0.9
|
|
|
|
|
|
This file contains classes for LCD, Button and Led control.
|
|
|
"""
|
|
@@ -18,8 +18,8 @@ class LCD:
|
|
|
|
|
|
############################## Attributes ##############################
|
|
|
|
|
|
- __lcd_setting_para = {"LCD_PARA_EXT_FUNC": 0x09, # Extended Function (4 line mode)
|
|
|
- "LCD_PARA_BIAS_SET": 0x12, # Bias Setting (BS1 = 1)
|
|
|
+ __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)
|
|
@@ -69,8 +69,8 @@ class LCD:
|
|
|
i2c_frequency: int|str = "FAST_MODE",
|
|
|
lcd_backlight_pin: int|str = 28,
|
|
|
lcd_brightness: int = 100,
|
|
|
- lcd_contrast: int = 0x2A,
|
|
|
- lcd_ascii_table: int|str = "ROM B",
|
|
|
+ lcd_contrast: int = 60,
|
|
|
+ lcd_ascii_rom: int|str = "ROM B",
|
|
|
lcd_line_mode: int = 0,
|
|
|
lcd_direction_top: int|bool = False):
|
|
|
|
|
@@ -81,7 +81,7 @@ class LCD:
|
|
|
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_ascii_table = self.__check_lcd_ascii_table(lcd_ascii_table)
|
|
|
+ self.__lcd_ascii_rom = self.__check_lcd_ascii_rom(lcd_ascii_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)
|
|
|
|
|
@@ -115,13 +115,13 @@ class LCD:
|
|
|
self.__set_lcd_brightness()
|
|
|
|
|
|
@property
|
|
|
- def lcd_ascii_table(self):
|
|
|
- return self.__lcd_ascii_table
|
|
|
+ def lcd_ascii_rom(self):
|
|
|
+ return self.__lcd_ascii_rom
|
|
|
|
|
|
- @lcd_ascii_table.setter
|
|
|
- def lcd_ascii_table(self, lcd_ascii_table: int|str):
|
|
|
- self.__lcd_ascii_table = self.__check_lcd_ascii_table(lcd_ascii_table)
|
|
|
- self.__set_lcd_ascii_table()
|
|
|
+ @lcd_ascii_rom.setter
|
|
|
+ def lcd_ascii_rom(self, lcd_ascii_rom: int|str):
|
|
|
+ self.__lcd_ascii_rom = self.__check_lcd_ascii_rom(lcd_ascii_rom)
|
|
|
+ self.__set_lcd_ascii_rom()
|
|
|
|
|
|
@property
|
|
|
def lcd_contrast(self):
|
|
@@ -179,12 +179,7 @@ class LCD:
|
|
|
|
|
|
@i2c_sda_pin.setter
|
|
|
def i2c_sda_pin(self, i2c_sda_pin: int|str):
|
|
|
- self.__check_i2c_ports(i2c_sda_pin, self.__i2c_scl_pin)
|
|
|
- self.__deinit_i2c()
|
|
|
- (self.__i2c_bus,
|
|
|
- self.__i2c_sda_pin,
|
|
|
- self.__i2c_scl_pin) = self.__check_i2c_ports(i2c_sda_pin, self.__i2c_scl_pin)
|
|
|
- self.__init_i2c()
|
|
|
+ self.change_i2c_port(i2c_sda_pin, self.__i2c_scl_pin)
|
|
|
|
|
|
@property
|
|
|
def i2c_scl_pin(self):
|
|
@@ -192,12 +187,7 @@ class LCD:
|
|
|
|
|
|
@i2c_scl_pin.setter
|
|
|
def i2c_scl_pin(self, i2c_scl_pin: int|str):
|
|
|
- self.__check_i2c_ports(self.__i2c_sda_pin, i2c_scl_pin)
|
|
|
- self.__deinit_i2c()
|
|
|
- (self.__i2c_bus,
|
|
|
- self.__i2c_sda_pin,
|
|
|
- self.__i2c_scl_pin) = self.__check_i2c_ports(self.__i2c_sda_pin, i2c_scl_pin)
|
|
|
- self.__init_i2c()
|
|
|
+ self.change_i2c_port(self.__i2c_sda_pin, i2c_scl_pin)
|
|
|
|
|
|
############################## Methods private ##############################
|
|
|
|
|
@@ -248,19 +238,20 @@ class LCD:
|
|
|
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 > 63:
|
|
|
+ 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_ascii_table(self, lcd_ascii_table: int|str):
|
|
|
- if not isinstance(lcd_ascii_table, int) and not isinstance(lcd_ascii_table, str):
|
|
|
- raise ValueError(f"Value \"{lcd_ascii_table}\" of \"lcd_ascii_table\" is not type" +
|
|
|
+ def __check_lcd_ascii_rom(self, lcd_ascii_rom: int|str):
|
|
|
+ if not isinstance(lcd_ascii_rom, int) and not isinstance(lcd_ascii_rom, str):
|
|
|
+ raise ValueError(f"Value \"{lcd_ascii_rom}\" of \"lcd_ascii_rom\" is not type" +
|
|
|
" \"int\" or \"str\"!")
|
|
|
- elif lcd_ascii_table not in self.__lcd_rom.keys():
|
|
|
- raise ValueError(f"Value \"{lcd_ascii_table}\" of \"lcd_ascii_table\" is not supported!")
|
|
|
+ elif((isinstance(lcd_ascii_rom, int) and lcd_ascii_rom not in self.__lcd_rom.keys()) or
|
|
|
+ (isinstance(lcd_ascii_rom, str) and lcd_ascii_rom.upper() not in self.__lcd_rom.keys())):
|
|
|
+ raise ValueError(f"Value \"{lcd_ascii_rom}\" of \"lcd_ascii_rom\" is not supported!")
|
|
|
else:
|
|
|
- return lcd_ascii_table
|
|
|
+ return lcd_ascii_rom
|
|
|
|
|
|
def __check_i2c_ports(self, i2c_sda_pin: int|str, i2c_scl_pin: int|str):
|
|
|
if not isinstance(i2c_sda_pin, int) and not isinstance(i2c_sda_pin, str):
|
|
@@ -343,7 +334,7 @@ class LCD:
|
|
|
self.__lcd_setting_para["LCD_PARA_DIS_CON"])
|
|
|
self.__i2c.writeto(self.__i2c_address, bytes(buffer))
|
|
|
self.__set_lcd_line_mode()
|
|
|
- self.__set_lcd_ascii_table()
|
|
|
+ self.__set_lcd_ascii_rom()
|
|
|
self.__set_lcd_contrast()
|
|
|
self.__set_lcd_direction()
|
|
|
self.clear()
|
|
@@ -364,22 +355,27 @@ class LCD:
|
|
|
def __set_lcd_brightness(self):
|
|
|
self.__backlight_pwm.duty_u16(round(65635 * (self.__lcd_brightness / 100)))
|
|
|
|
|
|
- def __set_lcd_ascii_table(self):
|
|
|
+ def __set_lcd_ascii_rom(self):
|
|
|
+ if isinstance(self.__lcd_ascii_rom, str):
|
|
|
+ lcd_ascii_rom = self.__lcd_ascii_rom.upper()
|
|
|
+ else:
|
|
|
+ lcd_ascii_rom = self.__lcd_ascii_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_rom[self.__lcd_ascii_table] << 0x02,
|
|
|
+ self.__lcd_rom[lcd_ascii_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"] | (self.__lcd_contrast >> 0x04),
|
|
|
- self.__lcd_contrast_para["LCD_PARA_CONTRAST"] | (self.__lcd_contrast & 0x0F),
|
|
|
+ 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))
|
|
|
|
|
@@ -404,6 +400,36 @@ class LCD:
|
|
|
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]):
|
|
|
+ rows = 0x04 if self.__lcd_line_mode == 0x00 else 0x02 if self.__lcd_line_mode == 0x03 else 0x03
|
|
|
+ output = {"rows": rows, "row": 0x01, "column": 0x01, "auto_line_break": True}
|
|
|
+ for key, val in keywords.items():
|
|
|
+ if key not in keys:
|
|
|
+ raise ValueError(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})
|
|
|
+ return output.copy()
|
|
|
+
|
|
|
############################## Methods public ##############################
|
|
|
|
|
|
def change_i2c_port(self, i2c_sda_pin: int|str, i2c_scl_pin: int|str):
|
|
@@ -421,55 +447,60 @@ class LCD:
|
|
|
elif len(text) == 0:
|
|
|
raise ValueError(f"Value \"{text}\" of \"text\" is out of range!")
|
|
|
|
|
|
- def check_keywords(keywords):
|
|
|
- pass
|
|
|
-
|
|
|
- buffer = []
|
|
|
- char=0
|
|
|
+ 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")
|
|
|
- column = 0
|
|
|
- line = 1
|
|
|
- lines = 4 if self.__lcd_line_mode == 0 else 2 if self.__lcd_line_mode == 3 else 3
|
|
|
-
|
|
|
- if len(keywords) == 0:
|
|
|
- check_text(text)
|
|
|
- for row in range(line,lines + 1):
|
|
|
- print(len(text))
|
|
|
- if len(text) == 0:
|
|
|
+ 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"])
|
|
|
- buffer.append(self.__lcd_control_para["DISPLAY_ROW_" + str(row)])
|
|
|
- for char in range(0, self.__lcd_control_para["DISPLAY_COLUMN"] if
|
|
|
- len(text) > self.__lcd_control_para["DISPLAY_COLUMN"] else
|
|
|
- len(text)):
|
|
|
- if text[char] in linefeed:
|
|
|
- text = text[char + 1:]
|
|
|
- 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"]:]
|
|
|
- else:
|
|
|
- check_text(text)
|
|
|
- check_keywords(keywords)
|
|
|
- print(keywords)
|
|
|
+ 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):
|
|
|
- buffer = (self.__lcd_control_para["CONTROL_BYTE"],
|
|
|
- self.__lcd_control_para["CLEAR_DISPLAY"])
|
|
|
+ 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))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
- lcd = LCD(i2c_scl_pin="GP1",
|
|
|
- i2c_sda_pin=0,
|
|
|
- i2c_frequency=400000,
|
|
|
- lcd_backlight_pin=5,
|
|
|
- lcd_direction_top=False,
|
|
|
- lcd_line_mode=0,
|
|
|
- lcd_contrast=40,
|
|
|
- lcd_brightness=100,
|
|
|
- lcd_ascii_table="B")
|
|
|
+ lcd = LCD()
|
|
|
lcd.print("Hallöle")
|
|
|
sleep_us(2000000)
|
|
|
lcd.clear()
|