|
@@ -1,7 +1,7 @@
|
|
|
"""
|
|
|
Author: Tobias Müller
|
|
|
Date: 30.06.2023
|
|
|
-Version: 1.0
|
|
|
+Version: 0.5
|
|
|
|
|
|
This file contains classes for LCD, Button and Led control.
|
|
|
"""
|
|
@@ -10,6 +10,7 @@ This file contains classes for LCD, Button and Led control.
|
|
|
|
|
|
from time import sleep_us
|
|
|
from machine import Pin, PWM, I2C
|
|
|
+import re
|
|
|
|
|
|
############################## Code ##############################
|
|
|
|
|
@@ -31,16 +32,45 @@ class LCD:
|
|
|
"LCD_PARA_DIS_CON": 0x0C, # Display on/off Control (Cursor off, Blink off)
|
|
|
"LCD_PARA_CLR_DIS": 0x01} # Clear Display
|
|
|
|
|
|
+ __lcd_control = {"CONTROL_BYTE": 0x80, # Set Continue Bit
|
|
|
+ "CONTROL_BYTE_DCB": 0x40, # Data/Command Selection Bit set
|
|
|
+ "LCD_PARA_CLR_DIS": 0x01, # Clear Display
|
|
|
+ "LCD_PARA_DIS_ROW1": 0x80, # Display Row 1
|
|
|
+ "LCD_PARA_DIS_ROW2": 0xA0, # Display Row 2
|
|
|
+ "LCD_PARA_DIS_ROW3": 0xC0, # Display Row 3
|
|
|
+ "LCD_PARA_DIS_ROW4": 0xE0, # Display Row 4
|
|
|
+ "LCD_PARA_DIS_COLUMN": 0x0A} # Columns per Display Row
|
|
|
+
|
|
|
+ __i2c_ports = {"I2C0": {"SDA_PINS": [0, 4 ,8 ,12 ,16 ,20],
|
|
|
+ "SCL_PINS": [1, 5, 9, 13, 17, 21]},
|
|
|
+ "I2C1": {"SDA_PINS": [2, 6, 10, 14, 18, 26],
|
|
|
+ "SCL_PINS": [3, 7, 11, 15, 19, 27]}}
|
|
|
+
|
|
|
+ __i2c_frequencies = {"STANDARD_MODE": 100000,
|
|
|
+ "FAST_MODE": 400000,
|
|
|
+ "FAST_MODE_PLUS": 1000000}
|
|
|
+
|
|
|
+ __i2c_address = 0x3c
|
|
|
+
|
|
|
############################## Constructor ##############################
|
|
|
|
|
|
def __init__(self,
|
|
|
- I2C_SDA_Pin: int = 2,
|
|
|
- I2C_SCL_Pin: int = 3,
|
|
|
- LCD_Brightness: int = 100):
|
|
|
-
|
|
|
- self.__i2c_sda_pin, self.__i2c_scl_pin = self.__check_i2c_ports(I2C_SDA_Pin,
|
|
|
- I2C_SCL_Pin)
|
|
|
- self.__lcd_brightness = self.__check_lcd_brightness(LCD_Brightness)
|
|
|
+ i2c_sda_pin: int|str = 2,
|
|
|
+ i2c_scl_pin: int|str = 3,
|
|
|
+ i2c_frequency: int|str = 400000,
|
|
|
+ lcd_backlight_pin: int|str = 28,
|
|
|
+ lcd_brightness: int = 100):
|
|
|
+
|
|
|
+ # 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_speed(i2c_frequency)
|
|
|
+ self.__lcd_backlight_pin = self.__check_lcd_backlight_pin(lcd_backlight_pin)
|
|
|
+ self.__lcd_brightness = self.__check_lcd_brightness(lcd_brightness)
|
|
|
+
|
|
|
+ # init i2c and backlight
|
|
|
+ self.__init_i2c()
|
|
|
+ self.__init_backlight_pwm()
|
|
|
|
|
|
############################## Properties ##############################
|
|
|
|
|
@@ -49,34 +79,148 @@ class LCD:
|
|
|
return self.__lcd_brightness
|
|
|
|
|
|
@lcd_brightness.setter
|
|
|
- def lcd_brightness(self, value: int):
|
|
|
- self.__lcd_brightness = self.__check_lcd_brightness(value)
|
|
|
- self.__set_lcd_brightness()
|
|
|
+ def lcd_brightness(self, lcd_brightness: int):
|
|
|
+ self.__lcd_brightness = self.__check_lcd_brightness(lcd_brightness)
|
|
|
+ self.__backlight_pwm.duty_u16(round(65635 * (lcd_brightness / 100)))
|
|
|
|
|
|
############################## Methods private ##############################
|
|
|
|
|
|
@staticmethod
|
|
|
- def __check_lcd_brightness(value):
|
|
|
- if not isinstance(value, int):
|
|
|
- raise ValueError(f"Value \"{value}\" for \"lcd_brightness\" is not type \"int\"!")
|
|
|
- elif value < 0 or value > 100:
|
|
|
- raise ValueError(f"Value \"{value}\" for \"lcd_brightness\" is out of range!")
|
|
|
- else:
|
|
|
- return value
|
|
|
+ def __reset_pin(pin):
|
|
|
+ Pin(pin, Pin.IN, None)
|
|
|
|
|
|
- def __set_lcd_brightness(self):
|
|
|
- pass
|
|
|
+ @staticmethod
|
|
|
+ def __check_lcd_brightness(lcd_brightness):
|
|
|
+ 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_i2c_ports(SDA_Pin, SCL_Pin):
|
|
|
- return SDA_Pin, SCL_Pin
|
|
|
+ def __check_lcd_backlight_pin(lcd_backlight_pin):
|
|
|
+ if not isinstance(lcd_backlight_pin, int) and not isinstance(lcd_backlight_pin, str):
|
|
|
+ raise ValueError(f"Value \"{lcd_backlight_pin}\" of \"lcd_backlight_pin\" is not type" +
|
|
|
+ " \"int\" or \"str\"!")
|
|
|
+ elif isinstance(lcd_backlight_pin, str) and not re.match(r"^GP\d\d?$",lcd_backlight_pin):
|
|
|
+ raise ValueError(f"String value \"{lcd_backlight_pin}\" of \"lcd_backlight_pin\" has" +
|
|
|
+ " wrong format!")
|
|
|
+ else:
|
|
|
+ return lcd_backlight_pin
|
|
|
+
|
|
|
+ def __check_i2c_ports(self, i2c_sda_pin, i2c_scl_pin):
|
|
|
+ if not isinstance(i2c_sda_pin, int) and not isinstance(i2c_sda_pin, str):
|
|
|
+ raise ValueError(f"Value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" is not type \"int\"" +
|
|
|
+ " or \"str\"!")
|
|
|
+ elif not isinstance(i2c_scl_pin, int) and not isinstance(i2c_scl_pin, str):
|
|
|
+ raise ValueError(f"Value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" is not type \"int\"" +
|
|
|
+ " or \"str\"!")
|
|
|
+ elif isinstance(i2c_sda_pin, str) and not re.match(r"^GP\d\d?$",i2c_sda_pin):
|
|
|
+ raise ValueError(f"String value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" has wrong format!")
|
|
|
+ elif isinstance(i2c_scl_pin, str) and not re.match(r"^GP\d\d?$",i2c_scl_pin):
|
|
|
+ raise ValueError(f"String value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" has wrong format!")
|
|
|
+ elif ((isinstance(i2c_sda_pin, int) and
|
|
|
+ not i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"] and
|
|
|
+ not i2c_sda_pin in self.__i2c_ports["I2C1"]["SDA_PINS"]) or
|
|
|
+ (isinstance(i2c_sda_pin, str) and
|
|
|
+ not int(i2c_sda_pin[2:]) in self.__i2c_ports["I2C0"]["SDA_PINS"] and
|
|
|
+ not int(i2c_sda_pin[2:]) 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 ((isinstance(i2c_scl_pin, int) and
|
|
|
+ not i2c_scl_pin in self.__i2c_ports["I2C0"]["SCL_PINS"] and
|
|
|
+ not i2c_scl_pin in self.__i2c_ports["I2C1"]["SCL_PINS"]) or
|
|
|
+ (isinstance(i2c_scl_pin, str) and
|
|
|
+ not int(i2c_scl_pin[2:]) in self.__i2c_ports["I2C0"]["SCL_PINS"] and
|
|
|
+ not int(i2c_scl_pin[2:]) 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 ((((isinstance(i2c_sda_pin, int) and
|
|
|
+ i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"]) or
|
|
|
+ (isinstance(i2c_sda_pin, str) and
|
|
|
+ int(i2c_sda_pin[2:]) in self.__i2c_ports["I2C0"]["SDA_PINS"])) and not
|
|
|
+ ((isinstance(i2c_scl_pin, int) and
|
|
|
+ i2c_scl_pin in self.__i2c_ports["I2C0"]["SCL_PINS"]) or
|
|
|
+ (isinstance(i2c_scl_pin, str) and
|
|
|
+ int(i2c_scl_pin[2:]) in self.__i2c_ports["I2C0"]["SCL_PINS"]))) or
|
|
|
+ (((isinstance(i2c_sda_pin, int) and
|
|
|
+ i2c_sda_pin in self.__i2c_ports["I2C1"]["SDA_PINS"]) or
|
|
|
+ (isinstance(i2c_sda_pin, str) and
|
|
|
+ int(i2c_sda_pin[2:]) in self.__i2c_ports["I2C1"]["SDA_PINS"])) and not
|
|
|
+ ((isinstance(i2c_scl_pin, int) and
|
|
|
+ i2c_scl_pin in self.__i2c_ports["I2C1"]["SCL_PINS"]) or
|
|
|
+ (isinstance(i2c_scl_pin, str) and
|
|
|
+ int(i2c_scl_pin[2:]) 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 ((isinstance(i2c_sda_pin, int) and
|
|
|
+ i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"]) or
|
|
|
+ (isinstance(i2c_sda_pin, str) and
|
|
|
+ int(i2c_sda_pin[2:]) 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_speed(self, i2c_frequency):
|
|
|
+ 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=Pin(self.__I2C_SDA_Pin),
|
|
|
+ scl=Pin(self.__I2C_SCL_Pin),
|
|
|
+ freq=(self.__i2c_frequency if isinstance(self.__i2c_frequency, int) else
|
|
|
+ self.__i2c_frequencies[self.__i2c_frequency]))
|
|
|
+ self.__i2c.writeto(self.__i2c_address, bytes(self.__lcd_setting.values()))
|
|
|
+
|
|
|
+ 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(Pin(self.__lcd_backlight_pin))
|
|
|
+ self.__backlight_pwm.freq(1000)
|
|
|
+ self.__backlight_pwm.duty_u16(round(65635 * (self.lcd_brightness / 100)))
|
|
|
+
|
|
|
+ def __deinit_backlight_pwm(self):
|
|
|
+ self.__backlight_pwm.deinit()
|
|
|
+ self.__reset_pin(self.__lcd_backlight_pin)
|
|
|
|
|
|
############################## Methods public ##############################
|
|
|
|
|
|
- def change_I2C_port(self, SDA_Pin, SCL_Pin):
|
|
|
- pass
|
|
|
-
|
|
|
+ def change_i2c_port(self, i2c_sda_pin: int|str, i2c_scl_pin: int|str):
|
|
|
+ self.__I2C_Bus, i2c_sda_pin, i2c_scl_pin = self.__check_i2c_ports(i2c_sda_pin, i2c_scl_pin)
|
|
|
+ self.__deinit_i2c()
|
|
|
+ self.__I2C_SCL_Pin = i2c_scl_pin
|
|
|
+ self.__I2C_SDA_Pin = i2c_sda_pin
|
|
|
+ self.__init_i2c()
|
|
|
+
|
|
|
+ def print(self, text: str, **keywords):
|
|
|
+ if not isinstance(text, str):
|
|
|
+ raise ValueError(f"Value \"{text}\" of \"text\" is not type \"str\"!")
|
|
|
+ elif len(keywords) == 0:
|
|
|
+ self.clear()
|
|
|
+ buffer = [self.__lcd_control["CONTROL_BYTE"]]
|
|
|
+ buffer.append(self.__lcd_control["LCD_PARA_DIS_ROW1"])
|
|
|
+ buffer.append(self.__lcd_control["CONTROL_BYTE_DCB"])
|
|
|
+ for i in range(0, self.__lcd_control["LCD_PARA_DIS_COLUMN"] if
|
|
|
+ len(text) > self.__lcd_control["LCD_PARA_DIS_COLUMN"] else len(text)):
|
|
|
+ buffer.append(ord(text[i]))
|
|
|
+ print(bytes(buffer))
|
|
|
+ self.__i2c.writeto(self.__i2c_address, bytes(buffer))
|
|
|
+
|
|
|
+ def clear(self):
|
|
|
+ buffer = [self.__lcd_control["CONTROL_BYTE"], self.__lcd_control["LCD_PARA_CLR_DIS"]]
|
|
|
+ self.__i2c.writeto(self.__i2c_address, bytes(buffer))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
- pass
|
|
|
-
|
|
|
+ lcd = LCD(i2c_scl_pin="GP3", i2c_sda_pin=2, i2c_frequency=100000)
|
|
|
+ lcd.print("Hallo")
|