【Beetle 树莓派RP2350】屏幕显示
本帖最后由 FuShenxiao 于 2025-5-10 21:21 编辑本文将介绍基于IIC驱动0.91寸OLED屏幕和基于SPI驱动1.8寸TFT屏幕
OLED屏幕
根据绘制的扩展板原理图,可以看到GP26和GP27分别对应IIC的SDA和SCL引脚
查看0.91寸OLED屏幕发现其驱动芯片为SSD1306,因此编写驱动程序ssd1306.py如下
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
from micropython import const
import framebuf
# register definitions
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xA4)
SET_NORM_INV = const(0xA6)
SET_DISP = const(0xAE)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP = const(0xA0)
SET_MUX_RATIO = const(0xA8)
SET_COM_OUT_DIR = const(0xC0)
SET_DISP_OFFSET = const(0xD3)
SET_COM_PIN_CFG = const(0xDA)
SET_DISP_CLK_DIV = const(0xD5)
SET_PRECHARGE = const(0xD9)
SET_VCOM_DESEL = const(0xDB)
SET_CHARGE_PUMP = const(0x8D)
# Subclassing FrameBuffer provides support for graphics primitives
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
class SSD1306(framebuf.FrameBuffer):
def __init__(self, width, height, external_vcc):
self.width = width
self.height = height
self.external_vcc = external_vcc
self.pages = self.height // 8
self.buffer = bytearray(self.pages * self.width)
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
self.init_display()
def init_display(self):
for cmd in (
SET_DISP | 0x00,# off
# address setting
SET_MEM_ADDR,
0x00,# horizontal
# resolution and layout
SET_DISP_START_LINE | 0x00,
SET_SEG_REMAP | 0x01,# column addr 127 mapped to SEG0
SET_MUX_RATIO,
self.height - 1,
SET_COM_OUT_DIR | 0x08,# scan from COM to COM0
SET_DISP_OFFSET,
0x00,
SET_COM_PIN_CFG,
0x02 if self.width > 2 * self.height else 0x12,
# timing and driving scheme
SET_DISP_CLK_DIV,
0x80,
SET_PRECHARGE,
0x22 if self.external_vcc else 0xF1,
SET_VCOM_DESEL,
0x30,# 0.83*Vcc
# display
SET_CONTRAST,
0xFF,# maximum
SET_ENTIRE_ON,# output follows RAM contents
SET_NORM_INV,# not inverted
# charge pump
SET_CHARGE_PUMP,
0x10 if self.external_vcc else 0x14,
SET_DISP | 0x01,
):# on
self.write_cmd(cmd)
self.fill(0)
self.show()
def poweroff(self):
self.write_cmd(SET_DISP | 0x00)
def poweron(self):
self.write_cmd(SET_DISP | 0x01)
def contrast(self, contrast):
self.write_cmd(SET_CONTRAST)
self.write_cmd(contrast)
def invert(self, invert):
self.write_cmd(SET_NORM_INV | (invert & 1))
def show(self):
x0 = 0
x1 = self.width - 1
if self.width == 64:
# displays with width of 64 pixels are shifted by 32
x0 += 32
x1 += 32
self.write_cmd(SET_COL_ADDR)
self.write_cmd(x0)
self.write_cmd(x1)
self.write_cmd(SET_PAGE_ADDR)
self.write_cmd(0)
self.write_cmd(self.pages - 1)
self.write_data(self.buffer)
class SSD1306_I2C(SSD1306):
def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False):
self.i2c = i2c
self.addr = addr
self.temp = bytearray(2)
self.write_list = # Co=0, D/C#=1
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.temp = 0x80# Co=1, D/C#=0
self.temp = cmd
self.i2c.writeto(self.addr, self.temp)
def write_data(self, buf):
self.write_list = buf
self.i2c.writevto(self.addr, self.write_list)
class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
self.rate = 10 * 1024 * 1024
dc.init(dc.OUT, value=0)
res.init(res.OUT, value=0)
cs.init(cs.OUT, value=1)
self.spi = spi
self.dc = dc
self.res = res
self.cs = cs
import time
self.res(1)
time.sleep_ms(1)
self.res(0)
time.sleep_ms(10)
self.res(1)
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(0)
self.cs(0)
self.spi.write(bytearray())
self.cs(1)
def write_data(self, buf):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(1)
self.cs(0)
self.spi.write(buf)
self.cs(1)
查看数据手册发现SDA和SCL两个引脚属于I2C1
编写显示主程序如下
在主程序中,我完成的显示内容包括:I2C初始化 -> OLED屏幕初始化 -> 显示文本 -> 显示图形 -> 滚动显示文本
from machine import Pin, I2C
import ssd1306
import time
# I2C初始化
i2c = I2C(1, scl=Pin(27), sda=Pin(26), freq=400000)
# OLED初始化 (根据你的屏幕尺寸调整)
# 对于128x32屏幕:
oled = ssd1306.SSD1306_I2C(128, 32, i2c)
# 对于128x64屏幕:
# oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# 清除屏幕
oled.fill(0)
oled.show()
# 显示文本
oled.text("Hello RP2350!", 0, 0)
oled.text("MicroPython", 0, 10)
oled.text("OLED Test", 0, 20)
oled.show()
# 显示图形
def draw_square():
for y in range(20, 30):
for x in range(80, 100):
oled.pixel(x, y, 1)
oled.show()
draw_square()
time.sleep(5)
# 滚动文本示例
for i in range(0, 128):
oled.fill(0)
oled.text("Scrolling text", 128-i, 10)
oled.show()
time.sleep(0.02)
显示效果如下
工程文件如下TFT屏幕
根据绘制的扩展板原理图,可以看到GP19和GP18分别对应SPI的SDA和SCL引脚,GP16为CS引脚,GP26为DC引脚,GP27为RES引脚,BL引脚默认接高电平,即背光打开
屏幕的驱动芯片为ST7735,编写驱动程序ST7735.py如下
#driver for Sainsmart 1.8" TFT display ST7735
#Translated by Guy Carver from the ST7735 sample code.
#Modirfied for micropython-esp32 by boochow
import machine
import time
from math import sqrt
#TFTRotations and TFTRGB are bits to set
# on MADCTL to control display rotation/color layout
#Looking at display with pins on top.
#00 = upper left printing right
#10 = does nothing (MADCTL_ML)
#20 = upper left printing down (backwards) (Vertical flip)
#40 = upper right printing left (backwards) (X Flip)
#80 = lower left printing right (backwards) (Y Flip)
#04 = (MADCTL_MH)
#60 = 90 right rotation
#C0 = 180 right rotation
#A0 = 270 right rotation
TFTRotations =
TFTBGR = 0x08 #When set color is bgr else rgb.
TFTRGB = 0x00
#@micropython.native
def clamp( aValue, aMin, aMax ) :
return max(aMin, min(aMax, aValue))
#@micropython.native
def TFTColor( aR, aG, aB ) :
'''Create a 16 bit rgb value from the given R,G,B from 0-255.
This assumes rgb 565 layout and will be incorrect for bgr.'''
return ((aR & 0xF8) << 8) | ((aG & 0xFC) << 3) | (aB >> 3)
ScreenSize = (128, 160)
class TFT(object) :
"""Sainsmart TFT 7735 display driver."""
NOP = 0x0
SWRESET = 0x01
RDDID = 0x04
RDDST = 0x09
SLPIN= 0x10
SLPOUT= 0x11
PTLON= 0x12
NORON= 0x13
INVOFF = 0x20
INVON = 0x21
DISPOFF = 0x28
DISPON = 0x29
CASET = 0x2A
RASET = 0x2B
RAMWR = 0x2C
RAMRD = 0x2E
VSCRDEF = 0x33
VSCSAD = 0x37
COLMOD = 0x3A
MADCTL = 0x36
FRMCTR1 = 0xB1
FRMCTR2 = 0xB2
FRMCTR3 = 0xB3
INVCTR = 0xB4
DISSET5 = 0xB6
PWCTR1 = 0xC0
PWCTR2 = 0xC1
PWCTR3 = 0xC2
PWCTR4 = 0xC3
PWCTR5 = 0xC4
VMCTR1 = 0xC5
RDID1 = 0xDA
RDID2 = 0xDB
RDID3 = 0xDC
RDID4 = 0xDD
PWCTR6 = 0xFC
GMCTRP1 = 0xE0
GMCTRN1 = 0xE1
BLACK = 0
RED = TFTColor(0xFF, 0x00, 0x00)
MAROON = TFTColor(0x80, 0x00, 0x00)
GREEN = TFTColor(0x00, 0xFF, 0x00)
FOREST = TFTColor(0x00, 0x80, 0x80)
BLUE = TFTColor(0x00, 0x00, 0xFF)
NAVY = TFTColor(0x00, 0x00, 0x80)
CYAN = TFTColor(0x00, 0xFF, 0xFF)
YELLOW = TFTColor(0xFF, 0xFF, 0x00)
PURPLE = TFTColor(0xFF, 0x00, 0xFF)
WHITE = TFTColor(0xFF, 0xFF, 0xFF)
GRAY = TFTColor(0x80, 0x80, 0x80)
@staticmethod
def color( aR, aG, aB ) :
'''Create a 565 rgb TFTColor value'''
return TFTColor(aR, aG, aB)
def __init__( self, spi, aDC, aReset, aCS ) :
"""aLoc SPI pin location is either 1 for 'X' or 2 for 'Y'.
aDC is the DC pin and aReset is the reset pin."""
self._size = ScreenSize
self._offset = bytearray()
self.rotate = 0 #Vertical with top toward pins.
self._rgb = True #color order of rgb.
self.tfa = 0 #top fixed area
self.bfa = 0 #bottom fixed area
self.dc= machine.Pin(aDC, machine.Pin.OUT, machine.Pin.PULL_DOWN)
self.reset = machine.Pin(aReset, machine.Pin.OUT, machine.Pin.PULL_DOWN)
self.cs = machine.Pin(aCS, machine.Pin.OUT, machine.Pin.PULL_DOWN)
self.cs(1)
self.spi = spi
self.colorData = bytearray(2)
self.windowLocData = bytearray(4)
def size( self, newSize = ScreenSize ) :
if (newSize != ScreenSize):
self._size = newSize
return self._size
# @micropython.native
def on( self, aTF = True ) :
'''Turn display on or off.'''
self._writecommand(TFT.DISPON if aTF else TFT.DISPOFF)
# @micropython.native
def invertcolor( self, aBool ) :
'''Invert the color data IE: Black = White.'''
self._writecommand(TFT.INVON if aBool else TFT.INVOFF)
# @micropython.native
def rgb( self, aTF = True ) :
'''True = rgb else bgr'''
self._rgb = aTF
self._setMADCTL()
# @micropython.native
def rotation( self, aRot ) :
'''0 - 3. Starts vertical with top toward pins and rotates 90 deg
clockwise each step.'''
if (0 <= aRot < 4):
rotchange = self.rotate ^ aRot
self.rotate = aRot
#If switching from vertical to horizontal swap x,y
# (indicated by bit 0 changing).
if (rotchange & 1):
self._size =(self._size, self._size)
self._setMADCTL()
#@micropython.native
def pixel( self, aPos, aColor ) :
'''Draw a pixel at the given position'''
if 0 <= aPos < self._size and 0 <= aPos < self._size:
self._setwindowpoint(aPos)
self._pushcolor(aColor)
# @micropython.native
def text( self, aPos, aString, aColor, aFont, aSize = 1, nowrap = False ) :
'''Draw a text at the given position.If the string reaches the end of the
display it is wrapped to aPos on the next line.aSize may be an integer
which will size the font uniformly on w,h or a or any type that may be
indexed with or .'''
if aFont == None:
return
#Make a size either from single value or 2 elements.
if (type(aSize) == int) or (type(aSize) == float):
wh = (aSize, aSize)
else:
wh = aSize
px, py = aPos
width = wh * aFont["Width"] + 1
for c in aString:
self.char((px, py), c, aColor, aFont, wh)
px += width
#We check > rather than >= to let the right (blank) edge of the
# character print off the right of the screen.
if px + width > self._size:
if nowrap:
break
else:
py += aFont["Height"] * wh + 1
px = aPos
# @micropython.native
def char( self, aPos, aChar, aColor, aFont, aSizes ) :
'''Draw a character at the given position using the given font and color.
aSizes is a tuple with x, y as integer scales indicating the
# of pixels to draw for each pixel in the character.'''
if aFont == None:
return
startchar = aFont['Start']
endchar = aFont['End']
ci = ord(aChar)
if (startchar <= ci <= endchar):
fontw = aFont['Width']
fonth = aFont['Height']
ci = (ci - startchar) * fontw
charA = aFont["Data"]
px = aPos
if aSizes <= 1 and aSizes <= 1 :
buf = bytearray(2 * fonth * fontw)
for q in range(fontw) :
c = charA
for r in range(fonth) :
if c & 0x01 :
pos = 2 * (r * fontw + q)
buf = aColor >> 8
buf = aColor & 0xff
c >>= 1
self.image(aPos, aPos, aPos + fontw - 1, aPos + fonth - 1, buf)
else:
for c in charA :
py = aPos
for r in range(fonth) :
if c & 0x01 :
self.fillrect((px, py), aSizes, aColor)
py += aSizes
c >>= 1
px += aSizes
# @micropython.native
def line( self, aStart, aEnd, aColor ) :
'''Draws a line from aStart to aEnd in the given color.Vertical or horizontal
lines are forwarded to vline and hline.'''
if aStart == aEnd:
#Make sure we use the smallest y.
pnt = aEnd if (aEnd < aStart) else aStart
self.vline(pnt, abs(aEnd - aStart) + 1, aColor)
elif aStart == aEnd:
#Make sure we use the smallest x.
pnt = aEnd if aEnd < aStart else aStart
self.hline(pnt, abs(aEnd - aStart) + 1, aColor)
else:
px, py = aStart
ex, ey = aEnd
dx = ex - px
dy = ey - py
inx = 1 if dx > 0 else -1
iny = 1 if dy > 0 else -1
dx = abs(dx)
dy = abs(dy)
if (dx >= dy):
dy <<= 1
e = dy - dx
dx <<= 1
while (px != ex):
self.pixel((px, py), aColor)
if (e >= 0):
py += iny
e -= dx
e += dy
px += inx
else:
dx <<= 1
e = dx - dy
dy <<= 1
while (py != ey):
self.pixel((px, py), aColor)
if (e >= 0):
px += inx
e -= dy
e += dx
py += iny
# @micropython.native
def vline( self, aStart, aLen, aColor ) :
'''Draw a vertical line from aStart for aLen. aLen may be negative.'''
start = (clamp(aStart, 0, self._size), clamp(aStart, 0, self._size))
stop = (start, clamp(start + aLen, 0, self._size))
#Make sure smallest y 1st.
if (stop < start):
start, stop = stop, start
self._setwindowloc(start, stop)
self._setColor(aColor)
self._draw(aLen)
# @micropython.native
def hline( self, aStart, aLen, aColor ) :
'''Draw a horizontal line from aStart for aLen. aLen may be negative.'''
start = (clamp(aStart, 0, self._size), clamp(aStart, 0, self._size))
stop = (clamp(start + aLen, 0, self._size), start)
#Make sure smallest x 1st.
if (stop < start):
start, stop = stop, start
self._setwindowloc(start, stop)
self._setColor(aColor)
self._draw(aLen)
# @micropython.native
def rect( self, aStart, aSize, aColor ) :
'''Draw a hollow rectangle.aStart is the smallest coordinate corner
and aSize is a tuple indicating width, height.'''
self.hline(aStart, aSize, aColor)
self.hline((aStart, aStart + aSize - 1), aSize, aColor)
self.vline(aStart, aSize, aColor)
self.vline((aStart + aSize - 1, aStart), aSize, aColor)
# @micropython.native
def fillrect( self, aStart, aSize, aColor ) :
'''Draw a filled rectangle.aStart is the smallest coordinate corner
and aSize is a tuple indicating width, height.'''
start = (clamp(aStart, 0, self._size), clamp(aStart, 0, self._size))
end = (clamp(start + aSize - 1, 0, self._size), clamp(start + aSize - 1, 0, self._size))
if (end < start):
tmp = end
end = (start, end)
start = (tmp, start)
if (end < start):
tmp = end
end = (end, start)
start = (start, tmp)
self._setwindowloc(start, end)
numPixels = (end - start + 1) * (end - start + 1)
self._setColor(aColor)
self._draw(numPixels)
# @micropython.native
def circle( self, aPos, aRadius, aColor ) :
'''Draw a hollow circle with the given radius and color with aPos as center.'''
self.colorData = aColor >> 8
self.colorData = aColor
xend = int(0.7071 * aRadius) + 1
rsq = aRadius * aRadius
for x in range(xend) :
y = int(sqrt(rsq - x * x))
xp = aPos + x
yp = aPos + y
xn = aPos - x
yn = aPos - y
xyp = aPos + y
yxp = aPos + x
xyn = aPos - y
yxn = aPos - x
self._setwindowpoint((xp, yp))
self._writedata(self.colorData)
self._setwindowpoint((xp, yn))
self._writedata(self.colorData)
self._setwindowpoint((xn, yp))
self._writedata(self.colorData)
self._setwindowpoint((xn, yn))
self._writedata(self.colorData)
self._setwindowpoint((xyp, yxp))
self._writedata(self.colorData)
self._setwindowpoint((xyp, yxn))
self._writedata(self.colorData)
self._setwindowpoint((xyn, yxp))
self._writedata(self.colorData)
self._setwindowpoint((xyn, yxn))
self._writedata(self.colorData)
# @micropython.native
def fillcircle( self, aPos, aRadius, aColor ) :
'''Draw a filled circle with given radius and color with aPos as center'''
rsq = aRadius * aRadius
for x in range(aRadius) :
y = int(sqrt(rsq - x * x))
y0 = aPos - y
ey = y0 + y * 2
y0 = clamp(y0, 0, self._size)
ln = abs(ey - y0) + 1;
self.vline((aPos + x, y0), ln, aColor)
self.vline((aPos - x, y0), ln, aColor)
def fill( self, aColor = BLACK ) :
'''Fill screen with the given color.'''
self.fillrect((0, 0), self._size, aColor)
def image( self, x0, y0, x1, y1, data ) :
self._setwindowloc((x0, y0), (x1, y1))
self._writedata(data)
def setvscroll(self, tfa, bfa) :
''' set vertical scroll area '''
self._writecommand(TFT.VSCRDEF)
data2 = bytearray()
self._writedata(data2)
data2 = 162 - tfa - bfa
self._writedata(data2)
data2 = bfa
self._writedata(data2)
self.tfa = tfa
self.bfa = bfa
def vscroll(self, value) :
a = value + self.tfa
if (a + self.bfa > 162) :
a = 162 - self.bfa
self._vscrolladdr(a)
def _vscrolladdr(self, addr) :
self._writecommand(TFT.VSCSAD)
data2 = bytearray()
self._writedata(data2)
# @micropython.native
def _setColor( self, aColor ) :
self.colorData = aColor >> 8
self.colorData = aColor
self.buf = bytes(self.colorData) * 32
# @micropython.native
def _draw( self, aPixels ) :
'''Send given color to the device aPixels times.'''
self.dc(1)
self.cs(0)
for i in range(aPixels//32):
self.spi.write(self.buf)
rest = (int(aPixels) % 32)
if rest > 0:
buf2 = bytes(self.colorData) * rest
self.spi.write(buf2)
self.cs(1)
# @micropython.native
def _setwindowpoint( self, aPos ) :
'''Set a single point for drawing a color to.'''
x = self._offset + int(aPos)
y = self._offset + int(aPos)
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData = self._offset
self.windowLocData = x
self.windowLocData = self._offset
self.windowLocData = x
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData = self._offset
self.windowLocData = y
self.windowLocData = self._offset
self.windowLocData = y
self._writedata(self.windowLocData)
self._writecommand(TFT.RAMWR) #Write to RAM.
# @micropython.native
def _setwindowloc( self, aPos0, aPos1 ) :
'''Set a rectangular area for drawing a color to.'''
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData = self._offset
self.windowLocData = self._offset + int(aPos0)
self.windowLocData = self._offset
self.windowLocData = self._offset + int(aPos1)
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData = self._offset
self.windowLocData = self._offset + int(aPos0)
self.windowLocData = self._offset
self.windowLocData = self._offset + int(aPos1)
self._writedata(self.windowLocData)
self._writecommand(TFT.RAMWR) #Write to RAM.
#@micropython.native
def _writecommand( self, aCommand ) :
'''Write given command to the device.'''
self.dc(0)
self.cs(0)
self.spi.write(bytearray())
self.cs(1)
#@micropython.native
def _writedata( self, aData ) :
'''Write given data to the device.This may be
either a single int or a bytearray of values.'''
self.dc(1)
self.cs(0)
self.spi.write(aData)
self.cs(1)
#@micropython.native
def _pushcolor( self, aColor ) :
'''Push given color to the device.'''
self.colorData = aColor >> 8
self.colorData = aColor
self._writedata(self.colorData)
#@micropython.native
def _setMADCTL( self ) :
'''Set screen rotation and RGB/BGR format.'''
self._writecommand(TFT.MADCTL)
rgb = TFTRGB if self._rgb else TFTBGR
self._writedata(bytearray( | rgb]))
#@micropython.native
def _reset( self ) :
'''Reset the device.'''
self.dc(0)
self.reset(1)
time.sleep_us(500)
self.reset(0)
time.sleep_us(500)
self.reset(1)
time.sleep_us(500)
def initb( self ) :
'''Initialize blue tab version.'''
self._size = (ScreenSize + 2, ScreenSize + 1)
self._reset()
self._writecommand(TFT.SWRESET) #Software reset.
time.sleep_us(50)
self._writecommand(TFT.SLPOUT) #out of sleep mode.
time.sleep_us(500)
data1 = bytearray(1)
self._writecommand(TFT.COLMOD) #Set color mode.
data1 = 0x05 #16 bit color.
self._writedata(data1)
time.sleep_us(10)
data3 = bytearray() #fastest refresh, 6 lines front, 3 lines back.
self._writecommand(TFT.FRMCTR1) #Frame rate control.
self._writedata(data3)
time.sleep_us(10)
self._writecommand(TFT.MADCTL)
data1 = 0x08 #row address/col address, bottom to top refresh
self._writedata(data1)
data2 = bytearray(2)
self._writecommand(TFT.DISSET5) #Display settings
data2 = 0x15 #1 clock cycle nonoverlap, 2 cycle gate rise, 3 cycle oscil, equalize
data2 = 0x02 #fix on VTL
self._writedata(data2)
self._writecommand(TFT.INVCTR) #Display inversion control
data1 = 0x00 #Line inversion.
self._writedata(data1)
self._writecommand(TFT.PWCTR1) #Power control
data2 = 0x02 #GVDD = 4.7V
data2 = 0x70 #1.0uA
self._writedata(data2)
time.sleep_us(10)
self._writecommand(TFT.PWCTR2) #Power control
data1 = 0x05 #VGH = 14.7V, VGL = -7.35V
self._writedata(data1)
self._writecommand(TFT.PWCTR3) #Power control
data2 = 0x01 #Opamp current small
data2 = 0x02 #Boost frequency
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
data2 = 0x3C #VCOMH = 4V
data2 = 0x38 #VCOML = -1.1V
self._writedata(data2)
time.sleep_us(10)
self._writecommand(TFT.PWCTR6) #Power control
data2 = 0x11
data2 = 0x15
self._writedata(data2)
#These different values don't seem to make a difference.
# dataGMCTRP = bytearray([0x0f, 0x1a, 0x0f, 0x18, 0x2f, 0x28, 0x20, 0x22, 0x1f,
# 0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10])
dataGMCTRP = bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29,
0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10])
self._writecommand(TFT.GMCTRP1)
self._writedata(dataGMCTRP)
# dataGMCTRN = bytearray([0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e, 0x30,
# 0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10])
dataGMCTRN = bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e,
0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10])
self._writecommand(TFT.GMCTRN1)
self._writedata(dataGMCTRN)
time.sleep_us(10)
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData = 0x00
self.windowLocData = 2 #Start at column 2
self.windowLocData = 0x00
self.windowLocData = self._size - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData = 1 #Start at row 2.
self.windowLocData = self._size - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.NORON) #Normal display on.
time.sleep_us(10)
self._writecommand(TFT.RAMWR)
time.sleep_us(500)
self._writecommand(TFT.DISPON)
self.cs(1)
time.sleep_us(500)
def initr( self ) :
'''Initialize a red tab version.'''
self._reset()
self._writecommand(TFT.SWRESET) #Software reset.
time.sleep_us(150)
self._writecommand(TFT.SLPOUT) #out of sleep mode.
time.sleep_us(500)
data3 = bytearray() #fastest refresh, 6 lines front, 3 lines back.
self._writecommand(TFT.FRMCTR1) #Frame rate control.
self._writedata(data3)
self._writecommand(TFT.FRMCTR2) #Frame rate control.
self._writedata(data3)
data6 = bytearray()
self._writecommand(TFT.FRMCTR3) #Frame rate control.
self._writedata(data6)
time.sleep_us(10)
data1 = bytearray(1)
self._writecommand(TFT.INVCTR) #Display inversion control
data1 = 0x07 #Line inversion.
self._writedata(data1)
self._writecommand(TFT.PWCTR1) #Power control
data3 = 0xA2
data3 = 0x02
data3 = 0x84
self._writedata(data3)
self._writecommand(TFT.PWCTR2) #Power control
data1 = 0xC5 #VGH = 14.7V, VGL = -7.35V
self._writedata(data1)
data2 = bytearray(2)
self._writecommand(TFT.PWCTR3) #Power control
data2 = 0x0A #Opamp current small
data2 = 0x00 #Boost frequency
self._writedata(data2)
self._writecommand(TFT.PWCTR4) #Power control
data2 = 0x8A #Opamp current small
data2 = 0x2A #Boost frequency
self._writedata(data2)
self._writecommand(TFT.PWCTR5) #Power control
data2 = 0x8A #Opamp current small
data2 = 0xEE #Boost frequency
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
data1 = 0x0E
self._writedata(data1)
self._writecommand(TFT.INVOFF)
self._writecommand(TFT.MADCTL) #Power control
data1 = 0xC8
self._writedata(data1)
self._writecommand(TFT.COLMOD)
data1 = 0x05
self._writedata(data1)
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData = 0x00
self.windowLocData = 0x00
self.windowLocData = 0x00
self.windowLocData = self._size - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData = self._size - 1
self._writedata(self.windowLocData)
dataGMCTRP = bytearray([0x0f, 0x1a, 0x0f, 0x18, 0x2f, 0x28, 0x20, 0x22, 0x1f,
0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10])
self._writecommand(TFT.GMCTRP1)
self._writedata(dataGMCTRP)
dataGMCTRN = bytearray([0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e, 0x30,
0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10])
self._writecommand(TFT.GMCTRN1)
self._writedata(dataGMCTRN)
time.sleep_us(10)
self._writecommand(TFT.DISPON)
time.sleep_us(100)
self._writecommand(TFT.NORON) #Normal display on.
time.sleep_us(10)
self.cs(1)
def initb2( self ) :
'''Initialize another blue tab version.'''
self._size = (ScreenSize + 2, ScreenSize + 1)
self._offset = 2
self._offset = 1
self._reset()
self._writecommand(TFT.SWRESET) #Software reset.
time.sleep_us(50)
self._writecommand(TFT.SLPOUT) #out of sleep mode.
time.sleep_us(500)
data3 = bytearray() #
self._writecommand(TFT.FRMCTR1) #Frame rate control.
self._writedata(data3)
time.sleep_us(10)
self._writecommand(TFT.FRMCTR2) #Frame rate control.
self._writedata(data3)
time.sleep_us(10)
self._writecommand(TFT.FRMCTR3) #Frame rate control.
self._writedata(data3)
time.sleep_us(10)
self._writecommand(TFT.INVCTR) #Display inversion control
data1 = bytearray(1) #
data1 = 0x07
self._writedata(data1)
self._writecommand(TFT.PWCTR1) #Power control
data3 = 0xA2 #
data3 = 0x02 #
data3 = 0x84 #
self._writedata(data3)
time.sleep_us(10)
self._writecommand(TFT.PWCTR2) #Power control
data1 = 0xC5 #
self._writedata(data1)
self._writecommand(TFT.PWCTR3) #Power control
data2 = bytearray(2)
data2 = 0x0A #
data2 = 0x00 #
self._writedata(data2)
self._writecommand(TFT.PWCTR4) #Power control
data2 = 0x8A #
data2 = 0x2A #
self._writedata(data2)
self._writecommand(TFT.PWCTR5) #Power control
data2 = 0x8A #
data2 = 0xEE #
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
data1 = 0x0E #
self._writedata(data1)
time.sleep_us(10)
self._writecommand(TFT.MADCTL)
data1 = 0xC8 #row address/col address, bottom to top refresh
self._writedata(data1)
#These different values don't seem to make a difference.
# dataGMCTRP = bytearray([0x0f, 0x1a, 0x0f, 0x18, 0x2f, 0x28, 0x20, 0x22, 0x1f,
# 0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10])
dataGMCTRP = bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29,
0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10])
self._writecommand(TFT.GMCTRP1)
self._writedata(dataGMCTRP)
# dataGMCTRN = bytearray([0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e, 0x30,
# 0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10])
dataGMCTRN = bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e,
0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10])
self._writecommand(TFT.GMCTRN1)
self._writedata(dataGMCTRN)
time.sleep_us(10)
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData = 0x00
self.windowLocData = 0x02 #Start at column 2
self.windowLocData = 0x00
self.windowLocData = self._size - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData = 0x01 #Start at row 2.
self.windowLocData = self._size - 1
self._writedata(self.windowLocData)
data1 = bytearray(1)
self._writecommand(TFT.COLMOD) #Set color mode.
data1 = 0x05 #16 bit color.
self._writedata(data1)
time.sleep_us(10)
self._writecommand(TFT.NORON) #Normal display on.
time.sleep_us(10)
self._writecommand(TFT.RAMWR)
time.sleep_us(500)
self._writecommand(TFT.DISPON)
self.cs(1)
time.sleep_us(500)
#@micropython.native
def initg( self ) :
'''Initialize a green tab version.'''
self._reset()
self._writecommand(TFT.SWRESET) #Software reset.
time.sleep_us(150)
self._writecommand(TFT.SLPOUT) #out of sleep mode.
time.sleep_us(255)
data3 = bytearray() #fastest refresh, 6 lines front, 3 lines back.
self._writecommand(TFT.FRMCTR1) #Frame rate control.
self._writedata(data3)
self._writecommand(TFT.FRMCTR2) #Frame rate control.
self._writedata(data3)
data6 = bytearray()
self._writecommand(TFT.FRMCTR3) #Frame rate control.
self._writedata(data6)
time.sleep_us(10)
self._writecommand(TFT.INVCTR) #Display inversion control
self._writedata(bytearray())
self._writecommand(TFT.PWCTR1) #Power control
data3 = 0xA2
data3 = 0x02
data3 = 0x84
self._writedata(data3)
self._writecommand(TFT.PWCTR2) #Power control
self._writedata(bytearray())
data2 = bytearray(2)
self._writecommand(TFT.PWCTR3) #Power control
data2 = 0x0A #Opamp current small
data2 = 0x00 #Boost frequency
self._writedata(data2)
self._writecommand(TFT.PWCTR4) #Power control
data2 = 0x8A #Opamp current small
data2 = 0x2A #Boost frequency
self._writedata(data2)
self._writecommand(TFT.PWCTR5) #Power control
data2 = 0x8A #Opamp current small
data2 = 0xEE #Boost frequency
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
self._writedata(bytearray())
self._writecommand(TFT.INVOFF)
self._setMADCTL()
self._writecommand(TFT.COLMOD)
self._writedata(bytearray())
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData = 0x00
self.windowLocData = 0x01 #Start at row/column 1.
self.windowLocData = 0x00
self.windowLocData = self._size - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData = self._size - 1
self._writedata(self.windowLocData)
dataGMCTRP = bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29,
0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10])
self._writecommand(TFT.GMCTRP1)
self._writedata(dataGMCTRP)
dataGMCTRN = bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e,
0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10])
self._writecommand(TFT.GMCTRN1)
self._writedata(dataGMCTRN)
self._writecommand(TFT.NORON) #Normal display on.
time.sleep_us(10)
self._writecommand(TFT.DISPON)
time.sleep_us(100)
self.cs(1)
#def maker() :
#t = TFT(1, "X1", "X2")
#print("Initializing")
#t.initr()
#t.fill(0)
#return t
#def makeb() :
#t = TFT(1, "X1", "X2")
#print("Initializing")
#t.initb()
#t.fill(0)
#return t
#def makeg() :
#t = TFT(1, "X1", "X2")
#print("Initializing")
#t.initg()
#t.fill(0)
#return t
接着编写相关字符文件,由于文件太长,这里不再赘述,详细可以参见工程文件
查看数据手册发现两个引脚属于SPI0
编写显示主程序如下
在主程序中,我完成的显示内容包括:SPI初始化 -> TFT屏幕初始化 -> 执行显示任务 -> 输出帧率
from machine import UART,SPI,Pin
from ST7735 import TFT
from font import sysfont, seriffont, terminalfont
import time
import math
# Fiz pra testar 2 displays com o mesmo script pq sim.
display085 = False
TFT_CLK = const(18)
TFT_MOSI =const(19)
TFT_DC = const(26)
TFT_RST = const(27)
TFT_CS = const(16)
# 20 Mhz = 20_000_000 (default), 51_200_000, 80_000_000
spi = SPI(0, baudrate=80_000_000, polarity=0, phase=0, bits=8, sck=Pin(TFT_CLK), mosi=Pin(TFT_MOSI), miso=None)
tft = TFT(spi, TFT_DC, TFT_RST, TFT_CS)
# Na vdd, no Aliexpress dizia que o display 0.85' (ST7735) era 128x160, mas
# depois desses testes confirmei ser na verdade 128x128.
if (display085):
tft.initb2() # lcd 0.85'
tft.invertcolor(True)
tft.rgb(False)
else:
tft.initg() # lcd 1.77' 128x160
tft.rotation(2);
print('Hello from Pi Pico using Python. Running: Display SPI ST7735.')
def testlines(color):
tft.fill(TFT.BLACK)
for x in range(0, tft.size(), 6):
tft.line((0,0),(x, tft.size() - 1), color)
for y in range(0, tft.size(), 6):
tft.line((0,0),(tft.size() - 1, y), color)
tft.fill(TFT.BLACK)
for x in range(0, tft.size(), 6):
tft.line((tft.size() - 1, 0), (x, tft.size() - 1), color)
for y in range(0, tft.size(), 6):
tft.line((tft.size() - 1, 0), (0, y), color)
tft.fill(TFT.BLACK)
for x in range(0, tft.size(), 6):
tft.line((0, tft.size() - 1), (x, 0), color)
for y in range(0, tft.size(), 6):
tft.line((0, tft.size() - 1), (tft.size() - 1,y), color)
tft.fill(TFT.BLACK)
for x in range(0, tft.size(), 6):
tft.line((tft.size() - 1, tft.size() - 1), (x, 0), color)
for y in range(0, tft.size(), 6):
tft.line((tft.size() - 1, tft.size() - 1), (0, y), color)
def testfastlines(color1, color2):
tft.fill(TFT.BLACK)
for y in range(0, tft.size(), 5):
tft.hline((0,y), tft.size(), color1)
for x in range(0, tft.size(), 5):
tft.vline((x,0), tft.size(), color2)
def testdrawrects(color):
tft.fill(TFT.BLACK);
for x in range(0,tft.size(),6):
tft.rect((tft.size()//2 - x//2, tft.size()//2 - x/2), (x, x), color)
def testfillrects(color1, color2):
tft.fill(TFT.BLACK);
for x in range(tft.size(),0,-6):
tft.fillrect((tft.size()//2 - x//2, tft.size()//2 - x/2), (x, x), color1)
tft.rect((tft.size()//2 - x//2, tft.size()//2 - x/2), (x, x), color2)
def testfillcircles(radius, color):
for x in range(radius, tft.size(), radius * 2):
for y in range(radius, tft.size(), radius * 2):
tft.fillcircle((x, y), radius, color)
def testdrawcircles(radius, color):
for x in range(0, tft.size() + radius, radius * 2):
for y in range(0, tft.size() + radius, radius * 2):
tft.circle((x, y), radius, color)
def testtriangles():
tft.fill(TFT.BLACK);
color = 0xF800
w = tft.size() // 2
x = tft.size() - 1
y = 0
z = tft.size()
for t in range(0, 15):
tft.line((w, y), (y, x), color)
tft.line((y, x), (z, x), color)
tft.line((z, x), (w, y), color)
x -= 4
y += 4
z -= 4
color += 100
def testroundrects():
tft.fill(TFT.BLACK);
color = 100
for t in range(5):
x = 0
y = 0
w = tft.size() - 2
h = tft.size() - 2
for i in range(17):
tft.rect((x, y), (w, h), color)
x += 2
y += 3
w -= 4
h -= 6
color += 1100
color += 100
def tftprinttest():
tft.fill(TFT.BLACK);
v = 30
tft.text((0, v), "Hello World!", TFT.RED, sysfont, 1, nowrap=True)
v += sysfont["Height"]
tft.text((0, v), "Hello World!", TFT.YELLOW, sysfont, 2, nowrap=True)
v += sysfont["Height"] * 2
tft.text((0, v), "Hello World!", TFT.GREEN, sysfont, 3, nowrap=True)
v += sysfont["Height"] * 3
tft.text((0, v), str(1234.567), TFT.BLUE, sysfont, 4, nowrap=True)
time.sleep_ms(2000)
tft.fill(TFT.BLACK);
v = 0
tft.text((0, v), "Hello World!", TFT.RED, sysfont)
v += sysfont["Height"]
tft.text((0, v), str(math.pi), TFT.GREEN, sysfont)
v += sysfont["Height"]
tft.text((0, v), " Want pi?", TFT.GREEN, sysfont)
v += sysfont["Height"] * 2
tft.text((0, v), hex(8675309), TFT.GREEN, sysfont)
v += sysfont["Height"]
tft.text((0, v), " Print HEX!", TFT.GREEN, sysfont)
v += sysfont["Height"] * 2
tft.text((0, v), "Sketch has been", TFT.WHITE, sysfont)
v += sysfont["Height"]
tft.text((0, v), "running for: ", TFT.WHITE, sysfont)
v += sysfont["Height"]
tft.text((0, v), str(time.ticks_ms() / 1000), TFT.PURPLE, sysfont)
v += sysfont["Height"]
tft.text((0, v), " seconds.", TFT.WHITE, sysfont)
def printhello():
x = 0
y = 0
message = "Hello World"
fontSize = 2
fontType = sysfont # sysfont (the best), terminalfont, seriffont
tft.text((x, y), message, TFT.GRAY, fontType, fontSize) # 1
tft.text((x, y+15), message, TFT.MAROON, fontType, fontSize)
tft.text((x, y+30), message, TFT.GRAY, fontType, fontSize)
tft.text((x, y+45), message, TFT.MAROON, fontType, fontSize)
tft.text((x, y+60), message, TFT.GRAY, fontType, fontSize) # 5
tft.text((x, y+75), message, TFT.MAROON, fontType, fontSize)
tft.text((x, y+90), message, TFT.GRAY, fontType, fontSize) # 7 (retrato 128x128)
tft.text((x, y+105), message, TFT.MAROON, fontType, fontSize) # 8 (paisagem 128x160, retrato 128x128)
tft.text((x, y+120), message, TFT.GRAY, fontType, fontSize) # 9 (metade fora do frame 128x128)
tft.text((x, y+135), message, TFT.MAROON, fontType, fontSize) # 10 (retrato 128x160)
tft.text((x, y+150), message, TFT.NAVY, fontType, fontSize) # 11 (metade fora do frame 128x160)
def test():
tft.fill(TFT.BLACK)
printhello()
tft.fill(TFT.RED)
printhello()
tft.fill(TFT.GREEN)
printhello()
tft.fill(TFT.BLUE)
printhello()
tft.fill(TFT.YELLOW)
printhello()
tft.fill(TFT.PURPLE)
printhello()
tft.fill(TFT.WHITE)
printhello()
def test_fps():
frame_count = 0
start_time = time.ticks_ms()
while True:
test()
frame_count += 1
# 每1秒计算一次帧率
if time.ticks_ms() - start_time >= 1000:
fps = frame_count / ((time.ticks_ms() - start_time) / 1000)
print("FPS: ", fps)
frame_count = 0
start_time = time.ticks_ms()
def test_fps2():
tft.fill(TFT.BLACK)# 清空屏幕
frame_count = 1# 测试 50 帧
start_time = time.ticks_ms()# 记录开始时间
for _ in range(frame_count):
testlines(TFT.RED)
test()
tftprinttest()
end_time = time.ticks_ms()# 记录结束时间
elapsed_time = (end_time - start_time) / 1000# 计算总时间 (秒)
fps = frame_count / elapsed_time# 计算 FPS
print(f"FPS: {fps:.2f}")# 输出帧率
test_fps2()
#test_main()
最终显示帧率大约为20帧/秒
显示效果如下
工程文件如下
页:
[1]