用ESP32-S2实现一个加速度传感器控制的彩灯
1 项目介绍
这是电子森林2023寒假一起练平台(5)- 基于ESP32 WiFi 的综合应用的项目,我完成的是项目6。实现的功能是一个加速度传感器控制的彩灯,将板子朝向不同摆放时,屏幕显示的数字不同,并且手持板子转到不同方位彩灯颜色跟随变化。在板子静置30秒后,彩灯的颜色呈现周期变化。
2 设计思路
1、读出板载加速度传感器传感器X、Y、Z的数值显示在OLED屏幕上
2、根据加速度传感器的数值,板载的RGB彩灯显示不同颜色。
3、当在板子静置30秒(即加速度传感器的X、Y、Z值不发生变化时),彩灯呈现周期性变化,依次显示相应的颜色,1秒钟切换一次。
3 框图和软件流程图
4 硬件介绍
4.1 ESP32-S2 WiFi模块
ESP32-S2 WiFi模块是物联网、可穿戴电子设备和智能家居等应用场景的理想选择,另搭配输入控制、输出显示以及传感器感知和控制的套件,使其功能更加完善。
该模块板载了:
- ESP32-S2-MINI-1模组
- 这是一款4 GHz WiFi 模组
- 内置 ESP32S2 系列芯片,Xtensa® 单核 32 位 LX7 微处理器
- 内置芯片叠封 4 MB flash,可叠封 2 MB PSRAM
- 37 个 GPIO,具有丰富的外设
- 板载 PCB 天线
配套的ESP32 S2 开发板除了ESP32wifi模组之外还集成了USB TYPE -C接口,两个按键,一个电源指示灯,一个用户LED灯,2排10pin的排针,将重要IO引出。使用USB供电或通过排针3.3V供电。
ESP32-S2 是一款高度集成、高性价比、低功耗、主打安全的单核 Wi-Fi SoC,具备强大的功能和丰富的 IO 接口。使用乐鑫ESP-IF开发环境,我们可以通过USB对其编程,作为带wifi的MCU单独使用,也可以烧录AT固件,作为WiFi透传模块与RP2040游戏机套件结合使用。
4.2 输入、输出扩展板
本扩展板包含如下功能:
- 按键、旋转编码器输入 - 以模拟信号的方式
- 双电位计控制输入 - 以数字信号的方式
- RGB三色LED显示
- 44寸128*128 LCD,SPI总线访问
- MMA7660三轴姿态传感器
- 电阻加热
- 温度传感器
- 与ESP32-S2核心模块的接口
5 实现的功能及图片展示
5.1 MMA7660加速度传感器的研究
板载一颗来自飞思卡尔的MMA7660这一款传感器。MMA7660FC是具有数字输出的I²C、低功耗、紧凑型电容式微机械加速度传感器,提供低通滤波器、零重力加速度偏移和增益误差补偿,并可以转化为6位数字值,用户可配置输出数据的传输速率。该器件可通过中断引脚(INT)识别传感器的数据变化、产品的朝向和姿态等。
产片结构图
产品特性
- I2C输出
- 可配置每秒采样率1到120次
- 低功耗的自动唤醒/休眠功能
- 低功耗: 关机模式:4 µA 待机模式:2 µA 工作模式:可配置,低至47 µA
- 工作电压:4V – 3.6V
- 3轴±5 g MEMS传感器和CMOS接口控制器集成在同一个封装中
- 输出数据传输速率可设置,采样频率从每秒1次到120次
- 具备自动唤醒/自动睡眠功能,以降低功耗
- 朝向检测:横向/纵向识别
- 姿势检测,包括震动和脉冲识别
系统框架图
5.2 功能实现
(1)读取三轴加速度传感器的数值。
(2)将读取的数值显示在TFT液晶屏上。
(3)根据读数变化,改变RGB灯颜色。
(4)30秒内,数值无变化,RGB彩灯间隔1秒依次变换颜色。
5.3 Thonny的下载与安装
Thonny是一个面向初学者的 Python IDE。Thonny 由爱沙尼亚的 Tartu 大学开发,它采用了不同的方法,因为它的调试器是专为学习和教学编程而设计的。
Installer with 64-bit Python 3.10下载链接:https://github.com/thonny/thonny/releases/download/v4.0.2/thonny-4.0.2.exe
5.4 导入mma7660库
这里我们使用了一个三轴加速度计驱动库文件mma7660.py,这个文件可以从github下载,也可以新建一个mma7660.py的文件,将下面代码复制粘贴进去。
将mma7660.py驱动文件通过Thonny上传到ESP32的根目录。
class MMA7660:
"""
Interface to the MMA7660FC 3 axis accelerometer of the pyboard
"""
X_REG = 0 # x axis acceleration register (RO)
Y_REG = 1 # y axis acceleration register (RO)
Z_REG = 2 # z axis acceleration register (RO)
TILT_REG = 3 # tilt register (RO)
SAMPLE_STAT_REG = 4 # sample rate status register (RO)
SLEEP_COUNT_REG = 5 # sleep count register (RW)
INT_REG = 6 # interrupt setup register (RW)
MODE_REG = 7 # mode register (RW)
SAMPLING_REG = 8 # sampling rates register
TAP_REG = 9 # tap detection register
TAP_DEBOUNCE_REG = 10 # tap debounce counter
# Tilt status register
SHAKE = 0b10000000 # shake in x, y or z direction
ALERT = 0b01000000 # register was read during update of its value
TAP = 0b00100000 # tap detected
POLA = 0b00011100 # landscape or vertical orientation
BAFRO = 0b00000011 # front/back orientation
# Sample rate status register
AWSRS = 0b00000010 # active sampling in auto wake mode
AMSRS = 0b00000001 # active sampling in active mode
# Interrupt setup register
SHINTX = 0b10000000 # interrupt when shaken along x axis
SHINTY = 0b01000000 # interrupt when shaken along y axis
SHINTZ = 0b00100000 # interrupt when shaken along z axis
GINT = 0b00010000 # interrupt when a measurement is made
ASINT = 0b00001000 # interrupt when exiting auto-sleep
PDINT = 0b00000100 # interrupt when a tap is detected
PLINT = 0b00000010 # interrupt when up/down/right/left position change
FBINT = 0b00000001 # interrupt when font/back position change
# Mode register
IAH = 0b10000000 # interrupt output active low (0) or high (1)
IPP = 0b01000000 # interrupt output open-drain (0) or push-pull (1)
SCPS = 0b00100000 # sleep counter counts in samples (0) or by 16 samples (1)
ASE = 0b00010000 # auto-sleep disabled (0) or enabled (1)
AWE = 0b00001000 # auto-wake disabled (0) or enabled (1)
TON = 0b00000100 # test mode enabled (1, with MODE = 0) or disabled (0)
MODE = 0b00000001 # standby mode (0) or active mode (1)
# Sampling rate register
FILT = 0b11100000 # Tilt debounce filtering: 000 = disable, 111 = match 8 measurements
AWSR = 0b00011000 # Auto-wake mode sampling rate: 00 = 32Hz, 11 = 1Hz
AMSR = 0b00000111 # Active and auto-sleep mode sampling rate: 000 = 120Hz, 001 = 64Hz, 111 = 1Hz
# Active and auto-sleep mode sampling rates (AMSR field)
AMPD = 0b000 # 120 samples per second
AM64 = 0b001 # 64 samples per second
AM32 = 0b010 # 32 samples per second
AM16 = 0b011 # 16 samples per second
AM8 = 0b100 # 8 samples per second
AM4 = 0b101 # 4 samples per second
AM2 = 0b110 # 2 samples per second
AM1 = 0b111 # 1 sample per second
# Auto-wake sampling rates (AWSR field)
AW32 = 0b00 # 32 samples per second
AW16 = 0b01 # 16 samples per second
AW8 = 0b10 # 8 samples per second
AW1 = 0b11 # 1 sample per second
# Tilt debounce filtering modes
FILT0 = 0b000 # No filtering
FILT2 = 0b001 # filter over 2 samples
FILT3 = 0b010 # filter over 3 samples
FILT4 = 0b011 # filter over 4 samples
FILT5 = 0b100 # filter over 5 samples
FILT6 = 0b101 # filter over 6 samples
FILT7 = 0b110 # filter over 7 samples
FILT8 = 0b111 # filter over 8 samples
# Tap detection
ZDA = 0b10000000 # enable tap detection on z axis
YDA = 0b01000000 # enable tap detection on y axis
XDA = 0b00100000 # enable tap detection on x axis
PDTH = 0b00011111 # tap detection threshold (1 to 31 counts)
"""
Initialize a new instance of the accelerometer interface.
The accelerometer is found by comparing the devices on the I2C bus
when the MMA chip is powered and when it is not powered.
The device is then put in standby mode.
"""
def __init__(self, i2c):
self.i2c = i2c
devices = self.i2c.scan() # get devices on I2C bus
self.address = None
for dev in devices:
if dev == 0x4c:
self.address = dev
if self.address == None:
raise RuntimeError("No MMA7660 accelerometer found on I2C bus 1")
self.buf = bytearray(1) # 1-byte buffer for I2C communications
self.on(False) # Put it in standby mode
"""
Get the address of the MMA7660 device on the I2C bus
"""
def getAddress(self):
return self.address
"""
Set a bit in a register of the device.
Params:
* reg is the register address
* bit is the mask of the bit to set
"""
def setBit(self, reg, bit):
self.i2c.readfrom_mem_into(self.address, reg, self.buf) # get previous register value
self.buf[0] |= bit # set bit to 1
self.i2c.writeto_mem(self.address, reg, self.buf) # write new value
"""
Clear a bit in a register of the device.
Params:
* reg is the register address
* bit is the mask of the bit to clear
"""
def clearBit(self, reg, bit):
self.i2c.readfrom_mem_into(self.address, reg, self.buf) # get previous register value
self.buf[0] &= ~bit # clear bit
self.i2c.writeto_mem(self.address, reg, self.buf) # write new value
"""
Put the MMA7660 in active or standby mode.
Params:
* on: True for active mode, False for standby mode
"""
def on(self, on=True):
if on:
self.setBit(MMA7660.MODE_REG, MMA7660.MODE)
else:
self.clearBit(MMA7660.MODE_REG, MMA7660.MODE)
"""
Tell whether the MMA7660 is in active mode.
"""
def isOn(self):
mode = self.i2c.readfrom_mem(self.address, MMA7660.MODE_REG, 1)
return not ((mode[0] & MMA7660.MODE) == 0)
"""
Get a sample a data from the MMA7660.
Params:
* data: a bytearray of length 3
data[0] will contain the 6-bit value of the acceleration along the x axis in 2's complement
data[1] will contain the 6-bit value of the acceleration along the y axis in 2's complement
data[2] will contain the 6-bit value of the acceleration along the z axis in 2's complement
"""
def getSample(self, data):
self.i2c.readfrom_mem_into(self.address, MMA7660.X_REG, data) # read sample
for i in range(3):
data[i] &= 0x3F # clip values to 6 bits
"""
Set the sampling rate of the accelerometer in active mode.
Params:
* rate: one of AMPD, AM64, ..., AM2, AM1
"""
def setActiveSamplingRate(self, rate):
self.i2c.mem_read(self.buf, self.address, MMA7660.SAMPLING_REG)
r = rate & MMA7660.AMSR # clip value to field width
self.buf[0] = (self.buf[0] & (~MMA7660.AMSR)) | r
was_on = self.isOn() # save previous mode of MMA7660
self.on(False) # put in standby mode to change register value
self.i2c.writeto_mem(self.address, MMA7660.SAMPLING_REG, self.buf)
self.on(was_on) # restore previous mode
"""
Set the mask of enabled interrupts.
Params:
* mask: any combination of SHINTX, SHINTY, ..., PLINT, FBINT
"""
def enableInterrupt(self, mask):
was_on = self.isOn() # save current mode
self.on(False) # put in standby mode to write register
self.i2c.writeto_mem(self.address, MMA7660.INT_REG, mask)
self.on(was_on) # restore previous mode
"""
Set the interrupt handler for MMA7660 interrupts.
Params:
* handler: a function taking a pyb.ExtInt object as parameter, or None
"""
def setInterruptHandler(self, handler):
mma_int_pin = pyb.Pin('MMA_INT') # interrupt pin of the MMA7660
# Note: we assume that the INT pin is active low and is open drain
# Firstly, remove the previous interrupt handler
extint = pyb.ExtInt(mma_int_pin, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, None)
# Then, if a handler is given, register it
if handler != None:
extint = pyb.ExtInt(mma_int_pin, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, handler)
return extint
5.5 导入ST7735库
这里我们使用了一个TFT液晶屏驱动库文件ST7735.py,这个文件可以从github下载,也可以新建一个ST7735.py的文件,将下面代码复制粘贴进去。
将ST7735.py驱动文件通过Thonny上传到ESP32的根目录。
#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 MdcTL to control display rotation/color layout
#Looking at display with pins on top.
#00 = upper left printing right
#10 = does nothing (MdcTL_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 = (MdcTL_MH)
#60 = 90 right rotation
#C0 = 180 right rotation
#A0 = 270 right rotation
TFTRotations = [0x00, 0x60, 0xC0, 0xA0]
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, 128)
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
MdcTL = 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, dc, rst, cs) :
"""aLoc SPI pin location is either 1 for 'X' or 2 for 'Y'.
dc is the DC pin and rst is the reset pin."""
self._size = ScreenSize
self._offset = bytearray([0,0])
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(dc, machine.Pin.OUT, machine.Pin.PULL_DOWN)
self.reset = machine.Pin(rst, machine.Pin.OUT, machine.Pin.PULL_DOWN)
self.cs = machine.Pin(cs, machine.Pin.OUT, machine.Pin.PULL_DOWN)
self.cs(1)
self.spi = spi
self.colorData = bytearray(2)
self.windowLocData = bytearray(4)
def size( self ) :
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._setMdcTL()
# @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[1], self._size[0])
self._setMdcTL()
# @micropython.native
def pixel( self, aPos, aColor ) :
'''Draw a pixel at the given position'''
if 0 <= aPos[0] < self._size[0] and 0 <= aPos[1] < self._size[1]:
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[0] 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 [0] or [1].'''
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[0] * 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[0]:
if nowrap:
break
else:
py += aFont["Height"] * wh[1] + 1
px = aPos[0]
# @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"][ci:ci + fontw]
px = aPos[0]
if aSizes[0] <= 1 and aSizes[1] <= 1 :
buf = bytearray(2 * fonth * fontw)
for q in range(fontw) :
c = charA[q]
for r in range(fonth) :
if c & 0x01 :
pos = 2 * (r * fontw + q)
buf[pos] = aColor >> 8
buf[pos + 1] = aColor & 0xff
c >>= 1
self.image(aPos[0], aPos[1], aPos[0] + fontw - 1, aPos[1] + fonth - 1, buf)
else:
for c in charA :
py = aPos[1]
for r in range(fonth) :
if c & 0x01 :
self.fillrect((px, py), aSizes, aColor)
py += aSizes[1]
c >>= 1
px += aSizes[0]
# @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[0] == aEnd[0]:
#Make sure we use the smallest y.
pnt = aEnd if (aEnd[1] < aStart[1]) else aStart
self.vline(pnt, abs(aEnd[1] - aStart[1]) + 1, aColor)
elif aStart[1] == aEnd[1]:
#Make sure we use the smallest x.
pnt = aEnd if aEnd[0] < aStart[0] else aStart
self.hline(pnt, abs(aEnd[0] - aStart[0]) + 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], 0, self._size[0]), clamp(aStart[1], 0, self._size[1]))
stop = (start[0], clamp(start[1] + aLen, 0, self._size[1]))
#Make sure smallest y 1st.
if (stop[1] < start[1]):
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], 0, self._size[0]), clamp(aStart[1], 0, self._size[1]))
stop = (clamp(start[0] + aLen, 0, self._size[0]), start[1])
#Make sure smallest x 1st.
if (stop[0] < start[0]):
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[0], aColor)
self.hline((aStart[0], aStart[1] + aSize[1] - 1), aSize[0], aColor)
self.vline(aStart, aSize[1], aColor)
self.vline((aStart[0] + aSize[0] - 1, aStart[1]), aSize[1], 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], 0, self._size[0]), clamp(aStart[1], 0, self._size[1]))
end = (clamp(start[0] + aSize[0] - 1, 0, self._size[0]), clamp(start[1] + aSize[1] - 1, 0, self._size[1]))
if (end[0] < start[0]):
tmp = end[0]
end = (start[0], end[1])
start = (tmp, start[1])
if (end[1] < start[1]):
tmp = end[1]
end = (end[0], start[1])
start = (start[0], tmp)
self._setwindowloc(start, end)
numPixels = (end[0] - start[0] + 1) * (end[1] - start[1] + 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[0] = aColor >> 8
self.colorData[1] = aColor
xend = int(0.7071 * aRadius) + 1
rsq = aRadius * aRadius
for x in range(xend) :
y = int(sqrt(rsq - x * x))
xp = aPos[0] + x
yp = aPos[1] + y
xn = aPos[0] - x
yn = aPos[1] - y
xyp = aPos[0] + y
yxp = aPos[1] + x
xyn = aPos[0] - y
yxn = aPos[1] - 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[1] - y
ey = y0 + y * 2
y0 = clamp(y0, 0, self._size[1])
ln = abs(ey - y0) + 1;
self.vline((aPos[0] + x, y0), ln, aColor)
self.vline((aPos[0] - 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([0, tfa])
self._writedata(data2)
data2[1] = 162 - tfa - bfa
self._writedata(data2)
data2[1] = 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([addr >> 8, addr & 0xff])
self._writedata(data2)
# @micropython.native
def _setColor( self, aColor ) :
self.colorData[0] = aColor >> 8
self.colorData[1] = 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[0] + int(aPos[0])
y = self._offset[1] + int(aPos[1])
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData[0] = self._offset[0]
self.windowLocData[1] = x
self.windowLocData[2] = self._offset[0]
self.windowLocData[3] = x
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData[0] = self._offset[1]
self.windowLocData[1] = y
self.windowLocData[2] = self._offset[1]
self.windowLocData[3] = 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[0] = self._offset[0]
self.windowLocData[1] = self._offset[0] + int(aPos0[0])
self.windowLocData[2] = self._offset[0]
self.windowLocData[3] = self._offset[0] + int(aPos1[0])
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData[0] = self._offset[1]
self.windowLocData[1] = self._offset[1] + int(aPos0[1])
self.windowLocData[2] = self._offset[1]
self.windowLocData[3] = self._offset[1] + int(aPos1[1])
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([aCommand]))
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[0] = aColor >> 8
self.colorData[1] = aColor
self._writedata(self.colorData)
#@micropython.native
def _setMdcTL( self ) :
'''Set screen rotation and RGB/BGR format.'''
self._writecommand(TFT.MdcTL)
rgb = TFTRGB if self._rgb else TFTBGR
self._writedata(bytearray([TFTRotations[self.rotate] | 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[0] + 2, ScreenSize[1] + 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[0] = 0x05 #16 bit color.
self._writedata(data1)
time.sleep_us(10)
data3 = bytearray([0x00, 0x06, 0x03]) #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.MdcTL)
data1[0] = 0x08 #row address/col address, bottom to top refresh
self._writedata(data1)
data2 = bytearray(2)
self._writecommand(TFT.DISSET5) #Display settings
data2[0] = 0x15 #1 clock cycle nonoverlap, 2 cycle gate rise, 3 cycle oscil, equalize
data2[1] = 0x02 #fix on VTL
self._writedata(data2)
self._writecommand(TFT.INVCTR) #Display inversion control
data1[0] = 0x00 #Line inversion.
self._writedata(data1)
self._writecommand(TFT.PWCTR1) #Power control
data2[0] = 0x02 #GVDD = 4.7V
data2[1] = 0x70 #1.0uA
self._writedata(data2)
time.sleep_us(10)
self._writecommand(TFT.PWCTR2) #Power control
data1[0] = 0x05 #VGH = 14.7V, VGL = -7.35V
self._writedata(data1)
self._writecommand(TFT.PWCTR3) #Power control
data2[0] = 0x01 #Opamp current small
data2[1] = 0x02 #Boost frequency
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
data2[0] = 0x3C #VCOMH = 4V
data2[1] = 0x38 #VCOML = -1.1V
self._writedata(data2)
time.sleep_us(10)
self._writecommand(TFT.PWCTR6) #Power control
data2[0] = 0x11
data2[1] = 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[0] = 0x00
self.windowLocData[1] = 2 #Start at column 2
self.windowLocData[2] = 0x00
self.windowLocData[3] = self._size[0] - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData[1] = 1 #Start at row 2.
self.windowLocData[3] = self._size[1] - 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([0x01, 0x2C, 0x2D]) #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([0x01, 0x2c, 0x2d, 0x01, 0x2c, 0x2d])
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[0] = 0x07 #Line inversion.
self._writedata(data1)
self._writecommand(TFT.PWCTR1) #Power control
data3[0] = 0xA2
data3[1] = 0x02
data3[2] = 0x84
self._writedata(data3)
self._writecommand(TFT.PWCTR2) #Power control
data1[0] = 0xC5 #VGH = 14.7V, VGL = -7.35V
self._writedata(data1)
data2 = bytearray(2)
self._writecommand(TFT.PWCTR3) #Power control
data2[0] = 0x0A #Opamp current small
data2[1] = 0x00 #Boost frequency
self._writedata(data2)
self._writecommand(TFT.PWCTR4) #Power control
data2[0] = 0x8A #Opamp current small
data2[1] = 0x2A #Boost frequency
self._writedata(data2)
self._writecommand(TFT.PWCTR5) #Power control
data2[0] = 0x8A #Opamp current small
data2[1] = 0xEE #Boost frequency
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
data1[0] = 0x0E
self._writedata(data1)
self._writecommand(TFT.INVOFF)
self._writecommand(TFT.MdcTL) #Power control
data1[0] = 0xC8
self._writedata(data1)
self._writecommand(TFT.COLMOD)
data1[0] = 0x05
self._writedata(data1)
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData[0] = 0x00
self.windowLocData[1] = 0x00
self.windowLocData[2] = 0x00
self.windowLocData[3] = self._size[0] - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData[3] = self._size[1] - 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 initb3( self ) :
'''Initialize eetree blue tab version.'''
self._size = (ScreenSize[0] + 2, ScreenSize[1] + 3)
self._offset[0] = 2
self._offset[1] = 3
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([0x01, 0x2C, 0x2D]) #
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[0] = 0x07
self._writedata(data1)
self._writecommand(TFT.PWCTR1) #Power control
data3[0] = 0xA2 #
data3[1] = 0x02 #
data3[2] = 0x84 #
self._writedata(data3)
time.sleep_us(10)
self._writecommand(TFT.PWCTR2) #Power control
data1[0] = 0xC5 #
self._writedata(data1)
self._writecommand(TFT.PWCTR3) #Power control
data2 = bytearray(2)
data2[0] = 0x0A #
data2[1] = 0x00 #
self._writedata(data2)
self._writecommand(TFT.PWCTR4) #Power control
data2[0] = 0x8A #
data2[1] = 0x2A #
self._writedata(data2)
self._writecommand(TFT.PWCTR5) #Power control
data2[0] = 0x8A #
data2[1] = 0xEE #
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
data1[0] = 0x0E #
self._writedata(data1)
time.sleep_us(10)
self._writecommand(TFT.MdcTL)
data1[0] = 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[0] = 0x00
self.windowLocData[1] = 0x02 #Start at column 2
self.windowLocData[2] = 0x00
self.windowLocData[3] = self._size[0] - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData[1] = 0x01 #Start at row 2.
self.windowLocData[3] = self._size[1] - 1
self._writedata(self.windowLocData)
data1 = bytearray(1)
self._writecommand(TFT.COLMOD) #Set color mode.
data1[0] = 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)
def initb2( self ) :
'''Initialize another blue tab version.'''
self._size = (ScreenSize[0] + 2, ScreenSize[1] + 1)
self._offset[0] = 2
self._offset[1] = 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([0x01, 0x2C, 0x2D]) #
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[0] = 0x07
self._writedata(data1)
self._writecommand(TFT.PWCTR1) #Power control
data3[0] = 0xA2 #
data3[1] = 0x02 #
data3[2] = 0x84 #
self._writedata(data3)
time.sleep_us(10)
self._writecommand(TFT.PWCTR2) #Power control
data1[0] = 0xC5 #
self._writedata(data1)
self._writecommand(TFT.PWCTR3) #Power control
data2 = bytearray(2)
data2[0] = 0x0A #
data2[1] = 0x00 #
self._writedata(data2)
self._writecommand(TFT.PWCTR4) #Power control
data2[0] = 0x8A #
data2[1] = 0x2A #
self._writedata(data2)
self._writecommand(TFT.PWCTR5) #Power control
data2[0] = 0x8A #
data2[1] = 0xEE #
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
data1[0] = 0x0E #
self._writedata(data1)
time.sleep_us(10)
self._writecommand(TFT.MdcTL)
data1[0] = 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[0] = 0x00
self.windowLocData[1] = 0x02 #Start at column 2
self.windowLocData[2] = 0x00
self.windowLocData[3] = self._size[0] - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData[1] = 0x01 #Start at row 2.
self.windowLocData[3] = self._size[1] - 1
self._writedata(self.windowLocData)
data1 = bytearray(1)
self._writecommand(TFT.COLMOD) #Set color mode.
data1[0] = 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([0x01, 0x2C, 0x2D]) #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([0x01, 0x2c, 0x2d, 0x01, 0x2c, 0x2d])
self._writecommand(TFT.FRMCTR3) #Frame rate control.
self._writedata(data6)
time.sleep_us(10)
self._writecommand(TFT.INVCTR) #Display inversion control
self._writedata(bytearray([0x07]))
self._writecommand(TFT.PWCTR1) #Power control
data3[0] = 0xA2
data3[1] = 0x02
data3[2] = 0x84
self._writedata(data3)
self._writecommand(TFT.PWCTR2) #Power control
self._writedata(bytearray([0xC5]))
data2 = bytearray(2)
self._writecommand(TFT.PWCTR3) #Power control
data2[0] = 0x0A #Opamp current small
data2[1] = 0x00 #Boost frequency
self._writedata(data2)
self._writecommand(TFT.PWCTR4) #Power control
data2[0] = 0x8A #Opamp current small
data2[1] = 0x2A #Boost frequency
self._writedata(data2)
self._writecommand(TFT.PWCTR5) #Power control
data2[0] = 0x8A #Opamp current small
data2[1] = 0xEE #Boost frequency
self._writedata(data2)
self._writecommand(TFT.VMCTR1) #Power control
self._writedata(bytearray([0x0E]))
self._writecommand(TFT.INVOFF)
self._setMdcTL()
self._writecommand(TFT.COLMOD)
self._writedata(bytearray([0x05]))
self._writecommand(TFT.CASET) #Column address set.
self.windowLocData[0] = 0x00
self.windowLocData[1] = 0x01 #Start at row/column 1.
self.windowLocData[2] = 0x00
self.windowLocData[3] = self._size[0] - 1
self._writedata(self.windowLocData)
self._writecommand(TFT.RASET) #Row address set.
self.windowLocData[3] = self._size[1] - 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
5.6 导入sysfont字体
这里我们使用了一个sysfont字体库文件sysfont.py,这个文件可以从github下载,也可以新建一个sysfont.py的文件,将下面代码复制粘贴进去。
将sysfont.py驱动文件通过Thonny上传到ESP32的根目录。
#Font used for ST7735 display.
#Each character uses 5 bytes.
#index using ASCII value * 5.
#Each byte contains a column of pixels.
#The character may be 8 pixels high and 5 wide.
sysfont = {"Width": 5, "Height": 8, "Start": 0, "End": 254, "Data": bytearray([
0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
0x18, 0x3C, 0x7E, 0x3C, 0x18,
0x1C, 0x57, 0x7D, 0x57, 0x1C,
0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
0x00, 0x18, 0x3C, 0x18, 0x00,
0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
0x00, 0x18, 0x24, 0x18, 0x00,
0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
0x30, 0x48, 0x3A, 0x06, 0x0E,
0x26, 0x29, 0x79, 0x29, 0x26,
0x40, 0x7F, 0x05, 0x05, 0x07,
0x40, 0x7F, 0x05, 0x25, 0x3F,
0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
0x7F, 0x3E, 0x1C, 0x1C, 0x08,
0x08, 0x1C, 0x1C, 0x3E, 0x7F,
0x14, 0x22, 0x7F, 0x22, 0x14,
0x5F, 0x5F, 0x00, 0x5F, 0x5F,
0x06, 0x09, 0x7F, 0x01, 0x7F,
0x00, 0x66, 0x89, 0x95, 0x6A,
0x60, 0x60, 0x60, 0x60, 0x60,
0x94, 0xA2, 0xFF, 0xA2, 0x94,
0x08, 0x04, 0x7E, 0x04, 0x08,
0x10, 0x20, 0x7E, 0x20, 0x10,
0x08, 0x08, 0x2A, 0x1C, 0x08,
0x08, 0x1C, 0x2A, 0x08, 0x08,
0x1E, 0x10, 0x10, 0x10, 0x10,
0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
0x30, 0x38, 0x3E, 0x38, 0x30,
0x06, 0x0E, 0x3E, 0x0E, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5F, 0x00, 0x00,
0x00, 0x07, 0x00, 0x07, 0x00,
0x14, 0x7F, 0x14, 0x7F, 0x14,
0x24, 0x2A, 0x7F, 0x2A, 0x12,
0x23, 0x13, 0x08, 0x64, 0x62,
0x36, 0x49, 0x56, 0x20, 0x50,
0x00, 0x08, 0x07, 0x03, 0x00,
0x00, 0x1C, 0x22, 0x41, 0x00,
0x00, 0x41, 0x22, 0x1C, 0x00,
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
0x08, 0x08, 0x3E, 0x08, 0x08,
0x00, 0x80, 0x70, 0x30, 0x00,
0x08, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x60, 0x60, 0x00,
0x20, 0x10, 0x08, 0x04, 0x02,
0x3E, 0x51, 0x49, 0x45, 0x3E,
0x00, 0x42, 0x7F, 0x40, 0x00,
0x72, 0x49, 0x49, 0x49, 0x46,
0x21, 0x41, 0x49, 0x4D, 0x33,
0x18, 0x14, 0x12, 0x7F, 0x10,
0x27, 0x45, 0x45, 0x45, 0x39,
0x3C, 0x4A, 0x49, 0x49, 0x31,
0x41, 0x21, 0x11, 0x09, 0x07,
0x36, 0x49, 0x49, 0x49, 0x36,
0x46, 0x49, 0x49, 0x29, 0x1E,
0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x40, 0x34, 0x00, 0x00,
0x00, 0x08, 0x14, 0x22, 0x41,
0x14, 0x14, 0x14, 0x14, 0x14,
0x00, 0x41, 0x22, 0x14, 0x08,
0x02, 0x01, 0x59, 0x09, 0x06,
0x3E, 0x41, 0x5D, 0x59, 0x4E,
0x7C, 0x12, 0x11, 0x12, 0x7C,
0x7F, 0x49, 0x49, 0x49, 0x36,
0x3E, 0x41, 0x41, 0x41, 0x22,
0x7F, 0x41, 0x41, 0x41, 0x3E,
0x7F, 0x49, 0x49, 0x49, 0x41,
0x7F, 0x09, 0x09, 0x09, 0x01,
0x3E, 0x41, 0x41, 0x51, 0x73,
0x7F, 0x08, 0x08, 0x08, 0x7F,
0x00, 0x41, 0x7F, 0x41, 0x00,
0x20, 0x40, 0x41, 0x3F, 0x01,
0x7F, 0x08, 0x14, 0x22, 0x41,
0x7F, 0x40, 0x40, 0x40, 0x40,
0x7F, 0x02, 0x1C, 0x02, 0x7F,
0x7F, 0x04, 0x08, 0x10, 0x7F,
0x3E, 0x41, 0x41, 0x41, 0x3E,
0x7F, 0x09, 0x09, 0x09, 0x06,
0x3E, 0x41, 0x51, 0x21, 0x5E,
0x7F, 0x09, 0x19, 0x29, 0x46,
0x26, 0x49, 0x49, 0x49, 0x32,
0x03, 0x01, 0x7F, 0x01, 0x03,
0x3F, 0x40, 0x40, 0x40, 0x3F,
0x1F, 0x20, 0x40, 0x20, 0x1F,
0x3F, 0x40, 0x38, 0x40, 0x3F,
0x63, 0x14, 0x08, 0x14, 0x63,
0x03, 0x04, 0x78, 0x04, 0x03,
0x61, 0x59, 0x49, 0x4D, 0x43,
0x00, 0x7F, 0x41, 0x41, 0x41,
0x02, 0x04, 0x08, 0x10, 0x20,
0x00, 0x41, 0x41, 0x41, 0x7F,
0x04, 0x02, 0x01, 0x02, 0x04,
0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x03, 0x07, 0x08, 0x00,
0x20, 0x54, 0x54, 0x78, 0x40,
0x7F, 0x28, 0x44, 0x44, 0x38,
0x38, 0x44, 0x44, 0x44, 0x28,
0x38, 0x44, 0x44, 0x28, 0x7F,
0x38, 0x54, 0x54, 0x54, 0x18,
0x00, 0x08, 0x7E, 0x09, 0x02,
0x18, 0xA4, 0xA4, 0x9C, 0x78,
0x7F, 0x08, 0x04, 0x04, 0x78,
0x00, 0x44, 0x7D, 0x40, 0x00,
0x20, 0x40, 0x40, 0x3D, 0x00,
0x7F, 0x10, 0x28, 0x44, 0x00,
0x00, 0x41, 0x7F, 0x40, 0x00,
0x7C, 0x04, 0x78, 0x04, 0x78,
0x7C, 0x08, 0x04, 0x04, 0x78,
0x38, 0x44, 0x44, 0x44, 0x38,
0xFC, 0x18, 0x24, 0x24, 0x18,
0x18, 0x24, 0x24, 0x18, 0xFC,
0x7C, 0x08, 0x04, 0x04, 0x08,
0x48, 0x54, 0x54, 0x54, 0x24,
0x04, 0x04, 0x3F, 0x44, 0x24,
0x3C, 0x40, 0x40, 0x20, 0x7C,
0x1C, 0x20, 0x40, 0x20, 0x1C,
0x3C, 0x40, 0x30, 0x40, 0x3C,
0x44, 0x28, 0x10, 0x28, 0x44,
0x4C, 0x90, 0x90, 0x90, 0x7C,
0x44, 0x64, 0x54, 0x4C, 0x44,
0x00, 0x08, 0x36, 0x41, 0x00,
0x00, 0x00, 0x77, 0x00, 0x00,
0x00, 0x41, 0x36, 0x08, 0x00,
0x02, 0x01, 0x02, 0x04, 0x02,
0x3C, 0x26, 0x23, 0x26, 0x3C,
0x1E, 0xA1, 0xA1, 0x61, 0x12,
0x3A, 0x40, 0x40, 0x20, 0x7A,
0x38, 0x54, 0x54, 0x55, 0x59,
0x21, 0x55, 0x55, 0x79, 0x41,
0x21, 0x54, 0x54, 0x78, 0x41,
0x21, 0x55, 0x54, 0x78, 0x40,
0x20, 0x54, 0x55, 0x79, 0x40,
0x0C, 0x1E, 0x52, 0x72, 0x12,
0x39, 0x55, 0x55, 0x55, 0x59,
0x39, 0x54, 0x54, 0x54, 0x59,
0x39, 0x55, 0x54, 0x54, 0x58,
0x00, 0x00, 0x45, 0x7C, 0x41,
0x00, 0x02, 0x45, 0x7D, 0x42,
0x00, 0x01, 0x45, 0x7C, 0x40,
0xF0, 0x29, 0x24, 0x29, 0xF0,
0xF0, 0x28, 0x25, 0x28, 0xF0,
0x7C, 0x54, 0x55, 0x45, 0x00,
0x20, 0x54, 0x54, 0x7C, 0x54,
0x7C, 0x0A, 0x09, 0x7F, 0x49,
0x32, 0x49, 0x49, 0x49, 0x32,
0x32, 0x48, 0x48, 0x48, 0x32,
0x32, 0x4A, 0x48, 0x48, 0x30,
0x3A, 0x41, 0x41, 0x21, 0x7A,
0x3A, 0x42, 0x40, 0x20, 0x78,
0x00, 0x9D, 0xA0, 0xA0, 0x7D,
0x39, 0x44, 0x44, 0x44, 0x39,
0x3D, 0x40, 0x40, 0x40, 0x3D,
0x3C, 0x24, 0xFF, 0x24, 0x24,
0x48, 0x7E, 0x49, 0x43, 0x66,
0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
0xFF, 0x09, 0x29, 0xF6, 0x20,
0xC0, 0x88, 0x7E, 0x09, 0x03,
0x20, 0x54, 0x54, 0x79, 0x41,
0x00, 0x00, 0x44, 0x7D, 0x41,
0x30, 0x48, 0x48, 0x4A, 0x32,
0x38, 0x40, 0x40, 0x22, 0x7A,
0x00, 0x7A, 0x0A, 0x0A, 0x72,
0x7D, 0x0D, 0x19, 0x31, 0x7D,
0x26, 0x29, 0x29, 0x2F, 0x28,
0x26, 0x29, 0x29, 0x29, 0x26,
0x30, 0x48, 0x4D, 0x40, 0x20,
0x38, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x38,
0x2F, 0x10, 0xC8, 0xAC, 0xBA,
0x2F, 0x10, 0x28, 0x34, 0xFA,
0x00, 0x00, 0x7B, 0x00, 0x00,
0x08, 0x14, 0x2A, 0x14, 0x22,
0x22, 0x14, 0x2A, 0x14, 0x08,
0xAA, 0x00, 0x55, 0x00, 0xAA,
0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x00, 0x00, 0x00, 0xFF, 0x00,
0x10, 0x10, 0x10, 0xFF, 0x00,
0x14, 0x14, 0x14, 0xFF, 0x00,
0x10, 0x10, 0xFF, 0x00, 0xFF,
0x10, 0x10, 0xF0, 0x10, 0xF0,
0x14, 0x14, 0x14, 0xFC, 0x00,
0x14, 0x14, 0xF7, 0x00, 0xFF,
0x00, 0x00, 0xFF, 0x00, 0xFF,
0x14, 0x14, 0xF4, 0x04, 0xFC,
0x14, 0x14, 0x17, 0x10, 0x1F,
0x10, 0x10, 0x1F, 0x10, 0x1F,
0x14, 0x14, 0x14, 0x1F, 0x00,
0x10, 0x10, 0x10, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x10,
0x10, 0x10, 0x10, 0x1F, 0x10,
0x10, 0x10, 0x10, 0xF0, 0x10,
0x00, 0x00, 0x00, 0xFF, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0xFF, 0x10,
0x00, 0x00, 0x00, 0xFF, 0x14,
0x00, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0x1F, 0x10, 0x17,
0x00, 0x00, 0xFC, 0x04, 0xF4,
0x14, 0x14, 0x17, 0x10, 0x17,
0x14, 0x14, 0xF4, 0x04, 0xF4,
0x00, 0x00, 0xFF, 0x00, 0xF7,
0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0xF7, 0x00, 0xF7,
0x14, 0x14, 0x14, 0x17, 0x14,
0x10, 0x10, 0x1F, 0x10, 0x1F,
0x14, 0x14, 0x14, 0xF4, 0x14,
0x10, 0x10, 0xF0, 0x10, 0xF0,
0x00, 0x00, 0x1F, 0x10, 0x1F,
0x00, 0x00, 0x00, 0x1F, 0x14,
0x00, 0x00, 0x00, 0xFC, 0x14,
0x00, 0x00, 0xF0, 0x10, 0xF0,
0x10, 0x10, 0xFF, 0x10, 0xFF,
0x14, 0x14, 0x14, 0xFF, 0x14,
0x10, 0x10, 0x10, 0x1F, 0x00,
0x00, 0x00, 0x00, 0xF0, 0x10,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x38, 0x44, 0x44, 0x38, 0x44,
0x7C, 0x2A, 0x2A, 0x3E, 0x14,
0x7E, 0x02, 0x02, 0x06, 0x06,
0x02, 0x7E, 0x02, 0x7E, 0x02,
0x63, 0x55, 0x49, 0x41, 0x63,
0x38, 0x44, 0x44, 0x3C, 0x04,
0x40, 0x7E, 0x20, 0x1E, 0x20,
0x06, 0x02, 0x7E, 0x02, 0x02,
0x99, 0xA5, 0xE7, 0xA5, 0x99,
0x1C, 0x2A, 0x49, 0x2A, 0x1C,
0x4C, 0x72, 0x01, 0x72, 0x4C,
0x30, 0x4A, 0x4D, 0x4D, 0x30,
0x30, 0x48, 0x78, 0x48, 0x30,
0xBC, 0x62, 0x5A, 0x46, 0x3D,
0x3E, 0x49, 0x49, 0x49, 0x00,
0x7E, 0x01, 0x01, 0x01, 0x7E,
0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
0x44, 0x44, 0x5F, 0x44, 0x44,
0x40, 0x51, 0x4A, 0x44, 0x40,
0x40, 0x44, 0x4A, 0x51, 0x40,
0x00, 0x00, 0xFF, 0x01, 0x03,
0xE0, 0x80, 0xFF, 0x00, 0x00,
0x08, 0x08, 0x6B, 0x6B, 0x08,
0x36, 0x12, 0x36, 0x24, 0x36,
0x06, 0x0F, 0x09, 0x0F, 0x06,
0x00, 0x00, 0x18, 0x18, 0x00,
0x00, 0x00, 0x10, 0x10, 0x00,
0x30, 0x40, 0xFF, 0x01, 0x01,
0x00, 0x1F, 0x01, 0x01, 0x1E,
0x00, 0x19, 0x1D, 0x17, 0x12,
0x00, 0x3C, 0x3C, 0x3C, 0x3C
])}
6 主要代码片段及说明
6.1 加载库函数
from machine import Pin, SPI, I2C
from mma7660 import MMA7660
from ST7735 import TFT
from sysfont import sysfont
import time
from RGB import RGB
6.2 定义变量
global j
j = 0
LED_1 = 43
LED_2 = 44
LED_3 = 12
# 引脚定义
LCD_CS = 13
LCD_RES = 18
LCD_DC = 17
LCD_SDA = 21
LCD_SCL = 41
i=False
#初始化数组
l[0] = 0
l[1] = 0
l[2] = 0
t = 0
6.3 实例化
# 实例化SPI
spi = SPI(2, baudrate=40000000, polarity=0, phase=0, sck=Pin(LCD_SCL), mosi=Pin(LCD_SDA))
# 实例化TFT
tft=TFT(spi, LCD_DC, LCD_RES, LCD_CS)
# 实例化RGB彩灯
rgb = RGB()
6.4 TFT屏初始化
#TFT屏初始化
tft.initb3()
tft.rotation(2)
tft.rgb(False)
6.5 配置3轴传感器MMA7660
#配置3轴传感器MMA7660
i2c1 = I2C(1, scl=Pin(3), sda=Pin(4))
acc = MMA7660(i2c1)
acc.on(True)
d = bytearray(3)
r = [0 for x in range(3)]
l = [0 for x in range(3)]
def twos_compliment(n, nbits):
sign_bit = 1 << nbits - 1
sign = 1 if n & sign_bit == 0 else -1
val = n & ~sign_bit if sign > 0 else sign * ((sign_bit << 1) - n)
return val
def thumb_filter(a):
return a
6.6 读取传感器数据
#循环10次读取传感器数据
for j in range(10):
acc.getSample(d)
for i in range(3):
r[i] = r[i] + twos_compliment(d[i], 6)
time.sleep(0.1)
for i in range(3):
r[i] = int(r[i]/10)
print((r[0], r[1], r[2]))
6.7 TFT屏显示加速度传感器数值
#TFT屏显示加速度传感器数值
tft.fill(TFT.BLACK);
tft.text((40, 30), str(r[0]), TFT.WHITE, sysfont, 2, nowrap=True)
tft.text((40, 60), str(r[1]), TFT.WHITE, sysfont, 2, nowrap=True)
tft.text((40, 90), str(r[2]), TFT.WHITE, sysfont, 2, nowrap=True)
6.8 根据加速度传感器值,切换彩灯颜色
if r[2] < -20:
rgb.on(0) #红
elif r[1] < 15 and r[2] < -15:
rgb.on(1)
elif r[2] > 20:
rgb.on(2) #绿
elif r[1] > 20:
rgb.on(3) #紫
elif r[1] > -15 and r[2] > 15:
rgb.on(4)
elif r[2] > 20: #蓝
rgb.on(5)
elif r[1] < -20:
rgb.on(6)
6.9 静置30秒周期性彩灯颜色变换
if abs(r[0] - l[0]) < 3 and abs(r[1] - l[1]) < 3 and abs(r[2] - l[2]) < 3:
tft.text((100, 10), str(t), TFT.WHITE, sysfont, 2, nowrap=True)
t = t + 1
else:
t = 0
l[0] = r[0]
l[1] = r[1]
l[2] = r[2]
#如果静置超过30秒,周期性切换彩灯颜色
if t > 30:
rgb.on(t % 7 )
print(t % 7)
i = i + 1
7 运行效果
程序运行效果如下图所示:
1、屏幕加速度显示传感器数据
2、板子转到不同方位彩灯颜色跟随变化
3、静置30秒后,彩灯呈现周期变化
8 遇到的主要难题及解决方法
此次项目中遇到的难题是MMA7660加速度传感器的驱动。之前未使用MMA7660,对于它的驱动,也是尝试在github上和网上找库。最终终于找到了MMA7660的驱动库文件。并在研究库文件的基础上,掌握了MMA7660加速度
传感器的使用。
9 未来的计划或建议
在完成此项目前,笔记尝试了恒温加热、USB HID,存在PID控温不理想,编码器、摇杆的识别会出现误判,计划未来进一步学习,尝试完成其他项目,进一步掌握基于此次扩展板的编码器、摇杆准确判断,PID的精准控温,以及菜单
功能的设计与实现等。