本系列将驱动一块1.44"的128x128像素的彩色液晶屏幕。
并分几个篇幅分别讲述如何使其显示色块,英文数字,汉字以及图片。
本文是系列的第一篇,目标是点亮屏幕并显示指定色块。
最终效果
硬件
- 1.44英寸 spi接口 128x128液晶屏幕 X 1(淘宝10-20元)
先上代码看效果
这次直接上代码,大家自己复制代码保存为py文件。文件名无所谓。
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
cs=23 # 片选
rs=17 # 数据 / 命令 切换
sda=13 # 数据
scl=19 # 时钟
reset=27 # 复位
# 传输byte
def setByteData(data):
# print ""
# print "S-----------setByte---------------:", hex(data)
for bit in range(0,8):
# 传入的数字从高位到低位依次判断是否为1,若为1则设置高电平,否则设置低电平
# 判断的方法是先向左移位,把要判断的位移动到最高位然后跟0x80(1000 0000)相与,
# 如果结果仍然是0x80(1000 0000)就表示最高位是1,否则最高位就是0
if ((data<<bit) & 0x80 == 0x80):
setBitData(True)
# print "1",
else:
setBitData(False)
# print "0",
# print ""
# print "E-----------setByte---------------"
def setBitData(data):
GPIO.output(scl, False)
GPIO.output(sda, data)
GPIO.output(scl, True)
def write_command(cmd):
GPIO.output(cs, False)
GPIO.output(rs, False)
setByteData(cmd)
GPIO.output(cs, True)
def write_data(data):
GPIO.output(cs, False)
GPIO.output(rs, True)
setByteData(data)
GPIO.output(cs, True)
def write_data_16bit(dataH, dataL):
write_data(dataH)
write_data(dataL)
def lcd_reset():
GPIO.output(reset, False)
time.sleep(0.1)
GPIO.output(reset, True)
time.sleep(0.1)
def lcd_init():
lcd_reset()
write_command(0x11) # Exit Sleep
time.sleep(0.02)
write_command(0x26) # Set Default Gamma
write_data(0x04)
write_command(0xB1)# Set Frame Rate
write_data(0x0e)
write_data(0x10)
write_command(0xC0) # Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD
write_data(0x08)
write_data(0x00)
write_command(0xC1) # Set BT[2:0] for AVDD & VCL & VGH & VGL
write_data(0x05)
write_command(0xC5) # Set VMH[6:0] & VML[6:0] for VOMH & VCOML
write_data(0x38)
write_data(0x40)
write_command(0x3a) # Set Color Format
write_data(0x05)
write_command(0x36) # RGB
write_data(0xc8)
write_command(0x2A) # Set Column Address
write_data(0x00)
write_data(0x00)
write_data(0x00)
write_data(0x7F)
write_command(0x2B) # Set Page Address
write_data(0x00)
write_data(0x00)
write_data(0x00)
write_data(0x7F)
write_command(0xB4)
write_data(0x00)
write_command(0xf2) # Enable Gamma bit
write_data(0x01)
write_command(0xE0)
write_data(0x3f)# p1
write_data(0x22)# p2
write_data(0x20)# p3
write_data(0x30)# p4
write_data(0x29)# p5
write_data(0x0c)# p6
write_data(0x4e)# p7
write_data(0xb7)# p8
write_data(0x3c)# p9
write_data(0x19)# p10
write_data(0x22)# p11
write_data(0x1e)# p12
write_data(0x02)# p13
write_data(0x01)# p14
write_data(0x00)# p15
write_command(0xE1)
write_data(0x00)# p1
write_data(0x1b)# p2
write_data(0x1f)# p3
write_data(0x0f)# p4
write_data(0x16)# p5
write_data(0x13)# p6
write_data(0x31)# p7
write_data(0x84)# p8
write_data(0x43)# p9
write_data(0x06)# p10
write_data(0x1d)# p11
write_data(0x21)# p12
write_data(0x3d)# p13
write_data(0x3e)# p14
write_data(0x3f)# p15
write_command(0x29) # Display On
write_command(0x2C)
def show_single_color(DH,DL):
for i in xrange(0,128):
for j in xrange(0,128):
write_data_16bit(DH,DL)
try:
GPIO.setmode(GPIO.BCM)
GPIO.setup(cs, GPIO.OUT)
GPIO.setup(rs, GPIO.OUT)
GPIO.setup(sda, GPIO.OUT)
GPIO.setup(scl, GPIO.OUT)
GPIO.setup(reset, GPIO.OUT)
lcd_init()
write_command(0x2C)
show_single_color(0xf8,0x00) # 红色背景
while True:
pass
except KeyboardInterrupt:
pass
# 清理GPIO口
GPIO.cleanup()
然后,按下表连接液晶屏和树莓派。(连接完以后屏幕应该是白屏状态)
液晶屏 | 树莓派 |
---|---|
LCD | 3.3V 或 5V均可,建议串一个100-330欧电阻 |
SCK | GPIO19 |
SDA | GPIO13 |
AO | GPIO17 |
RESET | GPIO27 |
CS | GPIO23 |
GND | GND |
VCC | 3.3V(不可以是5V!!) |
然后,执行!
sudo python prog.py
不出意外,你应该能看到屏幕被慢慢地扫描刷新成红屏了!!!
原理说明
想要跟硬件通信,给硬件发送指令,首先要搞清楚硬件的通信协议。
对于屏幕来说,其通信协议是由屏幕的主控IC芯片决定的,不同的主控IC芯片有不同的通信协议,也就是发送指令的方法。
不过,即使是不同的屏幕,也有可能使用同一款(或同系列)主控IC。
所以拿到一块屏幕首先要搞清楚这块屏幕使用的是哪种主控IC,谷歌,百度都可以,最方便的是问卖家。。。
本文使用的屏幕的主控IC是ST7735S,文末提供数据手册下载。
简单来说,通过SDA数据引脚和SCLK时钟引脚串行输入(从第一篇学习过来的一定不陌生)不同的指令数据就可以控制屏幕的输出。
指令数据分成两种,指令种类数据和指令内容数据。每次发送指令都是先发送指令种类再发送指令内容。
有点拗口,比如说我告诉屏幕“接下来我要改变屏幕颜色啦”,接着你发送了一串数字,硬件接收到这串数字后会作为一个颜色值应用在屏幕上。如果你告诉屏幕“接下来我要改变屏幕的亮度啦”,接着你又发送了一串数字,这次硬件接收到这一串数字后会作为亮度值应用在屏幕上。这么说你再不明白我就。。。。
再回过头来看代码:
def write_command(cmd):
GPIO.output(cs, False)
GPIO.output(rs, False)
setByteData(cmd)
GPIO.output(cs, True)
def write_data(data):
GPIO.output(cs, False)
GPIO.output(rs, True)
setByteData(data)
GPIO.output(cs, True)
上面这两个函数,一个用来发送指令种类,一个用来发送指令内容。区别仅仅在于rs引脚的电平高低不同。
另外,屏幕初始化函数lcd_init()里有一堆命令,天书一般,光是看就晕了。
别晕,这些代码大多只用执行一遍,最开始不必关心,照葫芦画瓢即可。
下面是你需要注意的关键指令种类和内容:
- 0x2A:指定绘图指针的列起始和结束地址(X坐标范围)
指令内容是4个字节的32位数据,从高位到低位分别是
起始X坐标高8位
起始X坐标低8位
结束X坐标高8位
结束X坐标低8位 - 0x2B:指定绘图指针的行起始和结束地址(Y坐标范围)
指令内容是4个字节的32位数据,从高位到低位分别是
起始Y坐标高8位
起始Y坐标低8位
结束Y坐标高8位
结束Y坐标低8位
下面的代码设定的范围是(0,0)-(127, 127),也就是全屏幕。
write_command(0x2A) # Set Column Address
write_data(0x00)
write_data(0x00)
write_data(0x00)
write_data(0x7F)
write_command(0x2B) # Set Page Address
write_data(0x00)
write_data(0x00)
write_data(0x00)
write_data(0x7F)
0x2C:在当前指针位置(X,Y坐标)绘制指定颜色的像素点
指令内容是2个字节的颜色数据。
每次执行完一个像素点的绘色以后,硬件会根据设定好的开始坐标和结束坐标自动移动绘图指针到下一个位置,遇到边界自动换行。
下面的代码的意义是连续绘制128 X 128个像素点,并且颜色为红色(#0xF800)。write_command(0x2C) show_single_color(0xf8,0x00) # 红色背景 ... ... def show_single_color(DH,DL): for i in xrange(0,128): for j in xrange(0,128): write_data_16bit(DH,DL)
这就是本文示例代码显示红屏的原理。
其实只要学会了这3个命令的使用,基本上啥都能显示了,无非是效率问题。给大家留个作业,自己完成本文开头的最终效果彩带。
本节到此结束,下一节我们继续讨论。
关于颜色的补充说明
有人问博主0xF800是什么鬼?红色难道不应该是0xFF0000吗?
这里就引出一个RGB颜色数据格式的问题,0xF800和0xFF0000都是红色,只是格式不一样。
我们常见的0xFF0000这种格式一共是24位,红绿蓝各用8位表示,所以红色就是FF,00,00。
而本文使用的是另一种叫RGB565的格式,这种格式一共只有16位,红绿蓝分别使用5位6位5位。
根据上图,红色应该是11111000 00000000,也就是0xF800。
其实,这款彩屏支持以下3种颜色格式
4k Colors, RGB 4,4,4
3AH=“03h”write_command(0x3a) write_data(0x03)
65k Colors, RGB 5,6,5
3AH=“05h”(本文使用的格式)write_command(0x3a) write_data(0x05)
262k Colors, RGB 6,6,6
3AH=“06h”write_command(0x3a) write_data(0x06)
详细内容请自己参考文档(9.8 Data Color Coding)。
资源下载
系列文章
- 树莓派GPIO入门01-使用GPIO接口控制发光二极管闪烁
- 树莓派GPIO入门02-GPIO控制LED亮度,制作呼吸灯效果
- 树莓派GPIO入门03-GPIO控制RGB彩色LED灯
- 树莓派GPIO入门04-使用按钮
- 树莓派GPIO入门05-驱动数码管显示数字
- 树莓派GPIO入门06-跟数字湿温度计DHT11通信
- 树莓派GPIO入门07-利用声音传感器制作声控灯
- 树莓派GPIO入门08-使用74HC595芯片驱动数码管(一)
- 树莓派GPIO入门08-使用74HC595芯片驱动数码管(二)
- 树莓派GPIO入门09-使用MAX7219芯片驱动8位数码管
- 树莓派GPIO入门10-使用TLC5940芯片输出多路PWM
- 树莓派GPIO入门11-驱动液晶屏幕(一)【当前文章】
- 树莓派GPIO入门11-驱动液晶屏幕(二)
16 comments
学习了
博主我想问一下,高8位和低8位是什么意思
把一个数写成2进制,右边是低位左边为高位,低8位就是右边的8位二进制数,反之就是高8位,这样说你能明白吗
博主,树莓派需要开启spi吗?好像只是用到gpio口
不需要的,我是用io模拟spi 的,如果你觉得速度不够快可以打开spi 用硬件spi ,这样程序也要相应改动。
怎么使用硬件的spi呢,是用github上的fbtft吗?
引用一个spi库
import spidev
然后用spi.xfer2()函数发送数据。硬件上要接树莓派的spi用的几个引脚,你去翻一下引脚定义。
记得应该是
MOSI,替代原来的sda=13
SPICLK,替代原来的scl=19
然后,树莓派默认的spi设备是被关闭的要打开一下,百度一下方法就行了。
谢谢,这个可以了
博主,还有一个问题,就是我的屏幕是128*128的,但是我用你的测试代码测试,屏幕右边和下面还是用好像花屏的
那你的屏幕可能不是128*128的吧,花屏表示那个像素上的颜色数据没有被设置,是随机的,看上去就是花屏。试试把程序里下面两句里的128 改大一点看看有什么变化。
for i in xrange(0, 128 )
for j in xrange(0, 128 )
好像是设置绘制范围的时候是128*128,然后右边和下面就花屏,好像只有把起始的x和y坐标设置大一点,不要是(0,0)就可以,不知道什么问题
这个比较怪,你可以试试将开始坐标跟结束坐标改成现在花屏那一块的坐标画一个小矩形看看行不行
感谢博主,关注了!
楼主,我也有一个1.44的跟你这一个同样的主控芯片,他上面的引脚是BLK,RS,RST,CS,SC,DI,GND,VCC,请问跟树莓派的哪些引脚相连接啊?
BLK应该相当于LCD,是背光灯引脚,你可以试试接3V电源是不是屏幕就亮了,如果是就没错了。
我猜测应该是这样,供参考。
液晶屏 |树莓派
----------|----------------------------
BLK |3.3V
SC |GPIO19
DI |GPIO13
RS |GPIO17
RST |GPIO27
CS |GPIO23
GND |GND
VCC |3.3V