LCD1602显示屏的使用
1、引脚功能
VSS:接地引脚
VDD:电源正极5v
VO:对比度调节电压
RS:指令/数据选择,0为指令,1为数据
RW:读写选择,0为写,1为读
E:使能,1为数据有效,下降沿执行指令
D0~D7:数据输入/输出引脚
A:背光灯电源正极
K:背光灯电源负极
2、组成结构
- LCD1602的分辨率是16x2,也就是有2行16列的小屏幕组成,而每个小屏幕都有相应对应的地址。在要屏幕显示数据的时候,需要发送指令,指定位置小屏幕显示。如下图所示,每个位置都要不同的1个字节数据对应。
【注意】
例如第二行第一个字符的地址是 40H,那么是否直接写入 40H 就可以将光标定位在第二行第。一个字符的位置呢?这样不行,因为写入显示地址时要求最高位 D7 恒定为高电平 1 。所以实际写入的数据应该是 01000000B(40H) +10000000B(80H)=11000000B(C0H)
-
而这些地址数据是存储在DDRAM中,DDRAM是一个40x2的存储数据的存储区,它前面16列存储对应的屏幕地址数据,后面的位置用于存储,发送来的指令/显示的数据。
-
而显示的字符,数字,特殊符号都要对应的字模库。
-
例如,需要在屏幕上面显示0,则只需要向D0~D7输入0011 0000的1个字节的数据即可。需要在屏幕上面显示A,则只需要向D0~D7输入0100 0001的1个字节的数据即可。我们将这个字模库和ASCII码表进行对比一下。
- 如图,ASCII码表中的’0’对应的一个字节数也是0010 0000。‘A’对应的一个字节的数据是0100 0001。所以我们需要显示0时,不需要给数据线输入一个字节的二进制数据,我们只需要向输入一个字符‘0’,单片机接收到字符‘0’,会按照ASCII码表转换为对应的一个字节数据,然后将这个数据和字母表中的数据进行比对,最终在屏幕上面显示。(但是有些字符ASCII码并不和字模库相对应)
3、时序结构与指令集
- 如图为向模块写数据/指令的时序结构:
RS = 0;R/W = 0;此时向模块写入数据(指令),而写指令时,E = 0。
在写完数据的tsp2的时间后,E变为1,在E= 1;时不能在写入数据了,在E下降沿时执行写入的数据(指令)。
RS = 1;R/W = 0;此时向模块写入屏幕显示的数据,而时序和写入指令同理。
LCD1602.c文件
#include <REGX52.H>
#include "intrins.h"
//引脚定义
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;
#define LCD_DataPort P0
void LCD_Delay1ms() //@11.0592MHz,1ms的延迟
{
unsigned char i, j;
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
/*
* 给LCD写入指令
*/
void LCD_WriteCommand(signed char Command)
{
RS = 0;/**RS为0代表写入的是指令,
*为1代表写入的是要显示的数据*/
RW = 0;/**RW为0代表从LCD中写入数据,
*RW为1代表从LCD中读取数据*/
EN = 0;//将E置为低电平开始写入数据
LCD_DataPort = Command;//开始将指令传给引脚口
_nop_(); //5us
EN = 1;
LCD_Delay1ms();//EN为高电平的时候,传来的数据才有效
EN = 0; //E置低,为下一次写入数据做准备
LCD_Delay1ms();
}
/*
* 给LCD写入显示的数据
*/
void LCD_WriteData(unsigned char Data)
{
RS = 1;/**RS为0代表写入的是指令,
*为1代表写入的是要显示的数据*/
RW = 0;/**RW为0代表从LCD中写入数据,
*RW为1代表从LCD中读取数据*/
EN = 0;
LCD_DataPort = Data;//开始将数据传给引脚口
_nop_();
EN = 1;
LCD_Delay1ms();//EN为高电平的时候,传来的数据才有效
EN = 0;
LCD_Delay1ms();
}
/*
* 给LCD初始化,也就是给LCD写入一下指令进行配置,为显示做准备
*/
void LCD_Init()//给LCD初始化,传输指令集
{
LCD_WriteCommand(0x38);//8位数据接口
LCD_WriteCommand(0x0C);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//读写操作,光标自动+1,画面不动
LCD_WriteCommand(0x01);//清屏
}
/*
* 显示行列,第1行第1列的地址为0x00,第2列0x01.....
第2行第1列的地址为0x40,第2列0x41.....
*/
void LCD_SetCuror(unsigned char Line,unsigned char Column)
{
if(Line == 1)//若第一行
{
LCD_WriteCommand(0x80|(Column-1));//1000 0000 + (x-1)
}
else
{
LCD_WriteCommand(0x80|(Column-1) + 0x40);
}
}
/*
***显示一个字符(行,列,字符)***
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCuror(Line,Column);
LCD_WriteData(Char);
}
/*
***显示字符串(行,列,字符串,字符串长度)***
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCuror(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/*
***显示数字(行,列,数字,数字长度)***
*/
/*
894 长度为:3
894/100 = 8 8%10 = 8
894/10 = 89 89%10 = 9
894/1 = 894 894%10 = 4
*/
int Counting_power(int x,int y)//x^y
{
unsigned char i;
int a = 1;
for(i = 0; i<y; i++)
{
a *= x;
}
return a;
}
void LCD_ShowNum(unsigned char Line,unsigned char Column,int Num, unsigned char Length)
{
unsigned char i;
unsigned int Num1;
LCD_SetCuror(Line,Column);
for(i = 1; i<= Length; i++)
{
Num1 = (Num/Counting_power(10,Length - i))%10;
LCD_WriteData('0'+ Num1);
}
}
/*
***显示有符号的数字(行,列,数字,数字长度)***
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Num, unsigned char Length)
{
unsigned char i;
unsigned int Num1;
LCD_SetCuror(Line,Column);
if(Num >= 0)
{
LCD_WriteData('+');
for(i = 1; i<= Length; i++)
{
LCD_WriteData('0'+ (Num/Counting_power(10,Length - i))%10);
}
}
else
{
LCD_WriteData('-');
for(i = 1; i<= Length; i++)
{
Num1 = -Num;
LCD_WriteData('0'+ (Num1/Counting_power(10,Length - i))%10);
}
}
}
主函数main.c文件
#include <REGX52.H>
#include "LCD1602.h"
void main(void)
{
LCD_Init();
LCD_ShowChar(1,1,'C');
LCD_ShowString(1,3,"nihao");
LCD_ShowNum(1,9,888,3);
LCD_ShowSignedNum(2,3,-12,2);
}