LCD1602( Liquid Crystal Display 1602),一种常见的字符型液晶显示模块。虽然它接线多,但是LCD1602是每个嵌入式工程师的必经之路。它能够显示16列2行,共32个字符字符,每个字符都由5x8像素点阵构成,是一种专门用来显示字母、数字、符号等的液晶显示模块。
LCD 具有体积小、功耗低、显示内容丰富等特点,这种显示模块广泛应用于嵌入式系统和电子项目中,为开发者提供了简单而有效的文本和数字显示。在本文中,我们将深入探讨 LCD 中的 LCD1602 的特点、原理和工作方式。同时,我们还会介绍如何使用代码进行初始化和编程,以实现自定义的内容显示。
通过学习 LCD1602,您将能够更好地理解液晶显示技术,并将其应用于各种项目中。无论您是新手还是有经验的开发人员,本文都将为您提供基础知识和实用指南。
本文首发 良许嵌入式网 :https://www.lxlinux.net/e/ ,欢迎关注!
本文所涉及的源码及安装包如下(由于平台限制,请点击以下链接阅读原文下载):
https://www.lxlinux.net/e/stm32/lcd1602-tutorial.html
如果你是嵌入式开发小白,那么建议你先读读下面几篇文章。
往期精彩教程,有兴趣的小伙伴可以看看。
从零开始轻松掌握STM32开发的必备指南:零基础快速上手STM32开发(手把手保姆级教程)
深入浅出,帮助您理解和应用MQTT协议:万字猛文:MQTT原理及案例
通俗易懂的 GPIO 介绍与实践:如何快速成为点灯大师?
作者简介 |
---|
大家好,我是良许,博客里所有的文章皆为我的原创。 下面是我的一些个人介绍,欢迎交个朋友: · 211工科硕士,国家奖学金获得者; · 深耕嵌入式11年,前世界500强外企高级嵌入式工程师; · 书籍《速学Linux作者》,机械工业出版社专家委员会成员; · 全网60W粉丝,博客分享大量原创成体系文章,全网阅读量累计超4000万; · 靠自媒体连续年入百万,靠自己买房买车。 |
我本科及硕士都是学机械,通过自学成功进入世界500强外企。我已经将自己的学习经验写成了一本电子书,超千人通过此书学习并转行成功。现在将这本电子书免费分享给大家,希望对你们有帮助:
电子书链接:https://www.lxlinux.net/1024.html
LCD,液晶显示模块具有体积小、功耗低、显示内容丰富等特点,现在字符型液晶显示模块已经是单片机应用设计中最常用的信息显示器件了。
有很多种型号的 LCD。
以上三种分类结果,排列组合,就成为了我们在橙色软件上看到的,眼花缭乱的型号选择。
当然,我们今天的主角是 LCD1602。顺带一提,我的是黄绿屏(黑字)5V。
工作参数如下:
引脚接线参考如下:
LCD1602 | STM32 | 说明 |
---|---|---|
GND | GND | 接地 |
VDD | 5V | 电源正极 |
V0 | 0-5V | 液晶驱动电压 |
RS | 任意GPIO口 | 寄存器选择: 1:数据寄存器 0:指令寄存器 |
RW | 任意GPIO口 | 读、写操作选择: 1:读 0: 写 |
E | 任意GPIO口 | 使能信号 |
D0 | 任意GPIO口 | 双向数据 |
D1 | 任意GPIO口 | 双向数据 |
D2 | 任意GPIO口 | 双向数据 |
D3 | 任意GPIO口 | 双向数据 |
D4 | 任意GPIO口 | 双向数据 |
D5 | 任意GPIO口 | 双向数据 |
D6 | 任意GPIO口 | 双向数据 |
D7 | 任意GPIO口 | 双向数据 |
BLA | 5V | 背光正极 |
BLK | GND | 背光负极 |
引脚注解:
V0:液品显示器对比度调整端,接正电源时对比度最高,接地时对比度最低,对比度过高时会产
生“鬼影”,使用时可以通过电位器或电阻调整对比度。电阻小了全是黑块,电阻大了不显示。
RW:读写信号线,高电平时进行读操作,低电平时进行写操作。
当 RS 和 RW 共同为低电平时可以写入指令成者显示地址;
当 RS 为低电平,RW 为高电平时可以读忙信号;
当 RS 为高电平,RW 为低电平时可以写入数据。
E:使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
LCD1602 的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
LCD1602 内部的控制器共有11条控制指令,如表所示:
指令1:清显示,指令码 01H,光标复位到地址 00H 位置。
指令2:光标复位,光标返回到地址00H。
指令3:I/D:光标和显示模式设置,光标移动方向,高电平右移,低电平左移;
S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。
D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示;
C:控制光标的开与关,高电平表示有光标,低电平表示无光标;
B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:S/C:高电平时移动显示的文字,低电平时移动光标;
R/L:高电平时右移,低电平时左移。
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线;
N:低电平时为单行显示,高电平时双行显示;
F:低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址,BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据。
LCD1602 的基本的操作分为以下四种:
状态字读操作:输入 RS=0、RW=1、E=1;输出:D0~7 读出为状态字;
数据读出操作:输入 RS=1、RW=1、E=1;输出:D0~7 读出为数据;
指令写入操作:输入 RS=0、RW=0、E=上升沿; 输出:无;
数据写入操作:输入 RS=1、RW=0、E=上升沿; 输出:无。
当我们要写指令的时候,RS 置为低电平,RW 置为低电平,E 置为低电平,然后将指令数据送到数据口 D0~D7,延时 tsp1,让 LCD1602 准备接收数据,这时候将 E 拉高,产生一个上升沿,这时候指令就开始写入 LCD1602,延时一段时间,将 E 置为低电平。
当我们要写数据的时候,RS 置为高电平,RW 置为低电平,E 置为低电平,然后将指令数据送到数据口 D0~D7,延时 tsp1,让 LCD1602 准备接收数据,这时候将 E 拉高,产生一个上升沿,这时候数据就开始写入 LCD1602,延时一段时间,将 E 置为低电平。
对比一下可以发现,写指令和写数据在时序上只是 RS 的不同,写指令 RS=0,写数据 RS=1。
时序时间参数如下表:
LCD1602 的控制器内置有 80 个 byte 的显存,而 LCD1602 只有两行 × 16 个字符的显示区域,所以 显存中有些地址是无法对应上 LCD 屏的,下图为显存地址对应图:
写入显示地址时要求最高位 D7 为高电平,也就是说,如果想你想
写入第一行第一个字符应该是:
00000000B(00H)+ 10000000B(80H) = 10000000B(80H)。
写入第二行第一个字符应该是:
01000000B(40H)+ 10000000B(80H) = 11000000B(C0H)。
在 LCD1602 的控制 IC 当中,字符库中 0x00~0x0F 未定义,留给使用者的自定义字符使用。但只能使用 0x00~0x07 或者 0x08~0x0F 之一。
字符表如下,和 ASCII 码相似。
LCD1602 初始化流程图如下:
现在我们就动手,让 LCD1602 居中显示一个「peace and love」和「LX handsome」。每秒右移一位,移完后再次居中显示「peace and love」和「LX handsome」。
本教程使用的硬件如下:
接线如下:
LCD1602 | STM32 |
---|---|
GND | GND |
VDD | 5V |
V0 | GND |
RS | B1 |
RW | B2 |
E | B10 |
D0 | A0 |
D1 | A1 |
D2 | A2 |
D3 | A3 |
D4 | A4 |
D5 | A5 |
D6 | A6 |
D7 | A7 |
BLA | 3.3 |
BLK | GND |
烧录的时候接线如下表,如果不会烧录的话可以看我之前的文章【STM32下载程序的五种方法】。
ST-Link V2 | STM32 |
---|---|
SWCLK | SWCLK |
SWDIO | SWDIO |
GND | GND |
3.3V | 3V3 |
接好如下图:
V0 需要接一个 5kΩ 左右的电阻才能正常显示,这里我用的是电位器。手上没有电位器或者电阻的小伙伴可以侧着看,上下左右侧着看,也是可以看到显示的字符的。
将我们要用到的引脚都进行一个初始化。
void lcd_gpio_init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ //__HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10, GPIO_PIN_SET); /*Configure GPIO pins : PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 */ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pins : PB1 PB2 PB10 */ GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); }
根据我们前面讲的时序,写指令:RS、RW、E 置为低电平,指令数据传输,延时,将 E 拉高,延时,将 E 拉低。
void write_cmd(char cmd) { RS_LOW; RW_LOW; EN_LOW; GPIOA->ODR = cmd; //将一字节数据发到GPIOA 8个引脚 HAL_Delay(5); EN_HIGH; HAL_Delay(5); EN_LOW; }
根据我们前面讲的时序,写数据:RS 置为高电平,RW、E 置为低电平,指令数据传输,延时,将 E 拉高,延时,将 E 拉低。
void write_data(char dataShow) { RS_HIGH; RW_LOW; EN_LOW; GPIOA->ODR = dataShow; //将一字节数据发到GPIOA 8个引脚 HAL_Delay(5); EN_HIGH; HAL_Delay(5); EN_LOW; }
按照初始化流程图写代码,检测忙信号可省略。
void lcd_init() { //(1)延时 15ms HAL_Delay(15); //(2)写指令 38H(不检测忙信号) write_cmd(0x38); //(3)延时 5ms HAL_Delay(5); //(4)检测忙信号(省略) //(5)写指令 38H:显示模式设置 write_cmd(0x38); //(6)写指令 08H:显示关闭 write_cmd(0x08); //(7)写指令 01H:显示清屏 write_cmd(0x01); //(8)写指令 06H:显示光标移动设置 write_cmd(0x06); //(9)写指令 0CH:显示开及光标设置 write_cmd(0x0c); }
根据我们前面说的显存地址,将数据一个个显示到 LCD1602。
row: 显示行,col: 显示起始列,string:显示字符。由于我们前面得出 LCD1602 字符表和 ACSII 码差不多,所以直接传参即可。
void lcd_show_line(char row, char col, char *string) { switch(row){ case 1: write_cmd(0x80+col); //最高位 D7 为高电平 while(*string){ write_data(*string); string++; } break; case 2: write_cmd(0x80+0x40+col); while(*string){ write_data(*string); string++; } break; } }
利用写指令,0x18,画面右移一位;0x1C,画面左移一位。
void lcd_right_move(void) { for(int i=0;i < 16;i++){ HAL_Delay(1000); write_cmd(0x18); //画面右移一位 0x18 } }
int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ delay_init(72); /* 延时初始化 */ lcd_gpio_init(); /* lcd初始化 */ while(1) { lcd_start(); lcd_show_line(1,1,"peace and love"); lcd_show_line(2,2,"LX handsome"); lcd_move(); } }
我用的是我自己打的板子,上官二号。大家可以用自己的板子,是 STM32F103C8T6 就行。
显示「peace and love」和「LX handsome」。
每秒右移一位,移完后再次居中显示「peace and love」和「LX handsome」。
在将来的项目中,您可以尝试利用 LED1602 进行更多的实践和创新。通过进一步探索和学习,您可以了解更多高级功能和扩展选项,以满足特定项目的需求。
另外,想进大厂的同学,一定要好好学算法,这是面试必备的。这里准备了一份 BAT 大佬总结的 LeetCode 刷题宝典,很多人靠它们进了大厂。
刷题 | LeetCode算法刷题神器,看完 BAT 随你挑!
推荐阅读:
欢迎关注我的博客:良许嵌入式教程网,满满都是干货!