欢迎来真孝善网,为您提供真孝善正能量书籍故事!

树莓派基础实验教程:29 - I2C接口LCD1602显示屏实战

时间:11-14 现代故事 提交错误

各位老铁们,大家好,今天由我来为大家分享树莓派基础实验教程:29 - I2C接口LCD1602显示屏实战,以及的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

I2C总线是PHLIPS公司发明的串行总线。它是一种高性能串行总线,具有多主机系统所需的总线控制和高速或低速设备同步功能。 I2C LCD1602上的蓝色电位器用于调节背光以获得更好的显示效果。 I2C 使用两条双向开漏线,串行数据线(SDA)和串行时钟线(SCL),通过电阻上拉。使用的典型电压为5V 或3.3V,但允许使用其他电压的系统。

其他I2C总线实验可以查看之前的PCF8591相关实验,例如:

树莓派基础实验12:PCF8591模数转换器实验

二、组件

树莓派主板*1

树莓派电源*1

40P软线*1

I2C LCD1602模块*1

面包板*1

一些毛衣

三、实验原理

LCD1602 正面LCD1602 背面LCD1602 电路图Raspberry Pi 的GPIO 端口数量有限。通过IO扩展芯片可以增加GPIO的数量,使Raspberry Pi能够适应更多的应用。本实验中的LCD1602模块有16个引脚。为了节省GPIO口,采用了通过I2C总线扩展IO的芯片PCF8574。单个PCF8574可以扩展8个IO,一条I2C总线最多可以挂载8个PCF8574,因此树莓派最多可以扩展64个IO。

本实验中的编程原理比较复杂,因此必须将程序和硬件原理结合起来,以便于理解。如果不想深入学习底层原理和驱动,掌握LCD1602的功能就可以了。但如果想灵活使用LCD1602,最好还是了解一下。

本文是在网上查阅大量中外资料,集众多大师智慧后编写而成。花了10天时间(当然我还是要每天上班)才编译完成。不过,还有很多不明白的地方,还有很多错误,尤其是程序的一部分。哪里有长长的一串“?”评论请留言指出!

3.1 LCD1602的存储器

LCD1602中有三种类型的存储器:CGROM、CGRAM和DDRAM。

DDRAM(Display Data RAM)是显示数据RAM,用于存储要显示的字符代码。总共80个字节,地址与屏幕的对应关系如下,如图:

数据地址与屏幕的对应关系DDRAM实际上就是我们通常所说的PC的显存。如果我们想在屏幕上显示我们想要显示的内容,只需要将需要的字符代码直接发送到显存中即可。这很简单。能够在屏幕上显示我们想要的内容。同样的LCD1602总共有80字节的显存,也就是DDRAM。不幸的是,LCD1602 无法显示这么多字符。因此,并不是写入DDRAM 的每个字符都能显示在显示器上,一次只能显示16 个字符。正因为如此,我们可以在程序中使用下面的“光标或显示移动命令”,将字符慢慢移动到可见的显示范围内,看看字符的移动效果。

那么如何在LCD上显示字符就是把要写入的字符给DDRAM。比如我要在屏幕上显示“A”,我就把我想要的字符“A”的字符代码41H写入DDRAM地址00H中并获取。那么我们应该怎么写呢?稍后我们会进一步阐述。下面我们要介绍的是A字体,如图:

上图左侧显示“A”的字体数据。上图右侧显示“A”的字体数据。 “”代表0,“”代表1。这样我们就可以显示字形“A”。

LCD1602模块具有固化字体存储器,即CGROM和CGRAM。 HD44780内置了192种常用的字符字体,存储在字符发生器CGROM(Character Generator ROM)中。还有8 个用户定义的字符生成RAM。称为CGRAM(Character Generator RAM),只剩下8个地址可供定制,即最多8个定制符号或图形。

下图(字体表)说明了CGROM和CGRAM与字符的对应关系。从ROM和RAM的名称我们还可以知道,ROM已经固化在LCD1602模块中,只能读取;但RAM可以读写。

字体表如果只需要在屏幕上显示CGROM中已有的字符,则只需将其字符代码写入DDRAM即可;如果要显示CGROM中不存在的字符,比如美元符号,那么我们只能先在CGRAM中指定,然后下一步将我们之前定义的字符写入DDRAM中。

字形和光标

上图展示了58点阵和510点阵字符的字形和光标位置。这里我们使用的是58的点阵,所以定义这样一个字符需要8个字节,并且每个字节的前3位没有被使用。

设置CGRAM地址指令上图说明了设置CGRAM地址指令。从这条指令的格式我们可以看出,它有6位aaaaaa,总共可以表示64个地址,即64个字节。一个58点阵字符总共占用8个字节,因此这64个字节可以定制为总共8个字符。也就是说,上图中6位地址中的DB5DB4DB3用于表示8个自定义字符,DB2DB1DB0用于表示每个字符8个字节。 DB5DB4DB3代表的8个自定义字符(0--7)是要写入DDRAM的字符代码。

3.2 管脚

LCD1602配备I2C适配器版本,可同时显示16x02或32个字符。 (16列2行)1602字符液晶屏通常有16针线液晶屏:

引脚 符号 功能说明1VSS 一般接地2VDD 接电源(+5V) 3V0 晶显对比度调节端,接正电源时对比度最弱,接正电源时对比度最高电源接地(对比度太高时会产生“重影”,可以通过10K电位器调整对比度)。 4RSRS 为寄存器选择,高电平(1)时选择数据寄存器、低电平(0)时选择指令寄存器。5R/WR/W 为读写选择,高电平(1)时进行读操作,低电平(0)时进行写操作。6EE(或EN)端为使能(enable)端,写操作时,下降沿使能。读操作时,E高电平有效7DB0 低4 位三态,双向数据总线0 位(最低位) 8DB1 低4 位三态, 双向数据总线1 位9DB2 低4 位三态, 双向数据总线2 位10DB3 低4 位三态,双向数据总线3 位11DB4 高4 位三态,双向数据总线4 位12DB5 高4 位三态,双向数据总线5 位13DB6 高4 位三态,双向数据总线6 位14DB7 高4 位三态,双向数据总线7 位(最高位)(还有忙标志) 15BLA 背光电源正极16BLK 背光电源负极

3.3 LCD1602的基本操作及时序

该系列模块内部有两个8 位寄存器:指令寄存器(IR)和数据寄存器(DR)。用户可以通过RS和R/W输入信号的组合选择指定的寄存器来执行相应的操作。组合选择选项如下表所示:

RSR/W 操作指令00 写入命令寄存器(清屏等) 01 读取忙标志(DB7),读取地址计数器(DB0~DB6)值10 写入数据寄存器(显示各字体等) ) 11 从机数据寄存器读取数据的基本操作LCD1602 :

1. 读取状态:输入RS=0,RW=1,E=高脉冲。输出:D0-D7 是状态字。

2. 读取数据:输入RS=1,RW=1,E=高脉冲。输出:D0-D7为数据。

3、写命令:输入RS=0,RW=0,E=高脉冲。输出:无。 (写入后,设置E=高脉冲)

4、写数据:输入RS=1,RW=0,E=高脉冲。输出:无。

注:E(或EN)端子为使能端子,在写操作期间的下降沿使能。读操作期间,E高电平有效。

读操作时序图:

读操作时序图写操作时序图:

写操作时序图时序参数:

定时时间参数

3.4 LCD1602的指令说明

1602液晶模块内部的控制器共有11条控制指令:

LCD1602控制命令表1602液晶模块读写操作、屏幕及光标操作均通过指令编程实现。

指令1:清除显示,命令码01H,光标复位到地址00H。

说明:清除屏幕显示内容。光标返回到屏幕的左上角。执行该命令需要一定的时间。

指令2:光标复位,光标返回地址00H。

说明:光标返回屏幕左上角,不改变屏幕显示内容。

指令3:光标和显示模式设置

进入模式设置命令I/D=1:写入新数据后,光标向右移动。

I/D=0:写入新数据后光标向左移动。

S=1:显示移动。

S=0:显示器不移动。

说明:这里的设置是0x06。

指令4:显示开关控制。

显示开关控制指令D=1:显示开,D=0:显示关。

C=1:显示光标,C=0:不显示光标。

B=1:光标闪烁,B=0:光标不闪烁。

注:此处设置为显示开启,不显示光标,光标不闪烁,设置字为0x0c。

指令5:光标或显示移位

光标或显示移动指令

光标或显示移动命令说明:当需要移动整个屏幕时,该命令非常有用,可以实现屏幕上的滚动显示效果。初始化期间不使用该指令。

指令6:功能设定指令

工作模式设置命令:无关,也就是说该位可以是0也可以是1,通常为0。

DL:设置数据接口位数。

DL=1:8位数据接口(D7-D0)。

DL=0:4位数据接口(D7-D4)。

N=0:显示一行。

N=1:显示两行。

F=0:58点阵字符。

F=1:510点阵字符。

注:由于写入指令字,RS、RW 均为0。LCD1602 只能以并行方式驱动,不能以串行方式驱动。在并行模式下,可以选择8位数据接口或4位数据接口。这里我们选择4位数据接口(D3-D0)。我们的设置是4位数据接口,两行显示,58点阵,即0b00101000或0x28。 (注:NF为10或11的效果是一样的,都是两行58点阵。因为不能在两行510点阵中显示,也就是说,这里使用0x28或0x2c是相同的)。

指令7:字符发生器CGRAM 地址设置。

设置CGRAM地址命令指令8:DDRAM地址设置。

设置DDRAM 地址命令说明: 该命令用于设置DDRAM 地址。在读写DDRAM之前,必须先设置DDRAM地址,然后才能进行读写。我们之前说过,DDRAM是LCD1602的显示内存。如果我们要显示它,我们必须将要显示的字符写入DDRAM中。同样,如果我们想知道DDRAM中某个地址上有哪些字符,我们必须先设置DDRAM地址,然后将其读出给单片机。

指令9:读取忙信号和光标地址

读忙信号和地址计数器ACBF:忙标志位。高电平表示忙。此时模块无法接收命令或数据。如果较低,则表示不忙。

说明: 该命令用于读取LCD1602的状态。对于微控制器来说,LCD1602 是一个速度较慢的设备。当单片机向它发送指令时,它就会执行该指令。此时,如果单片机再次发送下一条指令,由于LCD1602速度较慢,且上一条指令尚未完成,因此不会接受新指令,导致新指令丢失。因此,可以通过这个读忙命令来判断LCD1602是否忙以及是否可以接收单片机的指令。当BF=1时,表示LCD1602正忙,无法接受单片机的指令;当BF=0时,表示LCD1602空闲,可以接收单片机的指令。 RS=0表示命令; RW=1表示读。这条指令还有一个副产品:它可以获得地址计数器AC(地址计数器)的值。 LCD1602维护一个地址计数器AC来记录下一次读或写到CGRAM或DDRAM的位置。需要强调的是:我从来没有成功执行过这条指令。很多网友似乎也是这样。幸运的是,我们还有另一个办法,那就是延迟。通过查看每条指令的执行时间,并经过一些实验,可以确定指令延迟。这样,上一条指令执行完后,才能执行下一条指令。

指令10:写入数据。

将数据写入CGRAM 或DDRAM 指令

说明:RS=1,数据; RW=0,写入。执行该指令时,必须先将要写入的数据设置到DB7-DB0,然后再执行写命令。

指令11:读取数据。

从CGRAM 或DDRAM 读取数据指令

说明:RS=1,数据; RW=1,读取。首先设置CGRAM或DDRAM的地址,然后执行读命令。数据被读入DB7-DB0。

3.5 初始化

如果电路供电能够满足内部RESET电路的以下要求,则可以自动完成初始化:

自动初始化如果电路供电不能满足内部RESET电路的要求,则需要使用初始化程序来实现初始化。有两种模式:8位总线和4位总线。

8位数据传输模式:

8位总线模式初始化本实验采用4位数据传输模式:

4 位总线初始化参数示例

3.6 DDRAM地址

1602 个字符的LCD 显示屏可分为上下两部分,各16 位显示。不同行的字符显示地址如下:

显示字符1234.1213141516 地址第一行00H01H02H03H.0BH0CH0DH0EH0FH 地址第二行40H41H42H43H.4BH4CH4DH4EH4FH如上面的指令8格式所示,由于地址是7 位,在写入地址时,第8位D7始终为1。当我们要在指定位置写入内容时,首先必须指定地址。例如我们写入第一行第一位,地址位为00H,DB7加1,即80H(0010000000),第二行第一位为00H。位为40H,DB7加1,即C0H(0011000000),以此类推。

四、实验步骤

第1步:连接电路。连接电源并打开树莓派。显示屏将亮起并在第一行显示一行黑色方块。如果看不到黑色方块或黑色方块不明显,请调节可调电阻,直至黑色方块清晰显示。如果调整可调电阻后仍然看不到方块,则可能是您的连接有问题。请检查连接情况,包括检查显示引脚是否焊接。

树莓派T型转接板LCD1602SCLSCLSCLSDASDASDA5V5VVCCGNDGNDLCD1602实验电路图LCD1602实验物理接线图第2步:PCF8591模块使用I2C(IIC)总线进行通信,但在Raspberry Pi镜像中默认关闭。当使用这个传感器的时候,首先要允许IIC总线通讯。

打开I2C总线通讯第3步:查询LCD1602的地址。结果地址是0x27。

pi@raspberrypi:~ $ ls /dev/i2c-*

/dev/i2c-1

pi@raspberrypi:~ $ sudo i2cDetect -y 1

0 1 2 3 4 5 6 7 8 9 abcdef

00: -- -- -- -- -- -- -- -- -- -- -- -- -- --

10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

20: -- -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --

30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

70: -- -- -- -- -- -- -- -- --第4步:编写驱动程序。这里我们先编写一个LCD1602.py文件,然后编写一个python程序引入这个库文件,并调用这个文件中的函数来实现更复杂的功能。

LCD1602.py文件相当于LCD1602模块的驱动。它是单独编写的,以便于重用。

该程序也可以单独运行,并会在第一行显示“Hello”和“world!”在第二行。

#!/usr/bin/env python

导入时间

import smbus #SMBus(System Management Bus,系统管理总线) 将“smbus”模块导入到程序中

BUS=smbus.SMBus(1) #创建smbus实例

# 0代表/dev/i2c-0,1代表/dev/i2c-1,这取决于所使用的Raspberry Pi的I2C。

def write_word(地址,数据):

global BLEN #如果该变量为1,则表示打开LCD背光,如果为0,则表示关闭背光

临时=数据

如果BLEN==1:

temp |=0x08 #0x08=0000 1000,背光打开

#buf |=0x08 相当于buf=buf |0x08(按位或)

否则:

temp=0xF7 #0xF7=1111 0111,关闭背光

#buf=0xF7 相当于buf=buf0xF7(按位与)

BUS.write_byte(addr,temp) #这里为什么又写入8位呢?

#write_byte(int addr, char val) 发送一个字节到设备

def send_command(comm):

# 先发送bit7-4

buf=comm0xF0 #与运算,取高四位值

#由于4位总线的接线是连接P0口的高四位,所以发送时不需要改变高四位

buf |=0x04 #buf |=0x04 相当于buf=buf |0x04(按位或)0x04=0000 0100

# RS=0,RW=0,EN=1

#为什么这样写表示RS=0、RW=0、EN=1。这里的低4位有什么意义呢?

write_word(LCD_ADDR,buf) #为什么这里又多了一个8位写入呢?

睡眠时间(0.002)

buf=0xFB #buf=0xFB 相当于buf=buf0xFB(按位与)0xFB=1111 1011

# 使EN=0,EN从1——0开始,下降沿,写入

#为什么这样写就意味着Make EN=0?

write_word(LCD_ADDR,buf)

# 其次发送bit3-0

buf=(comm0x0F) 4 #与运算,取低四位,

#由于4位总线的接线连接的是P0口的高四位,所以需要左移4位。

缓冲|=0x04

# RS=0, RW=0, EN=1 写命令

write_word(LCD_ADDR,buf)

睡眠时间(0.002)

buf=0xFB # 使EN=0

write_word(LCD_ADDR,buf)

def send_data(数据):

# 先发送bit7-4

缓冲区=数据0xF0

buf |=0x05 # RS=1,RW=0,EN=1 写入数据

write_word(LCD_ADDR,buf)

睡眠时间(0.002)

buf=0xFB # 使EN=0

write_word(LCD_ADDR,buf)

# 其次发送bit3-0

buf=(数据0x0F)4

buf |=0x05 # RS=1,RW=0,EN=1 写入数据

write_word(LCD_ADDR,buf)

睡眠时间(0.002)

buf=0xFB # 使EN=0

write_word(LCD_ADDR,buf)

def init(addr, bl): #LCD1602初始化

global LCD_ADDR #这个变量是设备地址

global BLEN #如果该变量为1,则表示打开LCD背光,如果为0,则表示关闭背光

LCD_ADDR=地址

BLEN=bl

尝试:

send_command(0x33) # 必须初始化为8行模式110011 初始化

睡眠时间(0.005)

send_command(0x32) # 然后初始化为4行模式110010 初始化

睡眠时间(0.005)

send_command(0x28) # 4位总线,双行显示,显示58点阵字符。

睡眠时间(0.005)

send_command(0x0C) # 打开显示器,不显示光标,光标位置字符不闪烁

睡眠时间(0.005)

send_command(0x01) # 清屏命令,清除之前的显示内容

睡眠时间(0.005)

send_command(0x06) #设置光标和显示模式。写入新数据后,光标向右移动,显示不移动。

BUS.write_byte(LCD_ADDR,0x08) #这里写0x08是什么意思?

除了:

返回错误

否则:

返回真

def 清除():

send_command(0x01) # 清屏

def write(x, y, str):

if x 0: #LCD1602只有16列2行显示。小于第0 列的数据需要更正。

x=0

if x 15: #LCD1602只有16列2行显示。大于第15列的数据需要修正。

x=15

如果y0: #LCD1602 只有16 列和2 行显示。小于第0 行的数据需要更正。

y=0

if y 1: #LCD1602只有16列2行显示。大于第一行的数据需要更正。

y=1

# 移动光标

地址=0x80 +0x40 * y + x

#第一行第一位的地址为0x00,加上D7始终为1,所以第一行第一位的地址为0x80

#第二行第一位是0x40,加上D7始终为1,所以第二行第一位的地址是0x80加上0x40,最后是0xC0

send_command(addr) #设置显示位置

对于str: 中的chr

send_data(ord(chr)) #发送显示内容

#ord()函数以一个字符(长度为1的字符串)作为参数,

#返回对应的 ASCII 数值,或者 Unicode 数值 if __name__ == "__main__": init(0x27, 1) #在树莓派终端上使用命令"sudo i2cdetect -y 1"查询设备地址为0x27 # 第二个参数1表示打开LCD背光,若是0则关闭背光 write(4, 0, "Hello") #4,0参数指显示的起始位置为第4列,第0行 write(7, 1, "world!") #7,1参数指显示的起始位置为第7列,第1行 #‘Hello’为要显示的字符串  第5步:编写控制程序。先是静态显示内容:第一行显示“Greetings!!”,第二行显示“Welcome here!”,持续2秒。之后动态滚动显示“Thank you for buying Raspberry!”。    #!/usr/bin/env python import LCD1602 import time def setup(): LCD1602.init(0x27, 1) # init(slave address, background light) LCD1602.write(0, 0, "Greetings!!") LCD1602.write(1, 1, "Welcome here!") time.sleep(2) def loop(): space = " " greetings = "Thank you for buying Raspberry! ^_^" greetings = space + greetings while True: tmp = greetings for i in range(0, len(greetings)): LCD1602.write(0, 0, tmp) #当要显示的字符串过长时,会自动在LCD的第二行显示 tmp = tmp[1:] #每次循环去掉字符串首位字符,实现字幕向左移动的效果 time.sleep(0.8) LCD1602.clear() def destroy(): pass if __name__ == "__main__": try: setup() while True: loop() except KeyboardInterrupt:

用户评论

ー半忧伤

树莓派终于能操控显示屏啦!感觉很有成就感

    有17位网友表示赞同!

弃我者亡

我一直想试试LCD1602,这下有机会了,学习一下I2C协议

    有5位网友表示赞同!

糖果控

这么基础的实验?我之前没接触过树莓派,有点难度吗

    有14位网友表示赞同!

凝残月

看看这个实验能不能让我快速上马个小型显示屏项目

    有12位网友表示赞同!

々爱被冰凝固ゝ

1602尺寸还挺合适,用来显示一些简单的信息应该很酷

    有8位网友表示赞同!

喜欢梅西

I2C协议简单易学嘛?我还没接触过树莓派,不知道这种接口好不好用

    有13位网友表示赞同!

孤街浪途

这个实验的难度适中吗?适合初学者小白入门学习吗

    有12位网友表示赞同!

妄灸

终于找到了可以用树莓派玩硬件的实验,太棒了!

    有17位网友表示赞同!

情深至命

之前想做个小型设备显示信息,现在试试这个实验是不是合适的方案?

    有11位网友表示赞同!

江山策

感觉用LCD1602显示信息比单纯打印在控制台更友好

    有20位网友表示赞同!

oО清风挽发oО

这个实验代码实现难度应该不高吧?我希望能自己上手完成

    有17位网友表示赞同!

良人凉人

我已经开始想象了,用树莓派和LCD1602玩出什么好玩的功能!

    有9位网友表示赞同!

夏至离别

学习一些I2C协议的知识,可以让我后续更轻松地进行相关硬件开发

    有9位网友表示赞同!

话少情在

感觉这个实验应该需要用到几款相关的驱动软件或者库

    有8位网友表示赞同!

权诈

树莓派真是个强大的平台,可以玩转各种各样的硬件

    有19位网友表示赞同!

凉月流沐@

我希望这次实验能让我了解一下树莓派的编程能力

    有9位网友表示赞同!

怅惘

有了LCD1602这个显示屏,我的小型项目可就更有层次感了

    有16位网友表示赞同!

万象皆为过客

这个视频介绍详细吗?我准备先看一看教程再动手实践

    有10位网友表示赞同!

疲倦了

希望这个实验能让我对树莓派的硬件开发有个更深入的了解

    有15位网友表示赞同!

【树莓派基础实验教程:29 - I2C接口LCD1602显示屏实战】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活