(六).单片机输出电路实践——LCD1602与LCD12864的使用
一、LCD简介
LCD作为一种常见的外设,是广泛应用在单片机外围电路的一种显示设备。LCD1602和LCD12864是典型的单片机显示电路中常用的模块,两种该模块都属于点阵式液晶显示模块。
1、LCD1602模块
1602液晶也叫160字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。1602LCD是指显示内容为16*2,显示两行,每行可以显示16个字符液晶模块。液晶1602引脚说明如下表中所示:
编号 |
符号 |
引脚说明 |
编号 |
符号 |
引脚说明 |
1 |
VSS |
电源地 |
9 |
D2 |
数据口 |
2 |
VDD |
电源正极 |
10 |
D3 |
数据口 |
3 |
VO |
液晶显示对比度调节 |
11 |
D4 |
数据口 |
4 |
RS |
数据/命令选择端 |
12 |
D5 |
数据口 |
5 |
R/W(—) |
读写选择端 |
13 |
D6 |
数据口 |
6 |
E |
使能信号 |
14 |
D7 |
数据口 |
7 |
D0 |
数据口 |
15 |
BLA |
背光电源正极 |
8 |
D1 |
数据口 |
16 |
BLK |
背光电源负极 |
对LCD1602有两种操作方式,即“读”和“写”。“读”操作就是读液晶是否处于“忙”状态,如果是,就等液晶“空闲”时再往液晶“写”(写指令或数据)。一般情况下对于LCD1602可以不用“读”操作,用一个短暂延时即可。液晶1602工作之前,要对1602进行一些设置。
-
Function set功能设置
1602模块的功能设置指令码如下表中所示:RS R/W DB7
DB6
DB5
DB4
DB3
DB2
DB1
DB0
0
0
0
0
1
DL
N
F
-
-
设置模块数据接口的宽度和1602显示屏的显示方式,即单片机1602模块接口数据总线4位或8位、LCD显示行数和显示字符点阵的规格。DL:数据接口宽度标志。DL=1,8位数据DB7~DB0;DL=0,四位数据总线DB7~DB4;DB3~DB0不用,使用此方式传送数据,需分两次进行。N:显示行数标志。N=1,双行显示;N=0,单行显示方式。F:现实点阵字符字体标志。F=1,5*10点阵+光标显示;F=0:5*7点阵+光标显示方式。
-
Display on/off control(显示开/关控制)
1602模块的指令代码如下表所示:RS R/W DB7
DB6
DB5
DB4
DB3
DB2
DB1
DB0
0
0
0
0
0
0
1
D
C
B
D:显示开/关标志。D=1,开显示;D=0,关显示。
C:光标显示控制标志。C=1,光标显示;C=0,光标不显示。
B:闪烁控制标志。B=1,光标所指位置上,交替显示全黑点阵和显示字符,产生闪烁效果,f=250KHZ时,闪烁频率为0.4ms左右,通过设置,光标可以与其所指位置的字符一起闪烁。 - Entry mode set(设置输入方式)
RS | R/W |
DB7 |
DB6 |
DB5 |
DB4 |
DB3 |
DB2 |
DB1 |
DB0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
N |
S |
N=1,当读和写一个字符后地址指针加1,且光标加1;N=0,当读和写一个字符后地址指针减1,且光标减1.
S=1,当写一个字符时,整屏显示左移(N=1)或右移(N=0)。S=0,当写一个字符时,整屏显示不移动。
-
Clear display(清屏)
RS R/W DB7
DB6
DB5
DB4
DB3
DB2
DB1
DB0
0
0
0
0
0
0
0
0
0
1
所谓清屏就是把数据指针清零和所有显示清零
2、12864模块
12864是128*64点阵液晶模块的点阵数简称,其引脚说明如下表中所示:
编号 |
符号 |
引脚说明 |
编号 |
符号 |
引脚说明 |
1 |
VSS |
电源地 |
11 |
D4 |
数据口 |
2 |
VDD |
电源正极 |
12 |
D5 |
数据口 |
3 |
VO |
液晶显示对比度 调节 |
13 |
D6 |
数据口 |
4 |
RS |
数据/命令选择端(H/L)(串口片选) |
14 |
D7 |
数据口 |
5 |
R/W |
读写选择端(H/L)(串口数据) |
15 |
PSB |
并串选择,H并行,L串行 |
6 |
E |
使能信号 |
16 |
NC |
悬空 |
7 |
D0 |
数据口 |
17 |
RST |
复位,低电平有效 |
8 |
D1 |
数据口 |
18 |
NC |
悬空 |
9 |
D2 |
数据口 |
19 |
BLA |
背光电源正极 |
10 |
D3 |
数据口 |
20 |
BLK |
背光电源负极 |
对于液晶12864同1602也有两种工作方式,“读”和“写”。“读”操作即判断液晶是否处于“忙”状态,一般对12864用一个短延时即可。
- Function set 功能设置
RS R/W DB7
DB6
DB5
DB4
DB3
DB2
DB1
DB0
0
0
0
0
1
DL
X
0 RE
X
X
DL:数据接口宽度标志。DL=1(必须是1),8位数据DB7~DB0。
RE=1,扩充指令集动作;RE=0,基本指令集动作。
RS和R/W均为低电平的情况下,是“写指令”。 -
Display on/off control(显示开/关控制)
RS R/W DB7
DB6
DB5
DB4
DB3
DB2
DB1
DB0
0
0
0
0
0
0
1
D
C
B
D:显示开/关标志。D=1,开显示;D=0,关显示。
C:光标显示控制标志。C=1,光标显示;C=0,光标不显示。
B:光标位置反白开关控制位。B=1,光标位置反白ON(将光标所在处的资料反白显示);B=0,光标位置反白OFF。 -
Clear display(清屏)
RS R/W DB7
DB6
DB5
DB4
DB3
DB2
DB1
DB0
0
0
0
0
0
0
0
0
0
1
同1602,清屏就是把数据指针清零和所有显示清零。
-
12864串行显示
串行工作模式下:
CS(RS):片选信号线,进行数据操作时必须将CS端拉高。
SCLK(R/W):串行同步时钟,每操作一位数据都要有一个SCLK跳变沿,上升沿有效,当SCLK由低电平变为高电平的瞬间,液晶将SID上的数据读入或输出。
SID(EN):串行数据,每一次操作都由三个字符组成,第一个字节向控制器发送命令控制字,若为写指令则发送1111 1000,若为写数据则发送1111 1010。第二个字节高四位发送指令或数据的高四位,第二个字节低四位补0。第三个字节低四位发送指令或数据的低四位,第三个字节的低四位补0。 -
汉字显示LCD12864显示汉字,只能显示4行,每行显示8个汉字或16个字符。汉字的地址分布如下: LCD12864显示汉字,只能显示4行,每行显示8个汉字或16个字符。汉字的地址分布如下:
第一行汉字 |
0x80 |
0x81 |
0x82 |
0x83 |
0x84 |
0x85 |
0x86 |
0x87 |
第二行汉字 |
0x90 |
0x91 |
0x92 |
0x93 |
0x94 |
0x95 |
0x96 |
0x97 |
第三行汉字 |
0x88 |
0x89 |
0x8a |
0x8b |
0x8c |
0x8d |
0x8e |
0x8f |
第四行汉字 |
0x98 |
0x99 |
0x9a |
0x9b |
0x9c |
0x9d |
0x9e |
0x9f |
二、电路设计
以12864显示模块的电路为例。
1、并行显示电路
2、串行显示电路
三、程序设计
1、1602显示单个数字
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit Lcd1602_EN=P2^5; //使能端
sbit Lcd1602_RS=P1^0; //数据命令选择端
sbit Lcd1602_RW=P1^1; //读写选择端,可以直接电路置地,只使用写功能
void delay(uint i)
{
uint x,y;
for(x=i;x>0;x--)
for(y=110;y>0;y--);
}
void write_com(uchar com)
{
Lcd1602_RS=0;//命令
Lcd1602_RW=0;//写
Lcd1602_EN=0;
P0=com;
delay(5);
Lcd1602_EN=1;
delay(5);
Lcd1602_EN=0;
}
void write_data(uchar dat)
{
Lcd1602_RS=1;
Lcd1602_RW=0;
Lcd1602_EN=0;
P0=dat;
delay(5);
Lcd1602_EN=1;
delay(5);
Lcd1602_EN=0;
}
void Lcd_Init()
{
write_com(0x38);//16*2显示,8位数据接口
write_com(0x0c);//显示器开,光标开,光标闪烁
write_com(0x06);//显示字符不动,光标右移
write_com(0x01);//清屏
}
void display(uchar c,int v)//显示一个三位的数字
{
uint shu;
write_com(c);
write_com(0x80);//设置第一行第一列写
shu=v/100;
write_data(shu+'0');
shu=v%100/10;
write_data(shu+'0');
shu=v%10;
write_data(shu+'0');
}
void main()
{
int v;
v=789;
Lcd_Init();
while(1)
{
display(0x80,v);
}
}
2、1602显示单个字符
#include <reg52.h>
#include "LCD1602.h"
uchar table[]={"www.baidu.com"};
uchar num;
void display(int v)
{
int shu;
write_com(0x80);
for(num=0;num<13;num++)
{
write_data(table[num]);
delay(5);
}
write_com(0x80+40);
shu=v/100;
write_data(shu+'0');
shu=v%100/10;
write_data(shu+'0');
shu=v%10;
write_data(shu+'0');
write_data(0xdf);
write_data('C');
delay(5);
}
void main()
{
uint v;
Lcd_Init();
while(1)
{
v=100;
display(v);
}
}
//lcd1602.h文件
#ifndef _LCD1602_
#define _LCD1602_
#define uchar unsigned char
#define uint unsigned int
sbit Lcd1602_EN=P2^5; //ʹÄܶË
sbit Lcd1602_RS=P1^0; //Êý¾ÝÃüÁîÑ¡Ôñ¶Ë
sbit Lcd1602_RW=P1^1; //¶ÁдѡÔñ¶Ë,¿ÉÒÔÖ±½Óµç·Öõأ¬Ö»Ê¹ÓÃд¹¦ÄÜ
void delay(uint i)
{
uint x,y;
for(x=i;x>0;x--)
for(y=110;y>0;y--);
}
void write_com(uchar com)
{
Lcd1602_RS=0;//ÃüÁî
Lcd1602_RW=0;//д
Lcd1602_EN=0;
P0=com;
delay(5);
Lcd1602_EN=1;
delay(5);
Lcd1602_EN=0;
}
void write_data(uchar dat)
{
Lcd1602_RS=1;
Lcd1602_RW=0;
Lcd1602_EN=0;
P0=dat;
delay(5);
Lcd1602_EN=1;
delay(5);
Lcd1602_EN=0;
}
void Lcd_Init()
{
write_com(0x38);//16*2ÏÔʾ£¬8λÊý¾Ý½Ó¿Ú
write_com(0x0c);//ÏÔʾÆ÷¿ª£¬¹â±ê¿ª£¬¹â±êÉÁ˸
write_com(0x06);//ÏÔʾ×Ö·û²»¶¯£¬¹â±êÓÒÒÆ
write_com(0x01);//ÇåÆÁ
}
#endif
3、12864显示汉字
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit RS=P1^0;
sbit RW=P1^1;
sbit EN=P2^5;
sbit PSB=P1^2;
uchar code table1[]={"人生若只如初见,"};
uchar code table2[]={"何事秋风悲画扇。"};
uchar code table3[]={"等闲变却故人心,"};
uchar code table4[]={"却道故人心易变。"};
void delay(uint i)
{
uint x,y;
for(x=i;x>0;x--)
for(y=110;y>0;y--);
}
void write12864_cmd(uchar cmd)
{
RS=0;
RW=0;
EN=0;
P0=cmd;
delay(5);
EN=1;
delay(5);
EN=0;
}
void write12864_data(uchar dat)
{
RS=1;
RW=0;
EN=0;
P0=dat;
delay(1);
EN=1;
delay(1);
EN=0;
}
void lcd12864_init()
{
PSB=1;
write12864_cmd(0x30);//设置数据宽度为8位
delay(5);
write12864_cmd(0x0c);//开显示
delay(5);
write12864_cmd(0x01);//清屏
delay(5);
}
void lcd_pos(uchar x,uchar y)//显示位置坐标
{
uchar pos;
if(x==0)
{x=0x80;}
else if(x==1)
{x=0x90;}
else if(x==2)
{x=0x88;}
else if(x==3)
{x=0x98;}
pos=x+y;
write12864_cmd(pos);
}
void main()
{
lcd12864_init();
while(1)
{
uchar i;
lcd_pos(0,0);
for(i=0;i<16;i++)
{
write12864_data(table1[i]);
}
lcd_pos(1,0);
for(i=0;i<16;i++)
{
write12864_data(table2[i]);
}
lcd_pos(2,0);
for(i=0;i<16;i++)
{
write12864_data(table3[i]);
}
lcd_pos(3,0);
for(i=0;i<16;i++)
{
write12864_data(table4[i]);
}
}
}
4、12864串行显示程序
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit CS=P1^0;
sbit SCLK=P1^1;
sbit SID=P2^5;
sbit PSB=P1^2;
uchar code table1[]={"人生若只如初见,"};
uchar code table2[]={"何事秋风悲画扇。"};
uchar code table3[]={"等闲变却故人心,"};
uchar code table4[]={"却道故人心易变。"};
void delay(uint i)
{
uint x,y;
for(x=i;x>0;x--)
for(y=110;y>0;y--);
}
void sendbyte(uchar zdata)//根据液晶串口通信协议,发送数据
{
uint i;
for(i=0;i<8;i++)
{
if((zdata<<i)&0x80)
{
SID=1;
}
else
{
SID=0;
}
SCLK=0;
SCLK=1;
}
}
void write12864_com(uchar cmdcode)
{
CS=1;
sendbyte(0xf8);//写指令
sendbyte(cmdcode&0xf0);//指令高四位
sendbyte((cmdcode<<4)&0xf0);//低四位
delay(1);
}
void write12864_data(uchar dispdata)
{
CS=1;
sendbyte(0xfa);//写数据
sendbyte(dispdata&0xf0);//数据高四位
sendbyte((dispdata<<4)&0xf0);//低四位
delay(1);
}
void lcd12864_init()
{
PSB=0;
write12864_com(0x30);
delay(5);
write12864_com(0x0c);
delay(5);
write12864_com(0x01);
delay(5);
}
void lcd_pos(uchar x,uchar y)//显示位置坐标
{
uchar pos;
if(x==0)
{x=0x80;}
else if(x==1)
{x=0x90;}
else if(x==2)
{x=0x88;}
else if(x==3)
{x=0x98;}
pos=x+y;
write12864_com(pos);
}
void display(uchar *s)
{
while(*s>0)
{
write12864_data(*s);
s++;
delay(1);
}
}
void main()
{
lcd12864_init();
while(1)
{
lcd_pos(0,0);
display(table1);
lcd_pos(1,0);
display(table2);
lcd_pos(2,0);
display(table3);
lcd_pos(3,0);
display(table4);
}
}