lcd1602的基础操作和配置可查看12章讲解!
在这里插入图片描述

一.原理

基础回顾:
1. lcd1602一个字符的显示是宽5个像素高8个像素,一共40个像素。其中每行的5个像素是由1个字节的低5位控制,高3位不起作用(此处需要注意,后面创建图形需要考虑到)。所以一个字符的显示要8个字节;
在这里插入图片描述
2. 由lcd1602的使用手册可知,其用户字模存储区CGRAM是6位地址(即64个地址),每个地址可存入1个字节的数据。因此,CGRAM最多可存入8个完整字符
3. 动态的制作也是利用视觉残留现象,短时间播放多帧画面。

二.图形模型的创建

由上面动图可见,我使用左边8个字符位置显示图形(即一幅图片宽20,高16),一帧图片8个字符显示的顺序为从左至右,从上至下(即先显示第一行4个字符,再显示第2行4个字符)。
取字模的软件为PCtoLCD2002。

1.设置显示区大小

图片的宽度需保留完整字节的大小,把高3位空出来,因此宽度设为32。
在这里插入图片描述

2.字模输出设置

在这里插入图片描述

3.依据所设计的图形,一帧帧绘制出来。

设计的图形
在这里插入图片描述
逐帧绘制:
第一帧:
在这里插入图片描述
第二帧:
在这里插入图片描述
第n帧:

4.注意事项

实际需要显示的顺序:
在这里插入图片描述
代码生成字模的顺序:
在这里插入图片描述

由于此字模软件无法按需要显示的顺序输出,因此在代码中需要适当更改。
例如字模软件的输出为:

	{0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,	//实际显示的第1个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,			//第5个字符
	0x1F,0x1F,0x1F,0x1F,0x1C,0x1F,0x1F,0x1F,	//第2个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,			//第6个字符
	0x1F,0x1F,0x1F,0x1F,0x07,0x1F,0x1F,0x1F,	//第3个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,			//第7个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,	//第4个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},			//第8个字符	

三.代码与注释

#include "stc15.h"
#include "intrins.h"

#define LCD1602_DB P0
sbit LCD1602_RS=P2^0;  //RS,数据/命令选择端(H/L)
sbit LCD1602_RW=P2^1;  //R/W,读/写选择端(H/L)
sbit LCD1602_E=P1^2;  // E,使能信号

//共有17帧
unsigned char code picture[17][64]=	
{
	//第一帧
	{0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,	//第1个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,			//第5个字符
	0x1F,0x1F,0x1F,0x1F,0x1C,0x1F,0x1F,0x1F,	//第2个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,			//第6个字符
	0x1F,0x1F,0x1F,0x1F,0x07,0x1F,0x1F,0x1F,	//第3个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,			//第7个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,	//第4个字符
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},			//第8个字符		

	//第二帧
	{0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
	
	{0x1F,0x1C,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x13,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x19,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x13,0x19,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x19,0x13,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x13,0x19,
	0x1C,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x19,0x13,
	0x07,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x13,0x19,
	0x1C,0x1E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x19,0x13,
	0x07,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x13,0x19,
	0x1C,0x1E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x0F,0x07,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1E,0x1C,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x19,0x13,
	0x07,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x13,0x19,
	0x1C,0x1E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x0F,0x07,0x13,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1E,0x1C,0x19,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x19,0x13,
	0x07,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},

	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x13,0x19,
	0x1C,0x1E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x0F,0x07,0x13,0x19,0x1F,0x1F,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1E,0x1C,0x19,0x13,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x19,0x13,
	0x07,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},


	{0x1F,0x1C,0x19,0x13,0x17,0x17,0x13,0x19,
	0x1C,0x1E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
	0x1F,0x07,0x13,0x19,0x1C,0x1F,0x1F,0x1F,
	0x1F,0x0F,0x07,0x13,0x19,0x1C,0x1E,0x1F,
	0x1F,0x1C,0x19,0x13,0x07,0x1F,0x1F,0x1F,
	0x1F,0x1E,0x1C,0x19,0x13,0x07,0x0F,0x1F,
	0x1F,0x07,0x13,0x19,0x1D,0x1D,0x19,0x13,
	0x07,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
};

//读状态
void read_state(void)
{
	unsigned char sta;			//状态读取存储变量
	LCD1602_DB=0xff;
	LCD1602_RS=0;
	LCD1602_RW=1;
	LCD1602_E=1;
	do
	{
		LCD1602_E=1;
		sta=LCD1602_DB;//把状态字读取到sta变量中,可通过最高位判断液晶是否处于忙态,1时为忙 
		LCD1602_E=0;//释放总线,防止影响其他模块
	}while(sta&0x80);
}

//写命令
void write_cmd(unsigned char cmd)
{
	read_state();
	LCD1602_RS=0;					 //RS=0->指令
	LCD1602_RW=0;					 //R/W=0->写
	LCD1602_DB=cmd;
	LCD1602_E=1;	
	LCD1602_E=0;			
}
 
//写数据
void write_data(unsigned char date)
{
	read_state();
	LCD1602_RS=1;					 //RS=1->数据
	LCD1602_RW=0;	
	LCD1602_DB=date;
	LCD1602_E=1;
	LCD1602_E=0;
}

//LCD初始化
void lcd_init()
{				
	LCD1602_E=0;		 //使能关(操作前关使能使用时打开)
	write_cmd(0x3c);     //设置16*2显示,5*8点阵,8位数据口
	write_cmd(0x0c);     //设置开显示,不显示光标
	write_cmd(0x06);     //设置写一个字符后地址指针自动加1
	write_cmd(0x01);     //显示清0,数据指针清0
}

//把字符写入用户字模RAM
void Write_CGRAM(void)
{
	static unsigned char i=0;	//帧数
	unsigned char j,k;//j为字符的序号,k为每个字符的行序号
	
	for(j=0;j<8;j++)
	{
		write_cmd(0x40+j*8);	//此处的0x40为写入CGRAM命令的固定位,
								//不理解可以看12节,j*8为对应地址
		//此处的写入数据即将输出的字模转为所需的显示顺序依次存入CGRAM
		if(j<4)		//先将第一行4个字符存入
		{
			for(k=0;k<8;k++)
			{
				write_data(picture[i][2*8*j+k]);
			}
		}
		else	//再存入第二行4个字符
		{
			for(k=0;k<8;k++)
			{
				write_data(picture[i][2*8*(j-4)+8+k]);
			}
		}
	}
	
	i++;
	if(i==17)
		i=0;
}

//LCD显示一帧画面
void display()
{	
		unsigned char m;
		//按顺序把CGRAM中的字符存入DDRAM中进行显示
		write_cmd(0x80);
		for(m=0;m<4;m++)
		{
			write_data(m);	//从CGRAM中进行显示直接输出对应字符序号即可
		}	
		write_cmd(0xc0);
		for(m=0;m<4;m++)
		{
			write_data(m+4);
		}
}
//100ms延时
void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 5;
	j = 52;
	k = 195;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void main()
{
	lcd_init();
	while(1)
	{
		Write_CGRAM();
		display();
		Delay100ms();	//适当延时,10帧/s
	}
}