由于ESP8266片上资源有限,设计了 8266 专用精简驱动
# ili9341_min.py
from time import sleep
import ustruct as struct
# 仅保留最常用命令
_SWRESET = 0x01
_SLEEP_OUT = 0x11
_DISPLAY_ON = 0x29
_COLUMN_SET = 0x2A
_PAGE_SET = 0x2B
_MEMORY_WRITE = 0x2C
_MADCTL = 0x36
_PIXFMT = 0x3A
def color565(r, g, b):
return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3
class Display:
def __init__(self, spi, cs, dc, rst, w=240, h=320, rotation=90):#旋转90°,保持和竞赛样题显示方向一致
self.spi, self.cs, self.dc, self.rst = spi, cs, dc, rst
for p in (cs, dc, rst):
p.init(p.OUT, value=1)
self.w, self.h = w, h
self._madctl = [0x88, 0xE8, 0x48, 0x28][rotation // 90]
self._reset()
self._init9341()
def _reset(self):
self.rst(0)
sleep(0.05)
self.rst(1)
sleep(0.05)
def _write(self, dc_val, data=None):
self.dc(dc_val)
self.cs(0)
self.spi.write(data if data else b'')
self.cs(1)
def _init9341(self):
seq = (
(0xCF, b'\x00\xC1\x30'),
(0xED, b'\x64\x03\x12\x81'),
(0xE8, b'\x85\x00\x78'),
(0xCB, b'\x39\x2C\x00\x34\x02'),
(0xF7, b'\x20'),
(0xEA, b'\x00\x00'),
(0xC0, b'\x23'), # Power control
(0xC1, b'\x10'),
(0xC5, b'\x3E\x28'),
(0xC7, b'\x86'),
(_MADCTL, bytes([self._madctl])),
(0x3A, b'\x55'), # 16bit
(0xB1, b'\x00\x18'),
(0xB6, b'\x08\x82\x27'),
(0xF2, b'\x00'),
(0x26, b'\x01'),
(0xE0, b'\x0F\x31\x2B\x0C\x0E\x08\x4E\xF1\x37\x07\x10\x03\x0E\x09\x00'),
(0xE1, b'\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F'),
(_SLEEP_OUT, None),
(_DISPLAY_ON, None),
)
for cmd, dat in seq:
self._write(0, bytes([cmd]))
if dat:
self._write(1, dat)
sleep(0.01)
#self._write(0, b'\x36')
#self._write(1, b'\x08')
def set_window(self, x0, y0, x1, y1):
self._write(0, bytes([_COLUMN_SET]))
self._write(1, struct.pack('>HH', x0, x1))
self._write(0, bytes([_PAGE_SET]))
self._write(1, struct.pack('>HH', y0, y1))
self._write(0, bytes([_MEMORY_WRITE]))
def fill_rect(self, x0, y0, w, h, color):
x1 = min(x0 + w - 1, self.w - 1)
y1 = min(y0 + h - 1, self.h - 1)
if x0 < 0 or y0 < 0 or x0 >= self.w or y0 >= self.h:
return
self.set_window(x0, y0, x1, y1)
pixels = (x1 - x0 + 1) * (y1 - y0 + 1)
buf = color.to_bytes(2, 'big') * 256
for _ in range(pixels // 256):
self._write(1, buf)
rest = pixels % 256
if rest:
self._write(1, buf[:rest * 2])
def clear(self, color=0):
self.fill_rect(0, 0, self.w, self.h, color)
def pixel(self, x, y, color):
if 0 <= x < self.w and 0 <= y < self.h:
self.set_window(x, y, x, y)
self._write(1, color.to_bytes(2, 'big'))
#*******************************************
#以下是main.py文件
#*******************************************
font8x16 = (
# 0x20 ' ' ... 0x7E '~' 共 95 个
# 每个字符 16 字节,高位在前
# 为节省篇幅,这里只保留必要部分,其余用工具生成或从文末链接复制
# 下面给出 0x20-0x7E 的 **完整** 十六进制数据(已计数)
# 0x20
(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
# 0x21 '!'
(0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00),
# 0x22 '"'
(0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
# 0x23 '#'
(0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00),
# 0x24 '$'
(0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00),
# 0x25 '%'
(0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00),
# 0x26 '&'
(0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00),
# 0x27 '''
(0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
# 0x28 '('
(0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00),
# 0x29 ')'
(0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00),
# 0x2A '*'
(0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00),
# 0x2B '+'
(0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00),
# 0x2C ','
(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00),
# 0x2D '-'
(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
# 0x2E '.'
(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00),
# 0x2F '/'
(0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00),
# 数字 0-9
(0x00,0x00,0x7C,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00), # 0
(0x00,0x00,0x18,0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00), # 1
(0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00), # 2
(0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00), # 3
(0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00), # 4
(0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00), # 5
(0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00), # 6
(0x00,0x00,0xFE,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00), # 7
(0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00), # 8
(0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00), # 9
# 0x3A ':'
(0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00),
# 0x3B ';'
(0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00),
# 0x3C '<'
(0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00),
# 0x3D '='
(0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
# 0x3E '>'
(0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00),
# 0x3F '?'
(0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00),
# 0x40 '@'
(0x00,0x00,0x3C,0x66,0x6E,0x6E,0x6E,0x6E,0x60,0x62,0x66,0x3C,0x00,0x00,0x00,0x00),
# 大写字母 A-Z
(0x00,0x00,0x18,0x18,0x3C,0x66,0xC3,0xC3,0xFF,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00), # A
(0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00), # B
(0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00), # C
(0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00), # D
(0x00,0x00,0xFE,0xC6,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00), # E
(0x00,0x00,0xFE,0xC6,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00), # F
(0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xCE,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00), # G
(0x00,0x00,0xC3,0xC3,0xC3,0xC3,0xFF,0xC3,0xC3,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00), # H
(0x00,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00), # I
(0x00,0x00,0xFC,0x30,0x30,0x30,0x30,0x30,0x30,0x33,0x33,0x1E,0x00,0x00,0x00,0x00), # J
(0x00,0x00,0xC3,0xC6,0xCC,0xD8,0xF0,0xE0,0xF0,0xD8,0xCC,0xC6,0x00,0x00,0x00,0x00), # K
(0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00), # L
(0x00,0x00,0xC3,0xE7,0xFF,0xDB,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00), # M
(0x00,0x00,0xC3,0xC7,0xCF,0xDF,0xE3,0xF3,0xFB,0xE3,0xC3,0xC3,0x00,0x00,0x00,0x00), # N
(0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00), # O
(0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00), # P
(0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00), # Q
(0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00), # R
(0x00,0x00,0x7C,0xC6,0xC0,0x60,0x38,0x1C,0x0E,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00), # S
(0x00,0x00,0x7E,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00), # T
(0x00,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x7E,0x00,0x00,0x00,0x00), # U
(0x00,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x00,0x00,0x00,0x00), # V
(0x00,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xDB,0xDB,0xFF,0x66,0x66,0x00,0x00,0x00,0x00), # W
(0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00), # X
(0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00), # Y
(0x00,0x00,0xFE,0x06,0x0C,0x18,0x30,0x30,0x60,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00), # Z
# 0x5B '['
(0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00),
# 0x5C '\'
(0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00),
# 0x5D ']'
(0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00),
# 0x5E '^'
(0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
# 0x5F '_'
(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00),
# 0x60 '`'
(0x00,0x60,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
# 小写字母 a-z
(0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0x00,0x00,0x00,0x00), # a
(0x00,0x00,0xC0,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0xFC,0x00,0x00,0x00,0x00), # b
(0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00), # c
(0x00,0x00,0x06,0x06,0x06,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00), # d
(0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00), # e
(0x00,0x00,0x1C,0x36,0x32,0x30,0x78,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00), # f
(0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x06,0x06,0x7C,0x00), # g
(0x00,0x00,0xC0,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00), # h
(0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00), # i
(0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00), # j
(0x00,0x00,0xC0,0xC0,0xC0,0xC6,0xCC,0xD8,0xF0,0xD8,0xCC,0xC6,0x00,0x00,0x00,0x00), # k
(0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00), # l
(0x00,0x00,0x00,0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0xD6,0xD6,0x00,0x00,0x00,0x00), # m
(0x00,0x00,0x00,0x00,0x00,0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00), # n
(0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00), # o
(0x00,0x00,0x00,0x00,0x00,0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0xC0,0x00), # p
(0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x06,0x06,0x06,0x00), # q
(0x00,0x00,0x00,0x00,0x00,0xFC,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00), # r
(0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00), # s
(0x00,0x00,0x30,0x30,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0xFC,0x00,0x00,0x00,0x00), # t
(0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00), # u
(0x00,0x00,0x00,0x00,0x00,0xC3,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x00,0x00,0x00,0x00), # v
(0x00,0x00,0x00,0x00,0x00,0xC3,0xC3,0xC3,0xDB,0xDB,0xFF,0x66,0x00,0x00,0x00,0x00), # w
(0x00,0x00,0x00,0x00,0x00,0xC3,0x66,0x3C,0x18,0x3C,0x66,0xC3,0x00,0x00,0x00,0x00), # x
(0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x06,0x06,0xFC,0x00), # y
(0x00,0x00,0x00,0x00,0x00,0xFE,0x0C,0x18,0x30,0x60,0xC0,0xFE,0x00,0x00,0x00,0x00), # z
# 0x7B '{'
(0x00,0x0C,0x18,0x18,0x30,0x30,0x18,0x18,0x18,0x30,0x30,0x18,0x0C,0x00,0x00,0x00),
# 0x7C '|'
(0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00),
# 0x7D '}'
(0x00,0x30,0x0C,0x0C,0x06,0x06,0x0C,0x0C,0x0C,0x06,0x06,0x0C,0x30,0x00,0x00,0x00),
# 0x7E '~'
(0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00),
)
# 建立字典:ASCII 值 -> 字模
FONT = {chr(0x20 + i): font8x16[i] for i in range(min(95, len(font8x16)))}
##############################################################################
# 底层硬件驱动
##############################################################################
from machine import Pin, SPI
from ili9341_min import Display, color565
from time import sleep
import gc
spi = SPI(1, baudrate=20_000_000)
#sck=Pin(14), mosi=Pin(13), miso=Pin(12)) # 按实际引脚调整
lcd = Display(spi, cs=Pin(15), dc=Pin(2), rst=Pin(0))
BLACK = color565(0, 0, 0)
WHITE = color565(255, 255, 255)
##############################################################################
# 字符/字符串绘制(8×16)
##############################################################################
def draw_char(x, y, ch, color=WHITE, bg=BLACK):
"""画一个 8×16 字符(左上角 x,y)"""
if ord(ch) < 0x20 or ord(ch) > 0x7E:
ch = '?'
#c = ord(ch)
#if c >= 0x3A:
# c = c - 7 # 现在 c 是整数索引
#ch = chr(c)
bm = FONT[ch]
for row in range(16):
line = bm[row]
for col in range(8):
bit = (line >> (8-col)) & 1
lcd.pixel(x + col, y + row, color if bit else bg)
def draw_string(x, y, s, color=WHITE, bg=BLACK):
"""画字符串,8×16 等宽"""
for i, ch in enumerate(s):
draw_char(x + i * 8, y, ch, color, bg)
##############################################################################
# 传感器(伪)接口
##############################################################################
def read_temp() -> int:
return 25
def read_humidity() -> int:
return 60
def read_light() -> int:
return 480
##############################################################################
# 主循环:每秒刷新
##############################################################################
def main():
while True:
lcd.clear(BLACK)
draw_string(10, 10, f"Temp: {read_temp()} C")
draw_string(10, 30, f"Humidity: {read_humidity()} %")
draw_string(10, 50, f"Light: {read_light()} Lux")
gc.collect()
sleep(1)
if __name__ == "__main__":
main()
|