123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- """
- Author: Tobias Müller
- Date: 30.06.2023
- Version: 0.5
- This file contains classes for LCD, Button and Led control.
- """
- ############################## Modules ##############################
- from time import sleep_us
- from machine import Pin, PWM, I2C
- import re
- ############################## Code ##############################
- class LCD:
- ############################## Attributes ##############################
- __lcd_setting = {"CONTROL_BYTE": 0x80, # Set Continue Bit
- "LCD_PARA_FUNC1": 0x3A, # Function Set 1 (8 Bit, RE = 1, IS = 0)
- "LCD_PARA_EXT_FUNC": 0x09, # Extended Function
- "LCD_PARA_ENTRY_MODE": 0x06, # Bottom View
- "LCD_PARA_BIAS_SET": 0x1E, # Bias Setting
- "LCD_PARA_FUNC2": 0x39, # Function Set 2 (8 Bit, RE = 0, IS = 1)
- "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_POW_CON": 0x56, # Power Control (Booster on, Set Contrast)
- "LCD_PARA_CONTRAST": 0x7A, # Set Contrast
- "LCD_PARA_FUNC3": 0x38, # Function Set 3 (8 Bit, RE = 0, IS = 0)
- "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|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 ##############################
- @property
- def lcd_brightness(self):
- return self.__lcd_brightness
- @lcd_brightness.setter
- 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 __reset_pin(pin):
- Pin(pin, Pin.IN, None)
- @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_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, 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__":
- lcd = LCD(i2c_scl_pin="GP3", i2c_sda_pin=2, i2c_frequency=100000)
- lcd.print("Hallo")
|