51单片机应用开发---LCD1602显示应用
实现目标
1、了解LCD1602液晶屏;
2、掌握驱动程序的编写;
3. 具体目标:在屏幕上显示字符。
一、LCD1206概述
1.1 定义
LCD1602(Liquid Crystal Display)液晶显示屏是一种字符型液晶显示模块,可以显示ASCII码的标准字符和其它的一些内置特殊字符,还可以有8个自定义字符(如汉字)。
显示容量: 16—表示每行显示16个字符;02—表示显示两行。
1.2 实物与管脚
(1)实物
(2)管脚定义
1.3 内部结构框图
屏幕: 16*2
字模库:类似于数码管的数码表
DDRAM (data display RAM):前16列与屏幕一一对应的
AC: address counter
显示流程:在数据显示区写入相应的值(ASCII码),之后通过字模库找到对应的字符,将其显示到屏幕上。
(1)存储器结构:DDRAM(数据显示区)
LCD1602 实际有80个字节的DDRAM,只不过 LCD1602 只有 16X2 个位置,后面很多位置显示不出来,可以使用 指令5 “光标或显示移动指令” 使字符慢慢移动到可见的显示范围内,看到字符的移动效果。
(2)显示原理
如上图,每个字符由 5X8 点阵组成(也可选用 5X10),想要实现显示,只需如下图:
例:以 5X7 点阵为例, 显示字符 A
0 代表灭,1 代表亮
只需将想要显示的字符的对应位置1,就能显示该字符LCD1602 固化了字模寄存器,即 CGROM 和 CGRAM,存储了192个常用字符的字模。
(3) CGRAM+CGROM(字模库)
例如:要显示A,则索引码为0100 0001 该表 行是低四位,列是高四位
1.4 LCD1602指令集
常用指令:
0x80+0xdd:dd为地址,这条命令用于设置显示起点坐标
0x0c :开显示,无光标,光标不闪烁 。一般做带键盘输入的才加入光标,如计算器。常用的计量显示不显示光标。
0x06 :写一个数据,地址指针加1,由1602地址表可以看出,实际上就是设置成从左往右写数据而已。
0x38 : 设置显示模式,16x2显示 5x7点阵,8位数据接口。端口不够用时,这个命令也可以换用4位数据接口的。
0x01 :清屏。
1.5 LCD1602操作流程
(1) 初始化
发送指令0x38 //八位数据接口,两行显示,5*7点阵
发送指令0x0C //显示开,光标关,闪烁关
发送指令0x06 //数据读写操作后,光标自动加一,画面不动
发送指令0x01 //清屏
(2) 显示字符
发送指令 0x80 | AC //设置光标位置(之所以要将AC与0x80进行或运算,是因为DDRAM地址设置指令的DB7为1,故发送指令的最高位要为1)
【将光标设置在一行一列输入1000 0000,1为设置,剩下为00H】
【将光标设置在二行一列输入1100 0000,1为设置,剩下为40H(二进制100 0000转化为十进制为64,十六进制40转化为十进制也是64)】发送数据 //发送要显示的字符数据
1.6 时序结构
写数据/指令(对于LCD来说,一般不需要进行读操作)
写数据:先将RS置1,再将R/W置0,之后将数据写入对应I0口,将 E 置1,则此时数据有效;写数据完成后;E置0 。写指令同理
驱动编写:
(1) 管脚定义
#include "LCD1602.h"
#include <REGX52.H>
//管脚定义
sbit LCD_RW=P2^5;
sbit LCD_RS=P2^6;
sbit LCD_E =P2^7;
#define LCD_DataPort P0
(2)写命令
/*** @brief LCD1602延时函数,12MHz调用可延时1ms* @param 无* @retval 无*/
void LCD_Delay() //@12.000MHz 1ms
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}/*** @brief LCD1602写命令* @param Command 要写入的命令* @retval 无*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_E=1;LCD_Delay();LCD_E=0;LCD_Delay();
}
(3)写数据
/*** @brief LCD1602写数据* @param Data 要写入的数据* @retval 无*/
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_E=1;LCD_Delay();LCD_E=0;LCD_Delay();
}
(4)LCD1602初始化
/*** @brief LCD1602初始化函数* @param 无* @retval 无*/
void LCD_Init(void)
{LCD_WriteCommand(0x38);LCD_WriteCommand(0x0C);LCD_WriteCommand(0x06);LCD_WriteCommand(0x01);
}
(5)设置光标位置
/*** @brief LCD1602设置光标位置* @param Line 行位置,范围:1~2* @param Column 列位置,范围:1~16* @retval 无*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else{LCD_WriteCommand(0x80|(Column-1)+0x40);}
}
(6)显示一个字符
/*** @brief 在LCD1602指定位置上显示一个字符* @param Line 行位置,范围:1~2* @param Column 列位置,范围:1~16* @param Char 要显示的字符* @retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}
(7)显示字符串
/*** @brief 在LCD1602指定位置开始显示所给字符串* @param Line 起始行位置,范围:1~2* @param Column 起始列位置,范围:1~16* @param String 要显示的字符串* @retval 无*/
void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);}
}
(8)X的Y次方
/*** @brief 返回值=X的Y次方*/
int LCD_Pow(int X,int Y)
{unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result;
}
(9)显示数字
/*** @brief 在LCD1602指定位置开始显示所给数字* @param Line 起始行位置,范围:1~2* @param Column 起始列位置,范围:1~16* @param Number 要显示的数字,范围:0~65535* @param Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData('0'+Number/LCD_Pow(10,i-1)%10);}
}
(10)显示有符号数字
/*** @brief 在LCD1602指定位置开始以有符号十进制显示所给数字* @param Line 起始行位置,范围:1~2* @param Column 起始列位置,范围:1~16* @param Number 要显示的数字,范围:-32768~32767* @param Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;//int型-32768~32767}for(i=Length;i>0;i--){LCD_WriteData('0'+Number1/LCD_Pow(10,i-1)%10);}
}
二、原理图设计
三、程序设计
3.1 LCD1602.h 文件
#ifndef __LCD1602_H__
#define __LCD1602_H__void LCD_Init(void);
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif
3.2 LCD1602.c 文件
将前面的各项驱动程序模块添加到LCD1602.c文件中。
3.3 测试程序
#include <REGX52.H>
#include "LCD1602.h"void Delay500ms() //@11.0592MHz
{unsigned char i, j, k;i = 4;j = 129;k = 119;do{do{while (--k);} while (--j);} while (--i);
}void main()
{LCD_Init();LCD_ShowString(1,16,"day day up!");while(1){//指令集0x18:画面向左平移一个字符位,但光标不动。移屏LCD_WriteCommand(0x18);Delay500ms();}
}