基于ESP32的2.8寸彩屏驱动

作者:刘依哲    发布于:

前期准备

这快2.8寸TFT彩屏是从淘宝买的,分辨率320*240 驱动是ILI9341 接口是SPI,网上找到了32上跑的驱动代码,但是并没有找到ESP的驱动代码,准备自己写一个ESP32使用的ILI9341驱动和一些简单的画图接口

屏幕初始化

这个比较容易实现,现在已经有基于stm32的屏幕驱动,可以直接将C代码用python语法重写一遍即可

#——————————–初始化即底层代码(部分)——————————————–#
def init(self, spi, cs, dc, rst, w, h, r):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.init_width = w
self.init_height = h
self.width = w
self.height = h
self.rotation = r
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.reset()
self.init()
……………………………………….
def reset(self):
self.rst(0)
time.sleep_ms(50)
self.rst(1)
time.sleep_ms(50)
#写数据
def data(self, data):
self.dc(1)
self.cs(0)
self.spi.write(data)
self.cs(1)
#写命令
def command(self, command):
self.dc(0)
self.cs(0)
self.spi.write(bytearray([command]))
self.cs(1)
#写入块
def writeblock(self, x0, y0, x1, y1):
self.command(CASET)# 列地址设置
self.data(struct.pack(“>HH”, x0, x1))
self.command(PASET)# 页地址设置
self.data(struct.pack(“>HH”, y0, y1))
self.command(RAMWR)# 内存写入
#读取块,返回
def readblock(self, x0, y0, x1, y1):
self.command(CASET)# 列地址设置
self.data(struct.pack(“>HH”, x0, x1))
self.command(PASET)# 页地址设置
self.data(struct.pack(“>HH”, y0, y1))
self.command(RAMRD)# 内存读出
data = self.spi.read((x1 - x0 + 1) * (y1 - y0 + 1) * 3)
return data
#———————————————————————————————#

添加基本绘图接口

利用micro python固件提供的FrameBuffer类,重写该类方法,可以大大节省时间,在ESP内存中创建一个缓冲区,将要写入显存的数据先写入FrameBuffer,最终在show方法中将缓冲区数据通过SPI写入显存
注意!这块2.8寸屏的分辨率为320240,而且数据格式为RGB565,即一个像素点需要16个bit,共需要320240*16bit空间,对于ESP32肯定不能一次性写入显存(内存不足),应该多创建几次FrameBuffer分批写入比较合理

1.画点
def pixel(self,x,y,c = 0xffff):
    self.getbuffer(x,y,1,1)
    self.fb.pixel(0,0,c)    
2.画线
def line(self,x1,y1,x2,y2,c = 0xffff):
    w = x2-x1
    h = y2-y1
    self.getbuffer(x1,y1,w,h)
    self.fb.line(0,0,w,h,c)
    self.show()
3.画矩形
def rect(self,x,y,w,h,c = 0xffff):
    self.getbuffer(x,y,w,h)
    self.fb.rect(0,0,w,h,c)
    self.show()
4.填充、擦除、斜线等绘图接口

详见个人github

添加高级绘图接口
1.显示图片
#---------------------------------实现图片(数组)显示由SD卡或网络传输--------------------------------#
#x,y图片起始显示位置
#pic_w,pic_h图片宽高
#图片文件的路径
def bitmap(self,x,y,pic_w,pic_h,file_name):
    lines = 6
    block = pic_w * lines * 2
    nums = (pic_w * pic_h * 2) // block
    with open(file_name,'rb') as fio:
      for v in range(nums):
        self.getbuffer(x ,y+v*lines, pic_w ,lines)
        self.buf = fio.read(block)
        self.show()
#实现网络传输图片
def bitmap_net(self,sock):
    lines = 6
    x = int(sock.recv(10))
    sock.send(b's')
    y = int(sock.recv(10))
    sock.send(b's')
    pic_w = int(sock.recv(10))
    sock.send(b's')
    pic_h = int(sock.recv(10))
    sock.send(b's')
    block = pic_w * lines * 2
    nums = (pic_w * pic_h * 2) // block
    for v in range(nums):
      self.getbuffer(x ,y+v*lines, pic_w ,lines)
      self.buf = sock.recv(block)
      self.show()
      time.sleep_ms(100)#延时等待刷新
#---------------------------------------------------------------------------------------------#
2.显示字符
#--------------------------------字符输入自动换行支持所有字符的输入--------------------------------#        

#功能:传入黑白字库文件,支持自定义字体颜色,速度较慢

def print(self,str,xstart,ystart,fg = 0xffff,bg = 0x0000,font_path="/sd/utf16.zk",size=16):
    def hex2bin(g):#将传入的颜色转为字节串
      s = hex(g).replace("0x","")
      while len(s)<4:s = '0' + s#补全为四位
      return bytearray([int(s[0:2],16),int(s[2:4],16)])
    _fg = hex2bin(fg)    #前景色
    _bg = hex2bin(bg)    #背景色
    pos_y = ystart
    charbytes = int((size**2)/8)#一个字符的所占的字节数,是跳转字库指针的最小单位 
    n = -1#字符计数器,表示当前显示的字符

    max = int(240/size)-1
    with open(font_path,'rb') as f:#打开字库
      for c in str:#分割字符串为字符
        n = n + 1
        v = 0#写入buf的计数器,每显示一个字符清零
        f.seek(ord(c)*charbytes)#跳转到字符c的位置
        chr_num = f.read(charbytes)#读取字符c,返回此字符对应的点阵数据
        pos_x = xstart + size * n #y的位置为起始值加上n个字符size

        if pos_x >= 240 - 1.1 * size:#如果当前超出行
          pos_y = pos_y + size#y位置向下偏移一个size<换行>
          pos_x = xstart
          n = -1
        self.getbuffer(pos_x,pos_y,size,size)#每次显示一个字符
        for byte in chr_num:#分割一个字符点阵数据为字节,并将整个字符入self.buf等待显示
          x = bin(byte).replace('0b','')

          while len(x)<8:#补全为8位
            x = '0' + x
          for r in x:#将黑白字符转为彩色字符放在self.buf中
            if r == '0':
              self.buf[0+2*v:2+2*v] = _bg
            else:
              self.buf[0+2*v:2+2*v] = _fg
            v = v + 1
        self.show()#显示一个字符

#功能:直接传入转化好的RGB565字库,不可改颜色,但速度更快    

def printf(self,str,xstart,ystart,font_path="/sd/utf16.fzk",size=16):
    charbytes = int((size**2)*2)#一个字符的所占的字节数,是跳转字库指针的最小单位 
    n = -1
    pos_y = ystart
    max = int(240/size)-1
    with open(font_path,'rb') as f:#打开字库
      for c in str:#分割字符串为字符
        n = n + 1
        pos_x = xstart + size * n #y的位置为起始值加上n个字符size
        if pos_x >= 240 - 1.1 * size:#如果当前y位置超出屏幕
          pos_y = pos_y + size#x位置向下偏移一个size<换行>
          pos_x = xstart
          n = -1
        self.getbuffer(pos_x,pos_y,size,size)#每次显示一个字符
        f.seek(ord(c)*charbytes)#跳转到字符c的位置
        self.buf = f.read(charbytes)#读取字符c,返回此字符对应的点阵数据
        self.show()#显示一个字符
#---------------------------------------------------------------------------------------------#

字库文件通过取模软件生成,并将其格式处理为RGB65 存于内存卡中
实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
old = r'C:\Users\liu\Desktop\22.DZK'
new = r'C:\Users\liu\Desktop\utf.zk'
with open(old,'rb') as fd:
with open(new,'wb') as f:
while True:
a = fd.read(32)
for w in a:
flag = 1
x = bin(w).replace('0b','')
while len(x)<8:
x = '0' + x
for r in x:
if r == '0':
f.write(b'\x00\x00')
else:
f.write(b'\xff\xff')
最终效果

alt 文本

format_list_numbered

(无)

  1. 1. 前期准备
  2. 2. 屏幕初始化
  3. 3. 添加基本绘图接口
    1. 3.1. 1.画点
    2. 3.2. 2.画线
    3. 3.3. 3.画矩形
    4. 3.4. 4.填充、擦除、斜线等绘图接口
  4. 4. 添加高级绘图接口
    1. 4.1. 1.显示图片
    2. 4.2. 2.显示字符
  5. 5. 最终效果
vertical_align_top

Copyright © 2017 欢迎来到我的博客

Powered by Hexo && Theme - Vateral