LCD1602液晶显示屏编程

LCD1602液晶显示概述

LCM1602是最常见的点阵字符型液晶显示模块,由液晶板、控制器HD44780、驱动器HD44100及若干电阻电容组成。1602 液晶,可以显示2行,每行有40个字符 ,但由于显示容量的原因,每行只能显示16个字符(可以通过移动光标或者屏幕显示后面的字符,下面再讲),每行排列着40个5×8的点阵,专门用于显示字母、数字以及符号。
一般来说,LCD1602有16条引脚,据说还有14条引脚的,与16脚的相比缺少了背光电源A(15脚)和地线K(16脚)。


image.png

1602液晶模块引脚说明:
第1脚:VSS为地电源。
第2脚:VDD接5V正电源。
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15脚:背光源正极。
第16脚:背光源负极

LCD1602的基本操作分为四种:
读状态。输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。
读数据。输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。
写命令。输入RS=0,RW=0,E=高脉冲。输出:无。
写数据。输入RS=1,RW=0,E=高脉冲。输出:无。

读操作指令:


image.png

写操作指令:


image.png

时序时间参数:
image.png

1602指令集(11个):
1、清屏指令(clear display) RS=0 ,R/w=0, 01H
功能:

  • 清除液晶显示器,即将DDRAM中的内容全部填入20H(空白字符)
  • 光标撤回显示屏左上方
  • 将地址计数器(AC)设为0,
  • 光标移动方向为从左向右,并且DDRAM的自增量为1(I/D=1).


    image.png

2、光标归位指令(Return Home)RS=0 ,R/w=0, 0000_001X
功能:

  • 将地址计数器(AC)设为00H,
  • DDRAM内容保持不变,光标移至左上脚


    image.png

3、进入模式设置指令(Entry Mode Set)
功能:

  • 设 定 每 次 定 入 1 位 数据 后 光 标 移 位 方 向 并且设 定 次 写 入 一 个 字符是 否移动 。
  • I/D = 0 光标左移,DDRAM地址自增1 I/D = 1 光标右移,DDRAM地址自增1 (当从CGRAM中读取或写入数据时,CGRAM操作与DDRAM相同)
    SH = 0 且 DDRAM是读操作(CGRAM读或写),整个屏幕不移动
    SH = 1 且 DDRAM是写操作,整个屏幕移动,移动方向由I/D决定


    image.png

4、显示开关控制(Display ON/OFF Control)
功能:

  • D = 1 , 显示功能开 D = 0 , 显示功能关,但是DDRAM中的数据依然保留
  • C = 1 , 有光标 C = 0 , 没有光标
  • B = 1 , 光标闪烁 B = 0 , 光标不闪烁


    image.png

5、设置显示屏或光标移动方向的指令
功能:

  • 整屏的移动或光标移动
  • S/C =0 R/L =0 光标左移 ,地址计数器减1(即显示内容和光标一起左移)
  • S/C =0 R/L =1 光标右移 ,地址计数器加1(即显示内容和光标一起右移)
  • S/C =1 R/L =0 显示内容左移 ,光标不移动
  • S/C =1 R/L =1 显示内容右移 ,光标不移动


    image.png

6、功能设定指令
功能:

  • 设定数据总线位数、显示的行数及字形。
  • DL=1 ,数据总线是8位 DL=0 ,数据总线是4位
  • N =0 ,显示一行 N=1 ,显示两行
  • F =0 , 58 点阵/字符 F=1 ,511点阵/字符
    image.png

7、设定 CGRAM地址指令
功能:

  • 设定下一个要存入数据的CGRAM地址
  • DB5DB4DB3为字符号,即将显示该字符用到的字符地址
  • DB2DB1DB0为行号


    image.png

8、设置DDRAM地址
功能:

  • 设置DDRAM地址用于在屏幕上显示
  • DDRAM的地址与显示屏对照关系(N=LOW)


    image.png

    image.png

    注意:因为DB7是固定为1,所以DDRAM的地址与屏幕的对照关系要加上0x80才是真实的对照地址。

9、读取忙信号或AC地址指令
功能:

  • 如果BF=1 忙碌,无法接收数据或指令
  • BF=0可以接收数据、指令
  • 读取地址计数器的内容


    image.png

10、向DDRAM或CGRAM写入数据
功能:

  • 写指令 输 入 : RS=L , RW=L , E= 下 降沿脉冲 , DB0 ~ DB7= 指令
  • 写数据 输 入 : RS=H , RW=L , E= 下 降沿脉冲 , DB0 ~ DB7= 数据
image.png

11、从DDRAM或者CGRAM读数据
功能:

  • 读状态 输 入 : RS=L , RW=H , E=H 输出: DB0 ~ DB7= 状态字
  • 读数据 输 入 : RS=H , RW=H , E=H 输出: DB0 ~ DB7= 数据


    image.png

自定义字符显示

想要了解1602的自定义字符显示,就要先了解DDRAM/CGROM/CGRAM,
DDRAM:就是显示数据RAM,用来寄存待显示的字符代码。共80个字节,其地址和屏幕的对应关系如下:

image

DDRAM相当于计算机的显存,我们为了在屏幕上显示字符,就把字符代码送入显存,这样该字符就可以显示在屏幕上了。同样LCD1602共有80个字节的显存,即DDRAM。但LCD1602的显示屏幕只有16×2大小,因此,并不是所有写入DDRAM的字符代码都能在屏幕上显示出来,只有写在上图所示范围内的字符才可以显示出来,写在范围外的字符不能显示出来。这样,我们在程序中可以利用下面的“光标或显示移动指令”使字符慢慢移动到可见的显示范围内,看到字符的移动效果。

前面说了,为了在液晶屏幕上显示字符,就把字符代码送入DDRAM。例如,如果想在屏幕左上角显示字符‘A’,那么就把字符‘A’的字符代码41H写入DDRAM的00H+0x80地址处即可。至于怎么写入,后面会有说明。

那么为什么把字符代码写入DDRAM,就可以在相应位置显示这个代码的字符呢?我们知道,LCD1602是一种字符点阵显示器,为了显示一种字符的字形,必须要有这个字符的字模数据,什么叫字符的字模数据,看看下面的这个图就明白了,下图是‘A’的字模。


在LCD1602模块上固化了字模存储器,就是CGROM和CGRAM,HD44780内置了192个常用字符的字模,存于字符产生器CGROM(Character Generator ROM)中,另外还有8个允许用户自定义的字符产生RAM,称为CGRAM(Character Generator RAM)。下图说明了CGROM和CGRAM与字符的对应关系。


image.png

从ROM和RAM的名字我们也可以知道,ROM是早已固化在LCD1602模块中的,只能读取;而RAM是可读写的。也就是说,如果只需要在屏幕上显示已存在于CGROM中的字符,那么只须在DDRAM中写入它的字符代码就可以了,比如数据‘A’,只需在DDRAM的显示地址上输入‘A’即可;但如果要显示CGROM中没有的字符,比如摄氏温标的符号,那么就只有先在CGRAM中定义,然后再在DDRAM显示地址写入这个自定义字符的存放地址即可。和CGROM中固化的字符不同,CGRAM中本身没有字符,所以要在DDRAM中写入某个CGROM不存在的字符,必须在CGRAM中先定义后使用。程序退出后CGRAM中定义的字符也不复存在,下次使用时,必须重新定义。
可以使用上面提到的1602指令集的第七条指令,设置CGRAM地址,由于DB7和DB6固定为0和1,所以设置CGRAM的地址是从0x40H开始,DB5DB4DB3设置字符在CDRAM中的存放地址,DB2DB1DB0设置字符的字模存放地址,在5x8的字符点阵中,一个字符显示需要8个字节存放字模。
比如摄氏度℃字符,字模为{0x10,0x07,0x08,0x08,0x08,0x08,0x07,0x00},使用指令7设置摄氏度字符的存放位置为 01-000-xxx,000是设置摄氏度在CGRAM中的存放地址为0x00,显示摄氏度时只需在DDRAM中输入0x00即可,xxx是设置摄氏度字模存放的地址,摄氏度字模存放的8个地址为:0100000,01000001,01000010,01000011,01000100,01000101,01000110,01000111,对应的是0x40—0x47这8个地址。由此可得8个自定义字符的显示地址和字模的存放地址对应关系如下:

自定义字符存放地址 字模存放地址
0x00H 0x40H-0x47H
0x01H 0x48H--0x4fH
0x02H 0x50H-0x57H
0x03H 0x58H-0x5fH
0x04H 0x60H-0x67H
0x05H 0x68H-0x6fH
0x06H 0x70H-0x77H
0x07H 0x78H-0x7fH
LCD1602.h头文件
#ifndef  _LCD1602_H
#define  _LCD1602_H

#include "reg52.h"
#include <string.h>
#include <intrins.h>
#define  LCDPIN4

#define  LCD1602 P0

sbit RS = P2^6;
sbit RW = P2^5;
sbit EN = P2^7;

#define LCD_SCREEN_CLR       0x01    //清屏
#define LCD_CURSOR_RST       0x02    //光标复位
#define LCD_DIS_CUR_BLK_ON   0x0F    //显示开  有光标,光标闪烁
#define LCD_DIS_CUR_ON       0x0E    //显示开  有光标,光标不闪烁
#define LCD_DIS_ON           0x0C    //显示开  关光标,光标不闪烁
#define LCD_DIS_OFF          0x08    //显示关  
#define LCD_CURSOR_RIGHT     0x06    //光标右移,显示不动
#define LCD_CURSOR_LEFT      0x04    //光标左移,显示不动
#define LCD_DIS_MODE_LEFT    0x07    //AC自增,画面左移
#define LCD_DIS_MODE_RIGHT   0x05    //AC自减,画面右移
#define LCD_POWER_PIN8       0x38    //功能设置指令,数据总线为8位,2行
#define LCD_POWER_PIN4       0x28    //功能设置指令,数据总线为4位,2行
#define LCD_CUR_MOVE_LEFT    0x10    //光标左移
#define LCD_CUR_MOVE_RIGHT   0x14    //光标右移
#define LCD_DIS_MOVE_RIGHT   0x18    //显示右移
#define LCD_DIS_MOVE_LEFT    0x1c    //显示左移



void DelayXms(unsigned int num);
void LCDInit();
void LCDWriteData(unsigned char dat);
void LCDWriteCmd(unsigned char cmd);
void LCDShowStr(unsigned char x, unsigned char y, unsigned char* str);
void LCDSetChar(unsigned char x, unsigned char y, unsigned char pos,unsigned char* str);

#endif
LCD1602.c
#include "LCD1602.h"

void DelayXms(unsigned int num)     //@12.000MHz
{
    unsigned char i, j;

    for(;num > 0; num--)
    {
        i = 2;
        j = 239;
        do
        {
            while (--j);
        } while (--i);
    }   
}


void LCDReadBusy()  //忙信号检测
{
    unsigned char state, i;
    LCD1602 = 0xff;   //io口置1,做输入
    RS=0;
    RW=1;
    i=0;
    
    do
    {
        EN=1;
        state = LCD1602;
        EN = 0;
        i++;
        if(i > 100)
            break;
    }while(state & 0x80);  //   如果LCD1602最高位为1,说明液晶显示器忙
         
}

#ifndef LCDPIN4

//发送命名
void LCDWriteCmd(unsigned char cmd)
{
    LCDReadBusy();
    RS = 0;
    RW = 0;
    LCD1602 = cmd;
    EN = 1;
    EN = 0;
}

//发送数据
void LCDWriteData(unsigned char dat)
{
    LCDReadBusy();
    RS = 1;
    RW = 0;
    LCD1602 = dat;
    EN = 1;
    EN = 0;
}

//初始化屏幕
void LCDInit()
{
    LCDWriteCmd(LCD_POWER_PIN8);
    LCDWriteCmd(LCD_DIS_ON);
    LCDWriteCmd(LCD_CURSOR_RIGHT);
    LCDWriteCmd(LCD_SCREEN_CLR);
}
#else

void LCDWriteCmd(unsigned char cmd)
{
    LCDReadBusy();
    RS = 0;
    RW = 0;
    LCD1602 = cmd;
    //DelayXms(1);  //这里延时根据实际情况是否需要
    EN = 1;
    EN = 0;

    LCD1602 = cmd<<4;
    //DelayXms(1);
    EN =1;
    EN =0;
}

void LCDWriteData(unsigned char dat)
{
    LCDReadBusy();
    RS = 1;
    RW = 0;
    LCD1602 = dat;
    //DelayXms(1);  //这里延时根据实际情况是否需要
    EN = 1;
    EN = 0;

    LCD1602 = dat<<4;
    //DelayXms(1);
    EN = 1;
    EN = 0;
}

void LCDInit()
{
//  LCDWriteCmd(0x33);  
//  DelayXms(5);
    LCDWriteCmd(0x32);  //0x32是4位总线必须要设置的
    LCDWriteCmd(LCD_POWER_PIN4);
    LCDWriteCmd(LCD_DIS_ON);
    LCDWriteCmd(LCD_CURSOR_RIGHT);
    LCDWriteCmd(LCD_SCREEN_CLR);
}

#endif

//字符在屏幕上显示的位置
void LCDSetPos(unsigned char x, unsigned char y)
{
    if(y == 0)
     {
          LCDWriteCmd(0x80+x);
     }
     else
     {
           LCDWriteCmd(0x80 |(0x40+x));
     }
}

//构造和显示自定义字符    x,y为在屏幕上显示的位置,pos为在CGRAM存放字符的位置,str为字符的字模
void LCDSetChar(unsigned char x, unsigned char y, unsigned char pos, unsigned char str[])
{
    unsigned char i;
    //构造自定义字符,确定CGRAM位置
    for(i = 0; i < 8;i++)
    {
        LCDWriteCmd(0x40 + pos*8 + i); //确定字模位置
        LCDWriteData(*(str+i));        //写入字模
    }

    //显示
    LCDSetPos(x, y);//设置显示位置 DDRAM
    LCDWriteData(0x00+pos);     
}

//在屏幕上显示字符
void LCDShowStr(unsigned char x, unsigned char y, unsigned char* str)
{
     LCDSetPos(x ,y);
     while(*str != '\0')
     {
        LCDWriteData(*str++);       
     }
     
}
main.c
#include "LCD1602.h"

void main()
{


    /*****************************以下是对液晶显示4位和8位数据总线的操作******/
    //LCDInit();
    //DelayXms(2); //这里延时是必须的,让液晶显示器初始化完成再写数据
//  #ifndef LCDPIN4
//      unsigned char *str="hello lcd PIN8";
//  #else
//      unsigned char *str="hello lcd PIN4";
//  #endif
//  LCDShowStr( 2,0,str);
//  while(1);
//  

    /*****************************以下是显示自定义字符******/

//  unsigned char str1[] = {0x10,0x07,0x08,0x08,0x08,0x08,0x07,0x00};//自定义字符 ℃ 的字模
//  LCDInit();
//  DelayXms(2);
//  LCDSetChar(2, 0, 0, str1);
//  while(1);

    /*****************************以下是两种移屏操作******/
    unsigned char i=0;
    unsigned char str[]="HELLO LCD 1602";
     LCDInit();
     DelayXms(10);
     //第一种,初始设置字符的输入模式,整屏左移
//  LCDWriteCmd(LCD_DIS_MODE_LEFT); 
//  while(1)
//  {   
//      LCDWriteCmd(0x80);
//      for(i =0; i < strlen(str); i++)
//      {
//          LCDWriteData(str[i]);
//          DelayXms(600);
//
//      }
//  }

      //第二种,字符移动,光标不动
      LCDWriteCmd(0x80);
      for(i =0; i < strlen(str); i++)
      {
         LCDWriteData(str[i]);
      }
      while(1)
      {
            LCDWriteCmd(LCD_DIS_MOVE_LEFT);  //第二种
            DelayXms(600);
      }
       

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容