C51单片机学习笔记——LCD1602调试
在学习完数码管显示后发现具有局限性只能显示0—9的数字,而1602显示屏可以字符,数字等就具有灵活性,可以更直观的显示出想显示的东西。
一、LCD1602模块
1602液晶显示屏(LCD 1602)是一种常见的字符型液晶显示模块。
1. 硬件结构
1602显示屏的核心由以下部分组成:
-
液晶面板:由16×2个字符单元组成,每个单元由5×8或5×11点阵构成。
-
控制器芯片:通常采用 HD44780 或其兼容芯片,负责控制显示内容和通信。
-
背光:可选LED背光,提高显示对比度。
-
接口引脚:16个引脚(部分型号可能简化),包括电源、控制信号和数据总线。
2. 工作原理
(1) 控制芯片(HD44780)
-
内部寄存器:
-
指令寄存器(IR):存储控制指令(如清屏、光标移动等)。
-
数据寄存器(DR):存储待显示的字符数据。
-
-
显示数据RAM(DDRAM):存储屏幕上实际显示的字符码,容量为80字节(足够2行×40字符,但1602仅显示前16字符)。
-
字符生成ROM(CGROM):内置标准ASCII字符(5×8点阵)的字模库。
-
自定义字符RAM(CGRAM):允许用户定义8个5×8点阵的自定义字符。
(2) 通信方式
-
并行接口:通过8位(或4位)数据总线传输数据。
-
控制信号:
-
RS(Register Select):
-
RS=0
:选择指令寄存器(发送命令)。 -
RS=1
:选择数据寄存器(发送显示内容)。
-
-
RW(Read/Write):
-
RW=0
:写入模式(常用)。 -
RW=1
:读取模式(较少使用)。
-
-
E(Enable):使能信号,高电平到低电平的跳变触发芯片执行操作。
-
(3) 操作时序
-
写操作流程:
-
设置
RS
和RW
电平。 -
将数据/指令放到数据总线(DB0-DB7)。
-
拉高
E
信号并保持至少450ns。 -
拉低
E
信号,完成写入。
-
3. 显示流程
-
初始化:
-
发送指令设置显示模式(如4位/8位总线、显示行数、字体大小)。
-
开启显示、清屏、设置光标移动方向等。
-
-
写入数据:
-
通过
RS=1
发送字符的ASCII码到数据寄存器。 -
字符码被存入DDRAM,并自动显示在屏幕上。
-
-
地址控制:
-
第一行地址范围:
0x00-0x0F
(实际DDRAM地址为0x80-0x8F
)。 -
第二行地址范围:
0x40-0x4F
(实际DDRAM地址为0xC0-0xCF
)。
-
4. 关键指令
常用指令(通过 RS=0
发送):
-
0x01
:清屏。 -
0x0C
:开启显示,关闭光标。 -
0x80
:设置DDRAM地址到第一行开头。 -
0xC0
:设置DDRAM地址到第二行开头。
5. 对比度与背光
-
对比度调节:通过
V0
引脚连接电位器(典型值:10kΩ),调整电压(0-5V)控制显示清晰度。 -
背光控制:引脚15(A)和16(K)连接LED背光,需串联限流电阻(通常220Ω)。
二、1602模块头文件和源文件代码
#ifndef __LCD1602_H__
#define __LCD1602_H__
//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,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
#include <REGX52.H>
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
//函数定义:
/**
* @brief LCD1602延时函数,12MHz调用可延时1ms
* @param 无
* @retval 无
*/
void LCD_Delay()
{
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_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @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 if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}
/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @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;
}
/**
* @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(Number/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @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;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFF
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}
/**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void LCD_ShowBinNum(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(Number/LCD_Pow(2,i-1)%2+'0');
}
}
三、1602调试
例如:我们显示一个字符串
代码如下:
#include <REGX52.H>
#include "LCD1602.h"
void main()
{
LCD_Init();//初始化
LCD_ShowString(1,1,"HelloWorld");//显示字符串“HelloWorld”
while(1)
{
//
}
}
LED1602就显示了HelloWorld。