树莓派 python 驱动 lcd tft spi 2.8寸 ili9341 240x320
1. 驱动效果
娃开车图
2. 屏幕及接线
屏幕我某宝直接购买的,价钱31.5
接线图:
3. python驱动代码
写的不严谨,但是能驱动,作为入门吧。详见注释
代码中,需要先解析图片的每个像素,再spi写入屏幕芯片。解析图片耗时挺长的,见日志输出:
pi@raspberrypi:~ $ python3 ili9341Driver.py
setWindow donw
picReadTimeConsuming = 6.100s , SpiTimeConsuming = 0.128s
具体代码见下:
# coding : UTF-8
import time #用于计算spi刷新整个屏幕所用时长
import RPi.GPIO as GPIO #用于操作引脚
import spidev #树莓派与屏幕的交互协议为SPI,说明见:https://github.com/doceme/py-spidev
from PIL import Image, ImageFont, ImageDraw #用于创建画布,或者读取具体路径下的图片。给图片添加文字。
screenWidth = 320 #屏幕长度
screenHeight = 240 #屏幕宽度
PinDC = 18 #GPIO.BOARD引脚模式,第18号引脚
PinReset = 22 #GPIO.BOARD引脚模式,第22号引脚
PinLED=12 #GPIO.BOARD引脚模式,第12号引脚
def LCDReset(): #重置电平时序
GPIO.output(PinReset, 1)
time.sleep(.2)
GPIO.output(PinReset, 0)
time.sleep(.2)
GPIO.output(PinReset, 1)
time.sleep(.2)
def sendCommand(command, *bytes): #发送指令(DC为低电平)和数据(DC为高电平)
GPIO.output(PinDC, 0)
spi.writebytes([command])
if len(bytes) > 0:
GPIO.output(PinDC, 1)
spi.writebytes(list(bytes))
def sendManyBytes(bytes): #发送屏幕数据
GPIO.output(PinDC, 1)
spi.writebytes(bytes)
def init(): #屏幕初始化
GPIO.output(PinLED, 1) #LED.high();
LCDReset()
sendCommand(0xEF,0x03,0x80,0x02);
sendCommand(0xCF,0x00,0XC1,0X30);
sendCommand(0xED,0x64,0x03,0X12,0X81);
sendCommand(0xE8,0x85,0x00,0x78);
sendCommand(0xCB,0x39,0x2C,0x00,0x34,0x02);
sendCommand(0xF7,0x20);
sendCommand(0xEA,0x00,0x00);
sendCommand(0xC0,0x23); # Power control --VRH[5:0]
sendCommand(0xC1,0x10); # Power control # SAP[2:0];BT[3:0]
sendCommand(0xC5,0x3e,0x28); # VCM control
sendCommand(0xC7,0x86); # VCM control2
sendCommand(0x36,0x48); # Memory Access Control
sendCommand(0x3A,0x55);
sendCommand(0xB1,0x00,0x18);
sendCommand(0xB6,0x08,0x82,0x27); # Display Function Control
sendCommand(0xF2,0x00); # 3Gamma Function Disable
sendCommand(0x26,0x01); # Gamma curve selected
sendCommand(0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,0x0E,0x09,0x00); # Set Gamma
sendCommand(0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,0x08,0x0F,0x0C,0x31,0x36,0x0F); # Set Gamma
sendCommand(0x11); # Exit Sleep
sendCommand(0x29); # Display on
def setWindow():
sendCommand(0x2A); # Column addr set
x0 = 0;
bytes = []
bytes.append(x0 >> 8)
bytes.append(x0)
sendManyBytes(bytes); # XSTART
x1 = screenHeight - 1;
bytes = []
bytes.append(x1 >> 8)
bytes.append(x1)
sendManyBytes(bytes); # XEND
sendCommand(0x2B); # Row addr set
bytes = []
bytes.append(0 >> 8)
bytes.append(0)
sendManyBytes(bytes); # YSTART
y1 = screenWidth - 1;
bytes = []
bytes.append(y1 >> 8)
bytes.append(y1)
sendManyBytes(bytes); # YEND
sendCommand(0x2C);
print('setWindow donw')
def drawImg16BitColor(img320x240): #入参为320x240像素的image对象
init()
setWindow();
bytes = []
i = 0;
GPIO.output(PinDC, 1)
picReadStartTime = time.time()
for x in range(0, screenWidth):
for y in range(screenHeight - 1, -1, -1):
colorValue = img320x240.getpixel((x, y))
red = colorValue[0]
green = colorValue[1]
blue = colorValue[2]
red = red >> 3; # st7735s的红色占5位
green = green >> 2; # st7735s的绿色占6位
blue = blue >> 3; # st7735s的蓝色占5位
highBit = 0 | (red << 3) | (green >> 3); # 每个像素写入个字节,highBit高字节,lowBit低字节
lowBit = 0 | (green << 5) | blue;
bytes.append(highBit)
bytes.append(lowBit)
picReadTimeConsuming = time.time() - picReadStartTime #解析图像像素时长
startTime = time.time()
# screenWidth*screenHeight*2 每个像素写入2个字节。
#以下for循环是为了控制每次传入的数组长度,防止这个报错,:OverflowError: Argument list size exceeds 4096 bytes.
for j in range(2000, screenWidth * screenHeight * 2, 2000):
sendManyBytes(bytes[i:j])
i = i + 2000
sendManyBytes(bytes[i:screenWidth * screenHeight * 2])
SpiTimeConsuming = time.time() - startTime #Spi写入像素数据时长
print("picReadTimeConsuming = %.3fs , SpiTimeConsuming = %.3fs" % (picReadTimeConsuming, SpiTimeConsuming))
GPIO.setmode(GPIO.BOARD) #设置GPIO.BOARD引脚模式
GPIO.setwarnings(False)
GPIO.setup(PinDC, GPIO.OUT)
GPIO.setup(PinReset, GPIO.OUT)
GPIO.setup(PinLED, GPIO.OUT)
spi = spidev.SpiDev() #https://github.com/doceme/py-spidev
spi.open(0, 0)
spi.max_speed_hz = 24000000 #通信时钟最大频率
spi.mode = 0x00 #SPI的模式,9341为模式spi0
image = Image.new('RGB', (screenWidth, screenHeight)) #可以使用代码新建画布
draw = ImageDraw.Draw(image)
setFont = ImageFont.truetype("/usr/share/fonts/myfont/MSYHBD.TTF", 32) #字体地址,请参考我这篇内容:https://blog.csdn.net/chenqide163/article/details/106933858
draw.text((35, 0), "离思", font=setFont, fill="#FFA500", direction=None)
setFont = ImageFont.truetype("/usr/share/fonts/myfont/MSYHBD.TTF", 16)
draw.text((105, 15), "元稹", font=setFont, fill="#00FFFF", direction=None)
setFont = ImageFont.truetype("/usr/share/fonts/myfont/MSYHBD.TTF", 20)
draw.text((0, 35), "曾经沧海难为水,", font=setFont, fill="#FFFF00", direction=None)
draw.text((0, 60), "除却巫山不是云。", font=setFont, fill="#FFFF00", direction=None)
draw.text((0, 85), "取次花丛懒回顾,", font=setFont, fill="#FFFF00", direction=None)
draw.text((0, 110), "半缘修道半缘君。", font=setFont, fill="#FFFF00", direction=None)
#也可以从地址读取图片文件,并缩放为320x240
image = Image.open('/home/pi/test.jpg');
image = image.convert('RGBA');
image = image.resize((screenWidth, screenHeight)) #也可以从地址读取图片文件,并缩放为160x128
drawImg16BitColor(image)