【自学嵌入式:51单片机】LCD1602
LCD1602

LCD1602(Liquid Crystal Display)液晶显示屏是一种字符型液晶显示模块,可以显示ASCII码的标准字符和其他一些内置特殊字符,还可以有8个自定义字符。
- 显示容量:16×2个字符,每个字符为5×7点阵
电路

| 引脚 | 功能 |
|---|---|
| GND(VSS) | 地 |
| VCC(VDD) | 电源正极(4.5~5.5V) |
| VO | 对比度调节电压 |
| RS | 数据/指令选择,1为数据,0为指令 |
| RW | 读/写选择,1为读,0为写 |
| E | 使能,1为数据有效,下降沿执行命令 |
| D0~D7 | 数据输入/输出 |
| BG VCC(A) | 背光灯电源正极 |
| BG GND(K) | 背光灯电源负极 |
D0~D7是一个字节的并行口,不用一位一位传输
E相当于一个时钟线,高电平有效,它决定什么时候开始采样信号
【注】图中背光灯的VCC和GND都默认连好了,没法自己控制开关背光灯。
内部结构框图

字模库,相当于数码管的段码表(几乎所有能显示的ASCII字符都存在这里,少部分被替换为非标准的ASCII字模),RAM是可以自定义字模,ROM是出场自带的,数据显示区前16列可以显示在屏幕上,不能显示的向左移屏就能显示了。

存储器结构

这里索引码和ASCII是一样的
指令集

时序结构
写数据/指令

最开始要想写数据,置RS为高电平,如果想写指令,RS为低电平,R/W低电平,然后把数据/指令放在D0-D7,E使能端打开
读数据/指令

最开始想要读数据,置RS为高电平,想要写指令,RS为低电平,读就是把R/W设为高电平,E使能端打开,经过一段时间TD,它就会把想要发送的数据放在中间,然后I/O口把Valid Data读取,其他和写操作类似。
时序参数

操作流程

代码实现
LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
void LCD1602_Init(); //LCD1602初始化
void LCD1602_ShowChar(unsigned char x, unsigned char y, unsigned char Char); //显示字符
void LCD1602_ShowString(unsigned char x, unsigned char y, unsigned char* String); //显示字符串
void LCD1602_ShowNum(unsigned char x, unsigned char y, unsigned int Number, unsigned char Length); //显示数字
void LCD1602_ShowSignedNum(unsigned char x, unsigned char y, int Number, unsigned char Length); //显示有符号数
void LCD1602_ShowHexNum(unsigned char x, unsigned char y, unsigned int Number, unsigned char Length); //显示十六进制数字
void LCD1602_ShowBinNum(unsigned char x, unsigned char y, unsigned int Number, unsigned char Length); //显示二进制数字
void LCD1602_WriteData(unsigned char Data); //写数据
void LCD1602_WriteCommand(unsigned char Command); //写指令
#endif
LCD1602.c
#include <REGX52.H>
#include <intrins.h> // 延时空语句
sbit LCD_RS = P2^6;
sbit LCD_RW = P2^5;
sbit LCD_E = P2^7;
#define LCD_DataPort P0
void LCD1602_Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
//写指令
void LCD1602_WriteCommand(unsigned char Command)
{
LCD_RS = 0; //写指令,RS为低电平
LCD_RW = 0; //写
LCD_DataPort = Command; //指令
LCD_E = 1; //打开使能
LCD1602_Delay1ms(); //延迟1ms,写入指令大概40us
LCD_E = 0; //关闭使能
LCD1602_Delay1ms();
}
//写数据
void LCD1602_WriteData(unsigned char Data)
{
LCD_RS = 1; //写数据,RS为低电平
LCD_RW = 0; //写
LCD_DataPort = Data; //数据
LCD_E = 1; //打开使能
LCD1602_Delay1ms(); //延迟1ms,写入数据大概40us
LCD_E = 0; //关闭使能
LCD1602_Delay1ms();
}
//初始化
void LCD1602_Init()
{
LCD1602_WriteCommand(0x38); //八位数据结构,两行显示,5*7点阵
LCD1602_WriteCommand(0x0C); //显示开,光标关,闪烁关
LCD1602_WriteCommand(0x06); //数据读写操作后,光标自动加一,画面不动
LCD1602_WriteCommand(0x01); //清屏
}
//设置光标位置单独写一个函数
void LCD1602_SetCursor(unsigned char x, unsigned char y)
{
switch(x)
{
case 0:
LCD1602_WriteCommand(0x80 | y);//或运算,地址设置最高位要置1
break;
case 1:
LCD1602_WriteCommand((0x80 | y)+0x40); //第二行地址有偏移,加偏移量
break;
}
}
//显示字符,x和y按下标来
void LCD1602_ShowChar(unsigned char x, unsigned char y, unsigned char Char)
{
//将行和列进行运算变成实际地址
//我还是习惯下标为0开始,第0列
LCD1602_SetCursor(x, y);
//选完地址后写数据
LCD1602_WriteData(Char);
}
//显示字符串
void LCD1602_ShowString(unsigned char x, unsigned char y, unsigned char* String)
{
unsigned char i = 0;
LCD1602_SetCursor(x, y);
for(i = 0; String[i] != '\0'; i++)
{
LCD1602_WriteData(String[i]);
}
}
//次方函数
int LCD1602_Pow(int X, int Y)
{
unsigned char i;
int Result = 1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
//显示数字
//Length是长度
void LCD1602_ShowNum(unsigned char x, unsigned char y, unsigned int Number, unsigned char Length)
{
unsigned char i = 0;
LCD1602_SetCursor(x, y);
//除相应10的次方取余获得个十百千万位的数字
for(i = Length; i>0;i--)
{
LCD1602_WriteData('0' + Number/LCD1602_Pow(10, i-1) % 10); //加字符0的ACSII码,转换为字符
}
}
//显示有符号数字
void LCD1602_ShowSignedNum(unsigned char x, unsigned char y, int Number, unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD1602_SetCursor(x, y);
//0不加正负号
if(Number>0)
{
LCD1602_WriteData('+');
Number1 = Number;
}
else if(Number < 0)
{
LCD1602_WriteData('-');
Number1 = -Number; //直接取相反数除了-32768以外都能转换,因为有符号int是-32768-32767
}
//转成无符号数方便显示
for(i = Length; i>0;i--)
{
LCD1602_WriteData('0' + Number1/LCD1602_Pow(10, i-1) % 10); //加字符0的ACSII码,转换为字符
}
}
//显示十六进制
void LCD1602_ShowHexNum(unsigned char x, unsigned char y, unsigned int Number, unsigned char Length)
{
unsigned char i = 0;
unsigned char SingleNumber;
LCD1602_SetCursor(x, y);
//除相应16的次方取余获得个十百千万位的数字
//大于等于10,变为字母A-F,要重新偏移一下(对应ASC码)
for(i = Length; i>0;i--)
{
SingleNumber = Number/LCD1602_Pow(16, i-1) % 16;
if(SingleNumber<10)
{
LCD1602_WriteData('0' + SingleNumber);
}
else
{
LCD1602_WriteData('A' + SingleNumber - 10); //减去10才是从字符A开始的ASCII码,不减去10就不对
}
}
}
//显示二进制
void LCD1602_ShowBinNum(unsigned char x, unsigned char y, unsigned int Number, unsigned char Length)
{
unsigned char i = 0;
LCD1602_SetCursor(x, y);
//除相应2的次方取余获得个十百千万位的数字
for(i = Length; i>0;i--)
{
LCD1602_WriteData('0' + Number/LCD1602_Pow(2, i-1) % 2); //加字符0的ACSII码,转换为字符
}
}
main.c
#include <REGX52.H>
#include "LCD1602.h"
void Delay(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void main()
{
LCD1602_Init();
LCD1602_ShowChar(0, 0, 'A');
LCD1602_ShowString(0, 2, "Hello");
LCD1602_ShowNum(0, 8, 66, 2);
LCD1602_ShowSignedNum(0, 11, -88, 2);
LCD1602_ShowHexNum(1, 0, 0xA5, 2);
LCD1602_ShowBinNum(1, 3, 0xA5, 8);
LCD1602_ShowChar(1, 12, 0xDF); //显示°
//LCD1602_ShowChar(1, 13, 0xE0); //显示α
LCD1602_ShowChar(1, 13, 'C'); //显示字母C,凑成摄氏度符号
LCD1602_ShowString(0, 15, "Welcome to China!"); //流动字幕,不流动不够显示
while(1)
{
LCD1602_WriteCommand(0x18); //写指令,左移屏幕一次
Delay(500); //500ms移动一次
//移动到头又会循环移动回来
}
}
浙公网安备 33010602011771号