lcd.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import gc
  2. from machine import I2C
  3. from lcd import color, constant, font
  4. class LCD(object):
  5. def __init__(self, dt=constant.I2C128x64, baud=constant.I2CBAUDRATE):
  6. self.__width = int(dt['width'] if 'width' in dt else 0)
  7. self.__height = int(dt['height'] if 'height' in dt else 0)
  8. self.__pages = int(self.__height / 8)
  9. self.__buff_size = int(self.__width * self.__height / 8)
  10. self.__buffer = [0] * self.__buff_size
  11. self.__i2c = I2C(0, I2C.MASTER, baudrate=baud)
  12. self.__write(constant.SSD1306_DISPLAYOFF)
  13. self.__write(constant.SSD1306_SETDISPLAYCLOCKDIV, 0x80)
  14. self.__write(constant.SSD1306_SETDISPLAYOFFSET, 0x0)
  15. self.__write(constant.SSD1306_SETSTARTLINE | 0x0)
  16. self.__write(constant.SSD1306_CHARGEPUMP, 0x14)
  17. self.__write(constant.SSD1306_MEMORYMODE, 0x00)
  18. self.__write(constant.SSD1306_COLUMNADDR, 0, self.__width - 1)
  19. self.__write(constant.SSD1306_PAGEADDR, 0, self.__pages - 1)
  20. self.__write(constant.SSD1306_SEGREMAP | 0x1)
  21. self.__write(constant.SSD1306_COMSCANDEC)
  22. self.__write(constant.SSD1306_SETPRECHARGE, 0xF1)
  23. self.__write(constant.SSD1306_SETVCOMDETECT, 0x40)
  24. self.__write(constant.SSD1306_DISPLAYALLON_RESUME)
  25. self.__write(constant.SSD1306_NORMALDISPLAY)
  26. if dt == constant.I2C128x32:
  27. self.__write(constant.SSD1306_SETMULTIPLEX, 0x1F)
  28. self.__write(constant.SSD1306_SETCOMPINS, 0x02)
  29. self.__write(constant.SSD1306_SETCONTRAST, 0x8F)
  30. elif dt == constant.I2C128x64:
  31. self.__write(constant.SSD1306_SETMULTIPLEX, 0x3F)
  32. self.__write(constant.SSD1306_SETCOMPINS, 0x12)
  33. self.__write(constant.SSD1306_SETCONTRAST, 0xCF)
  34. else:
  35. raise NotImplementedError
  36. self.display_clear(True)
  37. self.display_off()
  38. def __write(self, *args):
  39. b = [0]
  40. if len(args) == 1 and type(args[0]) == bytearray:
  41. b = args[0]
  42. else:
  43. b = bytearray(b + list(args))
  44. self.__i2c.writeto(constant.SSD1306_I2C_ADDRESS, b)
  45. gc.collect()
  46. def display_contrast(self, c):
  47. if c < 0 or c > 255:
  48. raise ValueError("Contrast must be between 0-255")
  49. self.__write(constant.SSD1306_SETCONTRAST, c)
  50. def display_off(self):
  51. self.__write(constant.SSD1306_DISPLAYOFF)
  52. def display_on(self):
  53. self.__write(constant.SSD1306_DISPLAYON)
  54. def display_clear(self, update=False):
  55. self.__buffer = [0] * self.__buff_size
  56. if update:
  57. self.display_update()
  58. def draw_px(self, x, y, clr=color.WHITE):
  59. pos = int(y / 8) * self.__width + x
  60. bm = (0x1 << (y % 8))
  61. bpos = self.__buffer[pos]
  62. self.__buffer[pos] = bpos | bm if clr == color.WHITE else bpos & (0xff ^ bm)
  63. def draw_line(self, x0, y0, x1, y1, clr=color.WHITE):
  64. if x0 == x1:
  65. self.__draw_v_line(x0, y0, abs(y1 - y0), clr)
  66. elif y0 == y1:
  67. self.__draw_h_line(x0, y0, abs(x1 - x0), clr)
  68. else:
  69. self.__draw_line(x0, y0, x1, y1, clr)
  70. def __draw_line(self, x0, y0, x1, y1, clr):
  71. steep = abs(y1 - y0) > abs(x1 - x0)
  72. if steep:
  73. x0, y0 = y0, x0
  74. x1, y1 = y1, x1
  75. if x0 > x1:
  76. x0, x1 = x1, x0
  77. y0, y1 = y1, y0
  78. dx = abs(x1 - x0)
  79. dy = abs(y1 - y0)
  80. err = dx / 2
  81. ystep = 1 if y0 < y1 else -1
  82. y = y0
  83. for x in range(x0, x1):
  84. if steep:
  85. self.draw_px(y, x, clr)
  86. else:
  87. self.draw_px(x, y, clr)
  88. err = err - dy
  89. if err < 0:
  90. y += ystep
  91. err += dx
  92. def __draw_v_line(self, x, y, h, clr):
  93. for y1 in range(y, y + h):
  94. self.draw_px(x, y1, clr)
  95. def __draw_h_line(self, x, y, w, clr):
  96. for x1 in range(x, x + w):
  97. self.draw_px(x1, y, clr)
  98. def __bresenham_plot(self, x, d1, y, d2, clr):
  99. self.draw_px(x + d1, y + d2)
  100. self.draw_px(x + d1, y - d2)
  101. self.draw_px(x - d1, y + d2)
  102. self.draw_px(x - d1, y - d2)
  103. self.draw_px(x + d2, y + d1)
  104. self.draw_px(x + d2, y - d1)
  105. self.draw_px(x - d2, y + d1)
  106. self.draw_px(x - d2, y - d1)
  107. def __bresenham_line(self, x, d1, y, d2, clr):
  108. self.__draw_v_line(x + d1, y - d2, 2 * d2, clr)
  109. self.__draw_v_line(x + d2, y - d1, 2 * d1, clr)
  110. self.__draw_v_line(x - d1, y - d2, 2 * d2, clr)
  111. self.__draw_v_line(x - d2, y - d1, 2 * d1, clr)
  112. def draw_circle(self, x0, y0, r, clr=color.WHITE):
  113. x = r
  114. y = 0
  115. err = 0
  116. while x >= y:
  117. self.__bresenham_plot(x0, x, y0, y, clr)
  118. if err <= 0:
  119. y += 1
  120. err += (2 * y) + 1
  121. else:
  122. x -= 1
  123. err -= (2 * x) + 1
  124. def draw_rect(self, x, y, w, h, clr=color.WHITE):
  125. self.__draw_h_line(x, y, w, clr)
  126. self.__draw_h_line(x, y + h, w, clr)
  127. self.__draw_v_line(x, y, h, clr)
  128. self.__draw_v_line(x + w, y, h, clr)
  129. def fill_circle(self, x0, y0, r, clr=color.WHITE):
  130. x = r
  131. y = 0
  132. err = 0
  133. while x >= y:
  134. self.__bresenham_line(x0, x, y0, y, clr)
  135. if err <= 0:
  136. y += 1
  137. err += (2 * y) + 1
  138. else:
  139. x -= 1
  140. err -= (2 * x) + 1
  141. def fill_rect(self, x, y, w, h, clr=color.WHITE):
  142. for i in range(x, x+w):
  143. self.__draw_v_line(i, y, h, clr)
  144. def fill_screen(self, clr=color.WHITE):
  145. self.fill_rect(0, 0, self.__width, self.__height, clr)
  146. def invert_colors(self):
  147. for i in range(0, len(self.__buffer)):
  148. self.__buffer[i] = ~self.__buffer[i]
  149. def draw_string(self, x, y, s, f=font.ASCII, clr=color.WHITE):
  150. mx = int(self.__width / (f['width'] + 1))
  151. my = int(self.__height / (f['height'] + 1))
  152. if x < 0 or (x + len(s)) > mx:
  153. raise ValueError("Out of X range")
  154. if y < 0 or y > my:
  155. raise ValueError("Out of Y range")
  156. pos = (self.__width) * y + ((f['width'] + 1) * x)
  157. for i in range(0, len(s)):
  158. c = 5 * (ord(s[i]) - 32)
  159. for p in range(0, f['width']):
  160. self.__buffer[pos + p] = f['value'][c + p]
  161. pos = pos + 6
  162. def display_text_mid_x(self, l, f=font.ASCII):
  163. mx = int(self.__width / (f['width'] + 1))
  164. return int((mx - l) / 2)
  165. def display_text_mid_y(self, f=font.ASCII):
  166. my = int(self.__height / (f['height'] + 1))
  167. return int(my / 2)
  168. def display_update(self):
  169. self.__write(constant.SSD1306_SETLOWCOLUMN)
  170. self.__write(constant.SSD1306_SETHIGHCOLUMN)
  171. self.__write(constant.SSD1306_SETSTARTLINE)
  172. line = [0] * 17
  173. line[0] = 0x40
  174. for i in range(0, len(self.__buffer), 16):
  175. for pos in range(0, 16):
  176. line[pos + 1] = self.__buffer[pos + i]
  177. self.__write(bytearray(line))