__init__.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. """
  2. Author: Tobias Müller
  3. Date: 30.06.2023
  4. Version: 0.5
  5. This file contains classes for LCD, Button and Led control.
  6. """
  7. ############################## Modules ##############################
  8. from time import sleep_us
  9. from machine import Pin, PWM, I2C
  10. import re
  11. ############################## Code ##############################
  12. class LCD:
  13. ############################## Attributes ##############################
  14. __lcd_setting = {"CONTROL_BYTE": 0x80, # Set Continue Bit
  15. "LCD_PARA_FUNC1": 0x3A, # Function Set 1 (8 Bit, RE = 1, IS = 0)
  16. "LCD_PARA_EXT_FUNC": 0x09, # Extended Function
  17. "LCD_PARA_ENTRY_MODE": 0x06, # Bottom View
  18. "LCD_PARA_BIAS_SET": 0x1E, # Bias Setting
  19. "LCD_PARA_FUNC2": 0x39, # Function Set 2 (8 Bit, RE = 0, IS = 1)
  20. "LCD_PARA_INT_OSC": 0x1B, # Internal OSC (BS0 = 1, Bias = 1/6)
  21. "LCD_PARA_FOL_CON": 0x6E, # Follower Control (Devider on, Set Value)
  22. "LCD_PARA_POW_CON": 0x56, # Power Control (Booster on, Set Contrast)
  23. "LCD_PARA_CONTRAST": 0x7A, # Set Contrast
  24. "LCD_PARA_FUNC3": 0x38, # Function Set 3 (8 Bit, RE = 0, IS = 0)
  25. "LCD_PARA_DIS_CON": 0x0C, # Display on/off Control (Cursor off, Blink off)
  26. "LCD_PARA_CLR_DIS": 0x01} # Clear Display
  27. __lcd_control = {"CONTROL_BYTE": 0x80, # Set Continue Bit
  28. "CONTROL_BYTE_DCB": 0x40, # Data/Command Selection Bit set
  29. "LCD_PARA_CLR_DIS": 0x01, # Clear Display
  30. "LCD_PARA_DIS_ROW1": 0x80, # Display Row 1
  31. "LCD_PARA_DIS_ROW2": 0xA0, # Display Row 2
  32. "LCD_PARA_DIS_ROW3": 0xC0, # Display Row 3
  33. "LCD_PARA_DIS_ROW4": 0xE0, # Display Row 4
  34. "LCD_PARA_DIS_COLUMN": 0x0A} # Columns per Display Row
  35. __i2c_ports = {"I2C0": {"SDA_PINS": [0, 4 ,8 ,12 ,16 ,20],
  36. "SCL_PINS": [1, 5, 9, 13, 17, 21]},
  37. "I2C1": {"SDA_PINS": [2, 6, 10, 14, 18, 26],
  38. "SCL_PINS": [3, 7, 11, 15, 19, 27]}}
  39. __i2c_frequencies = {"STANDARD_MODE": 100000,
  40. "FAST_MODE": 400000,
  41. "FAST_MODE_PLUS": 1000000}
  42. __i2c_address = 0x3c
  43. ############################## Constructor ##############################
  44. def __init__(self,
  45. i2c_sda_pin: int|str = 2,
  46. i2c_scl_pin: int|str = 3,
  47. i2c_frequency: int|str = 400000,
  48. lcd_backlight_pin: int|str = 28,
  49. lcd_brightness: int = 100):
  50. # Check and store input values
  51. self.__I2C_Bus, self.__I2C_SDA_Pin, self.__I2C_SCL_Pin = self.__check_i2c_ports(i2c_sda_pin,
  52. i2c_scl_pin)
  53. self.__i2c_frequency = self.__check_i2c_speed(i2c_frequency)
  54. self.__lcd_backlight_pin = self.__check_lcd_backlight_pin(lcd_backlight_pin)
  55. self.__lcd_brightness = self.__check_lcd_brightness(lcd_brightness)
  56. # init i2c and backlight
  57. self.__init_i2c()
  58. self.__init_backlight_pwm()
  59. ############################## Properties ##############################
  60. @property
  61. def lcd_brightness(self):
  62. return self.__lcd_brightness
  63. @lcd_brightness.setter
  64. def lcd_brightness(self, lcd_brightness: int):
  65. self.__lcd_brightness = self.__check_lcd_brightness(lcd_brightness)
  66. self.__backlight_pwm.duty_u16(round(65635 * (lcd_brightness / 100)))
  67. ############################## Methods private ##############################
  68. @staticmethod
  69. def __reset_pin(pin):
  70. Pin(pin, Pin.IN, None)
  71. @staticmethod
  72. def __check_lcd_brightness(lcd_brightness):
  73. if not isinstance(lcd_brightness, int):
  74. raise ValueError(f"Value \"{lcd_brightness}\" of \"lcd_brightness\" is not type \"int\"!")
  75. elif lcd_brightness < 0 or lcd_brightness > 100:
  76. raise ValueError(f"Value \"{lcd_brightness}\" of \"lcd_brightness\" is out of range!")
  77. else:
  78. return lcd_brightness
  79. @staticmethod
  80. def __check_lcd_backlight_pin(lcd_backlight_pin):
  81. if not isinstance(lcd_backlight_pin, int) and not isinstance(lcd_backlight_pin, str):
  82. raise ValueError(f"Value \"{lcd_backlight_pin}\" of \"lcd_backlight_pin\" is not type" +
  83. " \"int\" or \"str\"!")
  84. elif isinstance(lcd_backlight_pin, str) and not re.match(r"^GP\d\d?$",lcd_backlight_pin):
  85. raise ValueError(f"String value \"{lcd_backlight_pin}\" of \"lcd_backlight_pin\" has" +
  86. " wrong format!")
  87. else:
  88. return lcd_backlight_pin
  89. def __check_i2c_ports(self, i2c_sda_pin, i2c_scl_pin):
  90. if not isinstance(i2c_sda_pin, int) and not isinstance(i2c_sda_pin, str):
  91. raise ValueError(f"Value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" is not type \"int\"" +
  92. " or \"str\"!")
  93. elif not isinstance(i2c_scl_pin, int) and not isinstance(i2c_scl_pin, str):
  94. raise ValueError(f"Value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" is not type \"int\"" +
  95. " or \"str\"!")
  96. elif isinstance(i2c_sda_pin, str) and not re.match(r"^GP\d\d?$",i2c_sda_pin):
  97. raise ValueError(f"String value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" has wrong format!")
  98. elif isinstance(i2c_scl_pin, str) and not re.match(r"^GP\d\d?$",i2c_scl_pin):
  99. raise ValueError(f"String value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" has wrong format!")
  100. elif ((isinstance(i2c_sda_pin, int) and
  101. not i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"] and
  102. not i2c_sda_pin in self.__i2c_ports["I2C1"]["SDA_PINS"]) or
  103. (isinstance(i2c_sda_pin, str) and
  104. not int(i2c_sda_pin[2:]) in self.__i2c_ports["I2C0"]["SDA_PINS"] and
  105. not int(i2c_sda_pin[2:]) in self.__i2c_ports["I2C1"]["SDA_PINS"])):
  106. raise ValueError(f"Value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" is not an I2C SDA-Pin!")
  107. elif ((isinstance(i2c_scl_pin, int) and
  108. not i2c_scl_pin in self.__i2c_ports["I2C0"]["SCL_PINS"] and
  109. not i2c_scl_pin in self.__i2c_ports["I2C1"]["SCL_PINS"]) or
  110. (isinstance(i2c_scl_pin, str) and
  111. not int(i2c_scl_pin[2:]) in self.__i2c_ports["I2C0"]["SCL_PINS"] and
  112. not int(i2c_scl_pin[2:]) in self.__i2c_ports["I2C1"]["SCL_PINS"])):
  113. raise ValueError(f"Value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" is not an I2C SCL-Pin!")
  114. elif ((((isinstance(i2c_sda_pin, int) and
  115. i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"]) or
  116. (isinstance(i2c_sda_pin, str) and
  117. int(i2c_sda_pin[2:]) in self.__i2c_ports["I2C0"]["SDA_PINS"])) and not
  118. ((isinstance(i2c_scl_pin, int) and
  119. i2c_scl_pin in self.__i2c_ports["I2C0"]["SCL_PINS"]) or
  120. (isinstance(i2c_scl_pin, str) and
  121. int(i2c_scl_pin[2:]) in self.__i2c_ports["I2C0"]["SCL_PINS"]))) or
  122. (((isinstance(i2c_sda_pin, int) and
  123. i2c_sda_pin in self.__i2c_ports["I2C1"]["SDA_PINS"]) or
  124. (isinstance(i2c_sda_pin, str) and
  125. int(i2c_sda_pin[2:]) in self.__i2c_ports["I2C1"]["SDA_PINS"])) and not
  126. ((isinstance(i2c_scl_pin, int) and
  127. i2c_scl_pin in self.__i2c_ports["I2C1"]["SCL_PINS"]) or
  128. (isinstance(i2c_scl_pin, str) and
  129. int(i2c_scl_pin[2:]) in self.__i2c_ports["I2C1"]["SCL_PINS"])))):
  130. raise ValueError(f"Value \"{i2c_scl_pin}\" of \"i2c_scl_pin\" and " +
  131. f"Value \"{i2c_sda_pin}\" of \"i2c_sda_pin\" " +
  132. "are not part of the same I2C Bus!")
  133. else:
  134. if ((isinstance(i2c_sda_pin, int) and
  135. i2c_sda_pin in self.__i2c_ports["I2C0"]["SDA_PINS"]) or
  136. (isinstance(i2c_sda_pin, str) and
  137. int(i2c_sda_pin[2:]) in self.__i2c_ports["I2C0"]["SDA_PINS"])):
  138. return 0, i2c_sda_pin, i2c_scl_pin
  139. else:
  140. return 1, i2c_sda_pin, i2c_scl_pin
  141. def __check_i2c_speed(self, i2c_frequency):
  142. if not isinstance(i2c_frequency, int) and not isinstance(i2c_frequency, str):
  143. raise ValueError(f"Value \"{i2c_frequency}\" of \"i2c_frequency\" is not type \"int\"" +
  144. " or \"str\"!")
  145. elif (isinstance(i2c_frequency, int) and not i2c_frequency in self.__i2c_frequencies.values() or
  146. isinstance(i2c_frequency, str) and not i2c_frequency in self.__i2c_frequencies.keys()):
  147. raise ValueError(f"Value \"{i2c_frequency}\" of \"i2c_frequency\" is not supported!")
  148. else:
  149. return i2c_frequency
  150. def __init_i2c(self):
  151. self.__i2c = I2C(self.__I2C_Bus,
  152. sda=Pin(self.__I2C_SDA_Pin),
  153. scl=Pin(self.__I2C_SCL_Pin),
  154. freq=(self.__i2c_frequency if isinstance(self.__i2c_frequency, int) else
  155. self.__i2c_frequencies[self.__i2c_frequency]))
  156. self.__i2c.writeto(self.__i2c_address, bytes(self.__lcd_setting.values()))
  157. def __deinit_i2c(self):
  158. self.__reset_pin(self.__I2C_SCL_Pin)
  159. self.__reset_pin(self.__I2C_SDA_Pin)
  160. def __init_backlight_pwm(self):
  161. self.__backlight_pwm = PWM(Pin(self.__lcd_backlight_pin))
  162. self.__backlight_pwm.freq(1000)
  163. self.__backlight_pwm.duty_u16(round(65635 * (self.lcd_brightness / 100)))
  164. def __deinit_backlight_pwm(self):
  165. self.__backlight_pwm.deinit()
  166. self.__reset_pin(self.__lcd_backlight_pin)
  167. ############################## Methods public ##############################
  168. def change_i2c_port(self, i2c_sda_pin: int|str, i2c_scl_pin: int|str):
  169. self.__I2C_Bus, i2c_sda_pin, i2c_scl_pin = self.__check_i2c_ports(i2c_sda_pin, i2c_scl_pin)
  170. self.__deinit_i2c()
  171. self.__I2C_SCL_Pin = i2c_scl_pin
  172. self.__I2C_SDA_Pin = i2c_sda_pin
  173. self.__init_i2c()
  174. def print(self, text: str, **keywords):
  175. if not isinstance(text, str):
  176. raise ValueError(f"Value \"{text}\" of \"text\" is not type \"str\"!")
  177. elif len(keywords) == 0:
  178. self.clear()
  179. buffer = [self.__lcd_control["CONTROL_BYTE"]]
  180. buffer.append(self.__lcd_control["LCD_PARA_DIS_ROW1"])
  181. buffer.append(self.__lcd_control["CONTROL_BYTE_DCB"])
  182. for i in range(0, self.__lcd_control["LCD_PARA_DIS_COLUMN"] if
  183. len(text) > self.__lcd_control["LCD_PARA_DIS_COLUMN"] else len(text)):
  184. buffer.append(ord(text[i]))
  185. print(bytes(buffer))
  186. self.__i2c.writeto(self.__i2c_address, bytes(buffer))
  187. def clear(self):
  188. buffer = [self.__lcd_control["CONTROL_BYTE"], self.__lcd_control["LCD_PARA_CLR_DIS"]]
  189. self.__i2c.writeto(self.__i2c_address, bytes(buffer))
  190. if __name__ == "__main__":
  191. lcd = LCD(i2c_scl_pin="GP3", i2c_sda_pin=2, i2c_frequency=100000)
  192. lcd.print("Hallo")