Proteus8 simulation: 51 single-chip LCD1602 display

components

components name
exclusion RESPACK-8
51 MCU AT89C51
LCD1602 LM016L
button BUTTON

Schematic part

insert image description here

LCD1602 driver:
HD44780 display mainly has 8-bit operation, 8-bit two-line display, 4-bit operation, 8-bit one-line display, and 8-bit operation, 8-bit one-line display.
LCD1602 is mainly driven by HD44780, first check the HD44780 data sheet to see the function of related pins
insert image description here

pin effect
RS select register
RW read-write control
EA enable read and write
D0-D3 The lower four bits of the data line
D4-47 The high four bits of the data line

insert image description here
Then HD44780 has two 8-bit registers, IR and DR, IR write command, DR write data.
insert image description here
Register operation is controlled by the RS and RW bits.

RS RW effect
0 0 IR write internal operation
0 1 Read flag (DB7 busy bit) and DB0-DB6 address
1 1 DR read internal operation
1 0 DR write internal operation

Read timing + program
insert image description here

uint_8 Lcd1602_read(bit Flag)
{
    
    
	uint_8 Data;
	E=0;
	RW=1;
	if(Flag==1) RS=0;  //读繁忙位
	else RS=1; //读DR寄存器
	E=1;
	Data=P0;
	E=0;
	return Data;
}

Write timing + program
insert image description here

void Lcd1602_write(bit Comm,uint_8 Data)
{
    
    
	while(Lcd1602_read(1)==1);//如果繁忙就暂停
	E=0;
	RW=0;
	if(Comm==1) RS=0; //写指令
	else RS=1; //写数据
	E=1;
	P0=Data;
	E=0;
}

Then you can view the corresponding commands according to the data manual:
insert image description here
for the instructions, because the space is too long, I will choose a few to talk about:

#define Clear_Display 0X01  //清屏
#define Display_On 0X0E //打开屏幕显示光标不闪烁  
#define Display_Off 0X00 //关闭屏幕不显示光标不闪烁 
//0000 1DCB D:1打开显示0关闭显示 C:1打开光标0关闭光标 B:1光标闪烁0光标不闪
#define Bit8_Line2_Display 0X38 //8位2行显示
#define Entry_Mode_Set 0X06 //光标右移显示器不移动
//0000 0 1 I/D S //I/D1模式自增一向右0模式自减一向左 S1光标不移动显示器移动0显示器不移动
#define Set_CGRAM00 0X80 //第一行
#define Set_CGRAM10 0XC0 //第二行
#define Shift_Function 0X14 //光标右移

Then write the initialization code according to the data sheet (8-bit operation, 8-bit 2-line display):
It is worth noting that the FLAG (busy bit) cannot be read during the instruction operation. According to the data sheet, the busy bit is the highest of DB0-7 bit.

void Lcd1602_init(void)
{
    
    
	Lcd1602_write(1,Bit8_Line2_Display); //设置为8位2行显示
	Lcd1602_write(1,Set_CGRAM00);//起始位置设置
	Lcd1602_write(1,Display_On); //打开显示和光标
    Lcd1602_write(1,Shift_Function);//光标右移
	Lcd1602_write(1,Entry_Mode_Set);//光标右移显示器不移动
}

This is the font given in the manual.
Since CGRAM will generate fonts, it can automatically display string
insert image description here
display functions:

void Show_String(uint_8 *line1,uint_8 *line2)
{
    
    
	uint_8 i=0;
	Lcd1602_write(1,Set_CGRAM00);
	for(i=0;i<strlen(line1);i++)
	{
    
    
		Lcd1602_write(0,line1[i]);
	}
	Lcd1602_write(1,Set_CGRAM10);
	for(i=0;i<strlen(line2);i++)
	{
    
    
		Lcd1602_write(0,line2[i]);
	}	
}

the code

In this experiment, LCD1602 displays the time.

main.c

code show as below:

#include <reg51.h>
#include "string.h"

#define Clear_Display 0X01  //清屏
#define Display_On 0X0E //打开屏幕显示光标不闪烁  
#define Display_Off 0X00 //关闭屏幕不显示光标不闪烁 
//0000 1DCB D:1打开显示0关闭显示 C:1打开光标0关闭光标 B:1光标闪烁0光标不闪
#define Bit8_Line2_Display 0X38 //8位2行显示
#define Entry_Mode_Set 0X06 //光标右移显示器不移动
//0000 0 1 I/D S //I/D1模式自增一向右0模式自减一向左 S1光标不移动显示器移动0显示器不移动
#define Set_CGRAM00 0X80 //第一行
#define Set_CGRAM10 0XC0 //第二行
#define Shift_Function 0X14 //光标右移
#define Cursor_Close 0X0C

//-----------Writer:CSDN 月明Mo----------------------------------------------------------------------------------------------------------------------
//-----------引脚连接------------------------------------------------------------------------------------------------------------
//RS -------- P10
//选择寄存器。
//0: 指令寄存器(用于写入)繁忙标志:
//地址计数器(供阅读)
//1: 数据寄存器(用于写入和读取)

//RW -------- P11
//0 写
//1 读

//EA -------- P12
//使能读和写

//D0-D3 数据线低四位
//D4-47 数据线高四位
//D0 -------- P00 
//D1 -------- P01
//---------
//D7 -------- P07
sbit RS=P1^0;
sbit RW=P1^1;
sbit E=P1^2;

typedef unsigned char uint_8;
typedef unsigned int uint_16;

//------------函数说明-------------------------------------------------------------------------------------------------
void Lcd1602_init(void); //初始化函数
uint_8 Lcd1602_read(bit Flag); //Lcd1602读函数
//Flag为1时读取忙碌为
//为0时读取DR寄存器
void Lcd1602_write(bit Comm,uint_8 Data);
//Comm为1时写指令,为0写数据
//Data为要写的数据
void Lcd1602_Clear(void);
//清屏
void Show_String(uint_8 *line1,uint_8 *line2);
//line1为第一行要显示的字符
//line2为第二行要显示的字符


void tim_init(void);
void delay_ms(uint_16 ms);

uint_8 mcount=55,fcount=59,scount=23; //时间定义

void main(void)
{
    
    
	uint_8 a=0;
	uint_8 line1[]="    time show"; 
	uint_8 line2[]="    00:00:00"; 
	Lcd1602_init();
	tim_init();
	while(1)
	{
    
    
		//加48是因为0和’0‘的ASCII值差48,将数字变为字符
		line2[4]=scount/10+48; //显示时十位
		line2[5]=scount%10+48;//显示时个位
		line2[7]=fcount/10+48;//显示分十位
		line2[8]=fcount%10+48;//显示分个位
		line2[10]=mcount/10+48;//显示秒十位
		line2[11]=mcount%10+48;//显示秒个位
		if(mcount>=60){
    
    mcount=0;fcount++;}//秒大于60清零
		if(fcount>=60){
    
    fcount=0;scount++;}//分大于60清零
		if(scount>=24){
    
    scount=0;}//时大于24清零
		Show_String(line1,line2);
	};
}

void Show_String(uint_8 *line1,uint_8 *line2)
{
    
    
	uint_8 i=0;
	Lcd1602_write(1,Set_CGRAM00);
	for(i=0;i<strlen(line1);i++)
	{
    
    
		Lcd1602_write(0,line1[i]);
	}
	Lcd1602_write(1,Set_CGRAM10);
	for(i=0;i<strlen(line2);i++)
	{
    
    
		Lcd1602_write(0,line2[i]);
	}	
}

void Lcd1602_init(void)
{
    
    
	Lcd1602_write(1,Bit8_Line2_Display); //设置为8位2行显示
	Lcd1602_write(1,Set_CGRAM00);//起始位置设置
	Lcd1602_write(1,Display_On); //打开显示和光标
  Lcd1602_write(1,Shift_Function);//光标右移
	Lcd1602_write(1,Entry_Mode_Set);//光标右移显示器不移动
	Lcd1602_write(1,Cursor_Close);
}

void Lcd1602_Clear(void)
{
    
    
	Lcd1602_write(1,Clear_Display);
}

void Lcd1602_write(bit Comm,uint_8 Data)
{
    
    
	while(Lcd1602_read(1)==1);//如果繁忙就暂停
	E=0;
	RW=0;
	if(Comm==1) RS=0; //写指令
	else RS=1; //写数据
	E=1;
	P0=Data;
	E=0;
}

uint_8 Lcd1602_read(bit Flag)
{
    
    
	uint_8 Data;
	E=0;
	RW=1;
	if(Flag==1) RS=0;  //读繁忙位
	else RS=1; //读DR寄存器
	E=1;
	if(Flag==1)Data=((P0&0x80)>>7);
	else Data=P0;
	E=0;
	return Data;
}

//定时器中断50ms
uint_8 t;
void time() interrupt 1
{
    
    
	t++;//每50ms进来一次
	if(t>=20){
    
    t=0;mcount++;} //50×20 ==1000 == 1s,秒加一
}

//定时器0初始化函数
void tim_init(void)
{
    
    
	TH0=(65535-50000)/256; //设置初始时间高八位
	TL0=(65535-50000)%256; //设置初始时间低八位
	EA=1;//打开总中断
	ET0=1; //打开定时器0中断
	TMOD=0X01; //定时器模式选择
	TR0=1;//开始计数
}

//延时函数
void delay_ms(uint_16 ms)
{
    
    
	uint_16 i,j;
	for(i=0;i<ms;i++)
	for(j=71;j>0;j--);
}


The running effect is as shown in the figure:
insert image description here

Project Files

Project files include HD44780 files

Guess you like

Origin blog.csdn.net/darlingqx/article/details/128347103