S&B Volcano vaporizer remote control with Pi Pico W
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lcd.py 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. # https://www.waveshare.com/wiki/Pico-LCD-1.3
  2. # https://thepihut.com/blogs/raspberry-pi-tutorials/coding-graphics-with-micropython-on-raspberry-pi-pico-displays
  3. # https://api.arcade.academy/en/latest/_modules/arcade/draw_commands.html#draw_arc_filled
  4. from machine import Pin, SPI, PWM
  5. from array import array
  6. import framebuf
  7. import time
  8. import os
  9. import math
  10. import gc
  11. class KeyCheck:
  12. def __init__(self, new, old):
  13. self.new = new
  14. self.old = old
  15. def once(self, k):
  16. return self.new[k] and not self.old[k]
  17. class LCD(framebuf.FrameBuffer):
  18. def __init__(self):
  19. self.pwm = PWM(Pin(13))
  20. self.pwm.freq(1000)
  21. self.brightness(0.0)
  22. self.width = 240
  23. self.height = 240
  24. self.cs = Pin(9, Pin.OUT)
  25. self.rst = Pin(12, Pin.OUT)
  26. self.cs(1)
  27. #self.spi = SPI(1)
  28. #self.spi = SPI(1, 1_000_000)
  29. self.spi = SPI(1, 100_000_000, polarity=0, phase=0, sck=Pin(10), mosi=Pin(11), miso=None)
  30. self.dc = Pin(8, Pin.OUT)
  31. self.dc(1)
  32. gc.collect()
  33. self.buffer = bytearray(self.height * self.width * 2)
  34. super().__init__(self.buffer, self.width, self.height, framebuf.RGB565)
  35. self.init_display()
  36. self.red = self.color(0xFF, 0x00, 0x00)
  37. self.green = self.color(0x00, 0xFF, 0x00)
  38. self.blue = self.color(0x00, 0x00, 0xFF)
  39. self.yellow = self.color(0xFF, 0xFF, 0x00)
  40. self.white = self.color(0xFF, 0xFF, 0xFF)
  41. self.black = self.color(0x00, 0x00, 0x00)
  42. self.fill(self.black)
  43. self.show()
  44. self.keyA = Pin(15, Pin.IN, Pin.PULL_UP)
  45. self.keyB = Pin(17, Pin.IN, Pin.PULL_UP)
  46. self.keyX = Pin(19, Pin.IN, Pin.PULL_UP)
  47. self.keyY = Pin(21, Pin.IN, Pin.PULL_UP)
  48. self.up = Pin( 2, Pin.IN, Pin.PULL_UP)
  49. self.down = Pin(18, Pin.IN, Pin.PULL_UP)
  50. self.left = Pin(16, Pin.IN, Pin.PULL_UP)
  51. self.right = Pin(20, Pin.IN, Pin.PULL_UP)
  52. self.ctrl = Pin( 3, Pin.IN, Pin.PULL_UP)
  53. self.keys_old = {
  54. "a": False,
  55. "b": False,
  56. "x": False,
  57. "y": False,
  58. "up": False,
  59. "down": False,
  60. "left": False,
  61. "right": False,
  62. "enter": False,
  63. }
  64. def buttons(self):
  65. keys = {
  66. "a": self.keyA.value() == 0,
  67. "b": self.keyB.value() == 0,
  68. "x": self.keyX.value() == 0,
  69. "y": self.keyY.value() == 0,
  70. "up": self.up.value() == 0,
  71. "down": self.down.value() == 0,
  72. "left": self.left.value() == 0,
  73. "right": self.right.value() == 0,
  74. "enter": self.ctrl.value() == 0,
  75. }
  76. kc = KeyCheck(keys, self.keys_old)
  77. self.keys_old = keys.copy()
  78. return kc
  79. # Convert RGB888 to RGB565
  80. def color(self, R, G, B):
  81. return (((G & 0b00011100) << 3) + ((B & 0b11111000) >> 3) << 8) + (R & 0b11111000) + ((G & 0b11100000) >> 5)
  82. def brightness(self, v):
  83. self.pwm.duty_u16(int(v * 65535))
  84. def write_cmd(self, cmd):
  85. self.cs(1)
  86. self.dc(0)
  87. self.cs(0)
  88. self.spi.write(bytearray([cmd]))
  89. self.cs(1)
  90. def write_data(self, buf):
  91. self.cs(1)
  92. self.dc(1)
  93. self.cs(0)
  94. self.spi.write(bytearray([buf]))
  95. self.cs(1)
  96. def init_display(self):
  97. self.rst(1)
  98. self.rst(0)
  99. self.rst(1)
  100. self.write_cmd(0x36)
  101. self.write_data(0x70)
  102. self.write_cmd(0x3A)
  103. self.write_data(0x05)
  104. self.write_cmd(0xB2)
  105. self.write_data(0x0C)
  106. self.write_data(0x0C)
  107. self.write_data(0x00)
  108. self.write_data(0x33)
  109. self.write_data(0x33)
  110. self.write_cmd(0xB7)
  111. self.write_data(0x35)
  112. self.write_cmd(0xBB)
  113. self.write_data(0x19)
  114. self.write_cmd(0xC0)
  115. self.write_data(0x2C)
  116. self.write_cmd(0xC2)
  117. self.write_data(0x01)
  118. self.write_cmd(0xC3)
  119. self.write_data(0x12)
  120. self.write_cmd(0xC4)
  121. self.write_data(0x20)
  122. self.write_cmd(0xC6)
  123. self.write_data(0x0F)
  124. self.write_cmd(0xD0)
  125. self.write_data(0xA4)
  126. self.write_data(0xA1)
  127. self.write_cmd(0xE0)
  128. self.write_data(0xD0)
  129. self.write_data(0x04)
  130. self.write_data(0x0D)
  131. self.write_data(0x11)
  132. self.write_data(0x13)
  133. self.write_data(0x2B)
  134. self.write_data(0x3F)
  135. self.write_data(0x54)
  136. self.write_data(0x4C)
  137. self.write_data(0x18)
  138. self.write_data(0x0D)
  139. self.write_data(0x0B)
  140. self.write_data(0x1F)
  141. self.write_data(0x23)
  142. self.write_cmd(0xE1)
  143. self.write_data(0xD0)
  144. self.write_data(0x04)
  145. self.write_data(0x0C)
  146. self.write_data(0x11)
  147. self.write_data(0x13)
  148. self.write_data(0x2C)
  149. self.write_data(0x3F)
  150. self.write_data(0x44)
  151. self.write_data(0x51)
  152. self.write_data(0x2F)
  153. self.write_data(0x1F)
  154. self.write_data(0x1F)
  155. self.write_data(0x20)
  156. self.write_data(0x23)
  157. self.write_cmd(0x21)
  158. self.write_cmd(0x11)
  159. self.write_cmd(0x29)
  160. def show(self):
  161. self.write_cmd(0x2A)
  162. self.write_data(0x00)
  163. self.write_data(0x00)
  164. self.write_data(0x00)
  165. self.write_data(0xef)
  166. self.write_cmd(0x2B)
  167. self.write_data(0x00)
  168. self.write_data(0x00)
  169. self.write_data(0x00)
  170. self.write_data(0xEF)
  171. self.write_cmd(0x2C)
  172. self.cs(1)
  173. self.dc(1)
  174. self.cs(0)
  175. self.spi.write(self.buffer)
  176. self.cs(1)
  177. def circle(self, x, y, r, c):
  178. self.hline(x-r,y,r*2,c)
  179. for i in range(1,r):
  180. a = int(math.sqrt(r*r-i*i)) # Pythagoras!
  181. self.hline(x-a,y+i,a*2,c) # Lower half
  182. self.hline(x-a,y-i,a*2,c) # Upper half
  183. def ring(self, x, y, r, c):
  184. self.pixel(x-r,y,c)
  185. self.pixel(x+r,y,c)
  186. self.pixel(x,y-r,c)
  187. self.pixel(x,y+r,c)
  188. for i in range(1, r):
  189. a = int(math.sqrt(r*r-i*i))
  190. self.pixel(x-a,y-i,c)
  191. self.pixel(x+a,y-i,c)
  192. self.pixel(x-a,y+i,c)
  193. self.pixel(x+a,y+i,c)
  194. self.pixel(x-i,y-a,c)
  195. self.pixel(x+i,y-a,c)
  196. self.pixel(x-i,y+a,c)
  197. self.pixel(x+i,y+a,c)
  198. def arc(self, x_off, y_off, w, h, c,
  199. start_angle, end_angle,
  200. filled = True,
  201. num_segments = 128):
  202. start_segment = int(start_angle / 360 * num_segments)
  203. end_segment = int(end_angle / 360 * num_segments)
  204. gc.collect()
  205. point_list = array('h')
  206. point_list.append(0)
  207. point_list.append(0)
  208. for segment in range(start_segment, end_segment + 1):
  209. theta = 2.0 * 3.1415926 * segment / num_segments
  210. x = w * math.cos(theta) / 2
  211. y = h * math.sin(theta) / 2
  212. i = (segment - start_segment + 1) * 2
  213. point_list.append(int(x))
  214. point_list.append(int(y))
  215. self.poly(int(x_off), int(y_off), point_list, c, True)
  216. def pie(self, x0, y0, w, c_border, c_circle, v):
  217. if v > 0.0:
  218. self.arc(int(x0), int(y0), int(w), int(w), c_circle, -90, int(v * 360) - 90)
  219. self.ring(int(x0), int(y0), int(w / 2), c_border)
  220. def textC(self, s, x, y, c, bgColor = None):
  221. xStart = x - int(len(s) * 8 / 2)
  222. yStart = y - 5
  223. if bgColor != None:
  224. self.rect(xStart, yStart - 1, len(s) * 8, 10, bgColor, True)
  225. self.text(s, xStart, yStart, c)
  226. def textLine(self, s, c, off = 0):
  227. charsPerLine = int(self.width / 8)
  228. lines = list(s[0+i:charsPerLine+i] for i in range(0, len(s), charsPerLine))
  229. n = 0
  230. for i, l in enumerate(lines):
  231. self.text(l, 0, (i + off) * 10, c)
  232. n += 1
  233. if i >= (self.height / 10):
  234. break
  235. return n
  236. def textBlock(self, s, c):
  237. lines = s.split("\n")
  238. off = 0
  239. for l in lines:
  240. off += self.textLine(l, c, off)