ESP8266+MicroPython开发:ESP8266使用软件模拟SPI驱动TFT屏幕

屏幕图片如下
ESP8266+MicroPython开发:ESP8266使用软件模拟SPI驱动TFT屏幕_第1张图片

这款屏幕是由ST7735进行驱动的,驱动方式有3线SPI,4线SPI,还有8线,16线,9线,18线驱动。由于是买的模块,所以采用4线SPI进行驱动。

ESP8266使用软件模拟SPI驱动TFT屏幕

  • 引脚连接
  • SPI的模拟
    • MYSPI.py
  • TFT的驱动
    • LCD.py
    • CODE.py
    • main.py
  • 效果
  • 工程文件

引脚连接

ESP8266+MicroPython开发:ESP8266使用软件模拟SPI驱动TFT屏幕_第2张图片

ESP8266 TFT
GPIO16 SCL
GPIO5 SDA
GPIO4 RES
GPIO0 DC
GPIO2 CS
GPIO14 BL
VCC 3.3V
GND GND

SPI的模拟

下图为四线SPI的写时序:
ESP8266+MicroPython开发:ESP8266使用软件模拟SPI驱动TFT屏幕_第3张图片
下图为四线SPI的8位读时序,在手册中还有24位读和32位读,由于本次未使用读,不做强调:
ESP8266+MicroPython开发:ESP8266使用软件模拟SPI驱动TFT屏幕_第4张图片

MYSPI.py

from machine import Pin

class MySPI:
    def __init__(self,scl=16,sda=5,res=4,dc=0,cs=2,bl=14):
        self.SCL=Pin(scl,Pin.OUT)
        self.SDA=Pin(sda,Pin.OUT)
        self.RES=Pin(res,Pin.OUT)
        self.DC=Pin(dc,Pin.OUT)
        self.CS=Pin(cs,Pin.OUT)
        self.BL=Pin(bl,Pin.OUT)
        
    def SPI_sendData(self,Data):
        self.CS.off()
        for i in range(8):
            self.SCL.off()
            if Data&0x80==0x80:  
                self.SDA.on()
            else:
                self.SDA.off()
            self.SCL.on()
            Data <<=1
        self.CS.on()
            
    ##未使用
    def SPI_getData(self):
        Data=0
        self.CS=0
        for i in range(8):
            if(self.SDA.value()):
                Data+=1
            self.SCL=1
            Data <<=1
            self.SCL=0
        self.CS=1
        return Data

TFT的驱动

驱动的话主要是写命令和写数据,手册中也说明了DC高电平写数据,低电平写命令,然后使用的话主要是对哪个位置设置哪一种颜色。

LCD.py

from MYSPI  import MySPI
from time import sleep_us
from CODE import StringCode


class LCD(MySPI):
    def __init__(self):
        #颜色定义查找字典
        self.RGB={'white':[31,63,31],'black':[0,0,0],'red':[31,0,0],'green':[0,63,0],'blue':[0,0,31]}
        super().__init__()
    
    #作用:8位数据传输
    #参数:
    #Data:传入的8位数据
    def LCD_Send8Data(self,Data):
        self.DC.on()
        self.SPI_sendData(Data)

    #作用:16位数据传输
    #参数:
    #Data:传入的16位数据
    def LCD_Send16Data(self,Data):
        self.DC.on()
        self.SPI_sendData(Data//256)
        self.SPI_sendData(Data%256)

    #作用:命令传输
    #参数:
    #Com:传入的命令
    def LCD_SendComm(self,Com):
        self.DC.off()
        self.SPI_sendData(Com)

    #作用:设置XY范围
    #参数:
    #xs:x的起始范围
    #xe:x的终止范围
    #ys:y的起始范围
    #ye:y的终止范围
    def LCD_SetXY(self,xs,xe,ys,ye):
        self.LCD_SendComm(0X2A) #设置x范围
        self.LCD_Send16Data(xs+1)
        self.LCD_Send16Data(xe+2)
        self.LCD_SendComm(0X2B) #设置y范围
        self.LCD_Send16Data(ys+1)
        self.LCD_Send16Data(ye+2)
        self.LCD_SendComm(0X2C)#打开内存写入
    
    '''
    0  0  0       黑色
    31 63 31      白色
    31 0  0       红色
    0  63 0       绿色
    0  0  31      蓝色
    '''
    #作用:指定范围颜色填充颜色
    #参数:
    #xs:x的起始范围
    #xe:x的终止范围
    #ys:y的起始范围
    #ye:y的终止范围
    #color: 颜色字符串
    #RGB:颜色数组
    def LCD_FullColor(self,xs,xe,ys,ye,color='',RGB=[]):
        if self.RGB.get(color):
            RGB=self.RGB.get(color)
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        elif RGB:
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        if color>=0 or RGB[0]<=31 and RGB[1]<=63 and RGB[2]<=31:
            self.LCD_SetXY(xs,xe,ys,ye)
            for i in range(ys,ye):
                for i in range(xs,xe):
                    self.LCD_Send16Data(color)
        else:
            print("颜色不在范围内")

    #作用:画一个颜色点
    #参数:
    #x:x的坐标
    #y:y的坐标
    #color: 颜色字符串
    #RGB:颜色数组
    def LCD_DrawPoint(self,x,y,color='',RGB=[]):
        if self.RGB.get(color):
            RGB=self.RGB.get(color)
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        elif RGB:
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        self.LCD_SetXY(x,x+1,y,y+1)
        self.LCD_Send16Data(color)


    #作用:指定范围颜色填充颜色
    #参数:
    #xs:x的起始坐标
    #ys:y的起始坐标
    #strcolor: 字体颜色字符串
    #RGB:字体颜色数组
    #background:背景色字符串
    def LCD_WriteString(self,x,y,string=str,strcolor='',background='',RGB=[]):
        if self.RGB.get(strcolor):
            RGB=self.RGB.get(strcolor)
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        elif RGB:
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        if self.RGB.get(background):
            RGB=self.RGB.get(background)
            background=RGB[2]+RGB[1]*32+RGB[0]*2048            
        for i in range(len(string)):
            self.LCD_SetXY(x+(8*i),x+(8*(i+1)),y,y+16)
            var=StringCode.get(string[i])
            for j in range(16):
                data=var[j]
                for k in range(8):
                    if data&0x01:
                        self.LCD_DrawPoint(x+(8*i)+k,y+j,color)
                    elif background:
                        self.LCD_DrawPoint(x+(8*i)+k,y+j,background)
                    data >>=1
        
    '''
    (xs,ys)------(xe,ys)
    |             |
    |             |
    |             |
    |             |
    |             |
    (xs,ye)------ (xe,ye)
    '''
    #作用:画矩形
    #参数:
    #xs:左上点x坐标
    #ys:左上点y坐标
    #xe:右上点x坐标
    #ye:右上点y坐标
    #size:大小
    #color: 颜色字符串
    #RGB:颜色数组
    def LCD_DrawRect(self,xs,ys,xe,ye,size=2,color='',RGB=[]):
        if self.RGB.get(color):
            RGB=self.RGB.get(color)
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        elif RGB:
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        self.LCD_DrawLine(xs,ys,xe-2,ys,int(size*2),color)
        self.LCD_DrawLine(xe,ys,xe,ye,size,color)
        self.LCD_DrawLine(xe,ye,xs-2,ye,int(size*2),color)
        self.LCD_DrawLine(xs,ye,xs,ys,size,color)
        
    
    def Change_num(self,x1,x2):
        var=max(x1,x2)
        minx=min(x1,x2)
        maxx=var
        return minx,maxx

    #作用:画直线
    #参数:
    #xs:起始点x坐标
    #ys:起始点y坐标
    #xe:结束点x坐标
    #ye:结束点y坐标
    #size:大小
    #color: 颜色字符串
    #RGB:颜色数组
    def LCD_DrawLine(self,xs,ys,xe,ye,size=1,color='',RGB=[]):
        xs,xe=self.Change_num(xs,xe)
        ys,ye=self.Change_num(ys,ye)
        if self.RGB.get(color):
            RGB=self.RGB.get(color)
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        elif RGB:
            color=RGB[2]+RGB[1]*32+RGB[0]*2048
        if xs==xe:
            for j in range(ys,ye):
                self.LCD_FullColor(xs,xs+size,j,j+size,color)             
        elif ys==ye:
            for i in range(xs,xe):
                self.LCD_FullColor(i,i+size,ys,ys+size,color)              
        else:
            tan=(ye-ys)/(xe-xs)
            for i in range(xs,xe):
                for j in range(ys,ye):
                    if (j-ys) <= (tan*(i-xs))+size and (j-ys) >= (tan*(i-xs))-size:
                        self.LCD_FullColor(i,i+size,j,j+size,color)

    #作用:显示图片
    #参数:
    #x:起始点x坐标
    #y:起始点y坐标
    #w:图片宽
    #h:图片高
    #img: 要显示的图片
    def LCD_ShowImage(self,x,y,w,h,img):
        self.LCD_SetXY(x,y,x+w,y+h)
        k=0
        for i in range(h):
            for j in range(w):
                self.LCD_Send8Data(img[2*k])
                self.LCD_Send8Data(img[2*k+1])
                k+=1

    #作用:初始化
    #参数:
    #inversion:颜色反转
    def LCD_init(self,inversion=False):
        self.RES.on()
        sleep_us(10)
        self.RES.off()
        self.RES.on()
        sleep_us(10)
        self.BL.on()#打开背光
        self.LCD_SendComm(0X11)##退出睡眠模式
        self.LCD_SendComm(0x13)#普通模式全屏显示
        if inversion:
            self.LCD_SendComm(0x21)#颜色反转
        else:
            self.LCD_SendComm(0x20)#颜色不反转
        self.LCD_SendComm(0x38)#怠速模式关闭
        self.LCD_SendComm(0x3a)#改变颜色模式
        self.LCD_Send8Data(0x05)#16位颜色
        self.LCD_SendComm(0xb4)
        self.LCD_Send8Data(0x00)
        
        self.LCD_SendComm(0x29)##显示打开

CODE.py

字模使用的是去字模软件获取的,长宽是16*8,设置为字典方便读取,目前只有英文和数字没有符号,需要可以自己补充。

StringCode={'0':[0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00],#0,0#
'1':[0x00,0x00,0x00,0x10,0x1C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00],#1,1#
'2':[0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x40,0x20,0x10,0x08,0x04,0x42,0x7E,0x00,0x00],#2,2#
'3':[0x00,0x00,0x00,0x3C,0x42,0x42,0x40,0x20,0x18,0x20,0x40,0x42,0x42,0x3C,0x00,0x00],#3,3#
'4':[0x00,0x00,0x00,0x20,0x30,0x30,0x28,0x24,0x24,0x22,0xFE,0x20,0x20,0xF8,0x00,0x00],#4,4#
'5':[0x00,0x00,0x00,0x7E,0x02,0x02,0x02,0x1E,0x22,0x40,0x40,0x42,0x22,0x1C,0x00,0x00],#5,5#
'6':[0x00,0x00,0x00,0x18,0x24,0x02,0x02,0x3A,0x46,0x42,0x42,0x42,0x44,0x38,0x00,0x00],#6,6#
'7':[0x00,0x00,0x00,0x7E,0x42,0x20,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x00,0x00],#7,7#
'8':[0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00],#8,8#
'9':[0x00,0x00,0x00,0x1C,0x22,0x42,0x42,0x42,0x62,0x5C,0x40,0x40,0x24,0x18,0x00,0x00],#9,9#
'a':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x30,0x2C,0x22,0x32,0x6C,0x00,0x00],#a,10#
'b':[0x00,0x00,0x00,0x00,0x03,0x02,0x02,0x1A,0x26,0x42,0x42,0x42,0x26,0x1A,0x00,0x00],#b,11#
'c':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x02,0x02,0x02,0x44,0x38,0x00,0x00],#c,12#
'd':[0x00,0x00,0x00,0x00,0x60,0x40,0x40,0x7C,0x42,0x42,0x42,0x42,0x62,0xDC,0x00,0x00],#d,13#
'e':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x7E,0x02,0x42,0x3C,0x00,0x00],#e,14#
'f':[0x00,0x00,0x00,0x00,0x30,0x48,0x08,0x3E,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00],#f,15#
'g':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x22,0x22,0x1C,0x02,0x3C,0x42,0x42,0x3C],#g,16#
'h':[0x00,0x00,0x00,0x00,0x03,0x02,0x02,0x3A,0x46,0x42,0x42,0x42,0x42,0xE7,0x00,0x00],#h,17#
'i':[0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x0E,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00],#i,18#
'j':[0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x22,0x1E],#j,19#
'k':[0x00,0x00,0x00,0x00,0x03,0x02,0x02,0x72,0x12,0x0A,0x0E,0x12,0x22,0x77,0x00,0x00],#k,20#
'l':[0x00,0x00,0x00,0x08,0x0E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00],#l,21#
'm':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x92,0x92,0x92,0x92,0x92,0xB7,0x00,0x00],#m,22#
'n':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3B,0x46,0x42,0x42,0x42,0x42,0xE7,0x00,0x00],#n,23#
'o':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00],#o,24#
'p':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1B,0x26,0x42,0x42,0x42,0x26,0x1A,0x02,0x07],#p,25#
'q':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x64,0x42,0x42,0x42,0x64,0x58,0x40,0xE0],#q,26#
'r':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x4C,0x04,0x04,0x04,0x04,0x1F,0x00,0x00],#r,27#
's':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x42,0x02,0x3C,0x40,0x42,0x3E,0x00,0x00],#s,28#
't':[0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x08,0x08,0x48,0x30,0x00,0x00],#t,29#
'u':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x42,0x42,0x42,0x42,0x62,0xDC,0x00,0x00],#u,30#
'v':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00],#v,31#
'w':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDB,0x91,0x52,0x5A,0x2A,0x24,0x24,0x00,0x00],#w,32#
'x':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x24,0x18,0x18,0x18,0x24,0x76,0x00,0x00],#x,33#
'y':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x18,0x18,0x08,0x08,0x06],#y,34#
'z':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x22,0x10,0x08,0x08,0x44,0x7E,0x00,0x00],#z,35#
'A':[0x00,0x00,0x00,0x08,0x08,0x18,0x14,0x14,0x24,0x3C,0x22,0x42,0x42,0xE7,0x00,0x00],#A,36#
'B':[0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x1E,0x22,0x42,0x42,0x42,0x22,0x1F,0x00,0x00],#B,37#
'C':[0x00,0x00,0x00,0x7C,0x42,0x42,0x01,0x01,0x01,0x01,0x01,0x42,0x22,0x1C,0x00,0x00],#C,38#
'D':[0x00,0x00,0x00,0x1F,0x22,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x22,0x1F,0x00,0x00],#D,39#
'E':[0x00,0x00,0x00,0x3F,0x42,0x12,0x12,0x1E,0x12,0x12,0x02,0x42,0x42,0x3F,0x00,0x00],#E,40#
'F':[0x00,0x00,0x00,0x3F,0x42,0x12,0x12,0x1E,0x12,0x12,0x02,0x02,0x02,0x07,0x00,0x00],#F,41#
'G':[0x00,0x00,0x00,0x3C,0x22,0x22,0x01,0x01,0x01,0x71,0x21,0x22,0x22,0x1C,0x00,0x00],#G,42#
'H':[0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0xE7,0x00,0x00],#H,43#
'I':[0x00,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00],#I,44#
'J':[0x00,0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x11,0x0F],#J,45#
'K':[0x00,0x00,0x00,0x77,0x22,0x12,0x0A,0x0E,0x0A,0x12,0x12,0x22,0x22,0x77,0x00,0x00],#K,46#
'L':[0x00,0x00,0x00,0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x42,0x7F,0x00,0x00],#L,47#
'M':[0x00,0x00,0x00,0x77,0x36,0x36,0x36,0x36,0x36,0x2A,0x2A,0x2A,0x2A,0x6B,0x00,0x00],#M,48#
'N':[0x00,0x00,0x00,0xE3,0x46,0x46,0x4A,0x4A,0x52,0x52,0x52,0x62,0x62,0x47,0x00,0x00],#N,49#
'O':[0x00,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x22,0x1C,0x00,0x00],#O,50#
'P':[0x00,0x00,0x00,0x3F,0x42,0x42,0x42,0x42,0x3E,0x02,0x02,0x02,0x02,0x07,0x00,0x00],#P,51#
'Q':[0x00,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x41,0x41,0x41,0x4D,0x32,0x1C,0x60,0x00],#Q,52#
'R':[0x00,0x00,0x00,0x3F,0x42,0x42,0x42,0x3E,0x12,0x12,0x22,0x22,0x42,0xC7,0x00,0x00],#R,53#
'S':[0x00,0x00,0x00,0x7C,0x42,0x42,0x02,0x04,0x18,0x20,0x40,0x42,0x42,0x3E,0x00,0x00],#S,54#
'T':[0x00,0x00,0x00,0x7F,0x49,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00],#T,55#
'U':[0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00],#U,56#
'V':[0x00,0x00,0x00,0xE7,0x42,0x42,0x22,0x24,0x24,0x14,0x14,0x18,0x08,0x08,0x00,0x00],#V,57#
'W':[0x00,0x00,0x00,0x6B,0x2A,0x2A,0x2A,0x2A,0x2A,0x36,0x14,0x14,0x14,0x14,0x00,0x00],#W,58#
'X':[0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x18,0x18,0x18,0x24,0x24,0x42,0xE7,0x00,0x00],#X,59#
'Y':[0x00,0x00,0x00,0x77,0x22,0x22,0x14,0x14,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00],#Y,60#
'Z':[0x00,0x00,0x00,0x7E,0x21,0x20,0x10,0x10,0x08,0x04,0x04,0x42,0x42,0x3F,0x00,0x00],#Z,61#
' ':[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]}# ,62#

main.py

from LCD import LCD
import machine 

machine.freq()          
machine.freq(160000000) 
lcd=LCD()
lcd.LCD_init()
lcd.LCD_FullColor(0,131,0,161,'white')
lcd.LCD_WriteString(20,20,'hello world','red')

然后颜色数据有以下三种,12位,16位,18位,这里使用的是16位。
在这里插入图片描述
ESP8266+MicroPython开发:ESP8266使用软件模拟SPI驱动TFT屏幕_第5张图片
关于这个16位颜色,如图所示其中前四位代表R,中间五位代表G,最后四位代表B,代码的RGB列表就是这样的,比如RGB=[0,0,0]就是黑色。

效果

ESP8266+MicroPython开发:ESP8266使用软件模拟SPI驱动TFT屏幕_第6张图片

工程文件

工程文件

你可能感兴趣的:(python,开发语言,嵌入式硬件,单片机)