1602字符液晶显示

环境

软件

  • uVision V4.02
  • ISIS Professional 7.8

芯片

  • AT89C51
  • LM016L(LCD)

仿真图

1602字符液晶显示_第1张图片

实现效果

实现功能有四个

  • 水平滚动显示字符串
  • 带光标显示随机算术式
  • 全码表字符显示
  • CGRAM自定义字符显示
    1602字符液晶显示_第2张图片

相关代码及资源

https://github.com/duganlx/DSP

操作小记

LCD1602相关函数编写

指令表

1602字符液晶显示_第3张图片

指令说明

上述表中,1为高电平0为低电平

  • 指令1:清显示:,光标复位到地址00H位置
  • 指令2:光标返回:,光标返回到地址00H
  • 指令3:光标和显示模式设置
    • I/D:光标移动方向,1:右移,0:左移
    • S:屏幕上所有文字是否左移动或右移:1:有效,0:无效
  • 指令4:显示开关控制
    • D:控制整体显示的开关,1:开显示,0:关显示
    • C:控制光标的开关,1:有光标,0:无光标
    • B:控制光标是否闪烁,1:闪烁,0:不闪烁
  • 指令5:光标或显示移位S/C:1:移动显示的文字,0:移动光标
  • 指令6:功能设置命令
    • DL:1:4位总线,0:8位总线(有些模块反过来,比如这里所用的就是)
    • N:0:单行显示,1:双行显示
    • F:0: 5 ∗ 7 5*7 57的点阵字符,1: 5 ∗ 10 5*10 510的点阵字符
  • 指令7:字符发生器RAM地址设置
  • 指令8:DDRAM地址设置
  • 指令9:读忙信号和光标地址
    • BF:1:忙,此时模块不能接收命令或数据,0:不忙
  • 指令10:写数据
  • 指令11:读数据

其他说明

  1. 液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平(不忙),否则该指令失效
  2. 当显示字符时要先输入显示字符地址,以下是内部显示地址
    1602字符液晶显示_第4张图片
    所以若要写入字符到第二行第一个(40H),那么实际上写入的命令数据为C0H0100_0000(40H)+1000_0000(80H)=1100_0000(C0H)

基本操作时序

说明下,RS为寄存器选择,高电平时选择寄存器,低电平时选择指令寄存器RW为读写信号线,高电平时进行读操作低电平时进行写操作EN为使能端,当EN端由高电平跳变成低电平时,液晶模块执行命令L表示低电平,H表示高电平。

  • 读状态
    • 输入:RS=L; RW=H; E=H
    • 输出:D0~7=状态字
  • 写指令
    • 输入:RS=L; RW=L; E=下降沿脉冲; D0~7=指令码
    • 输出:null
  • 读数据
    • 输入:RS=H; RW=H; E=H
    • 输出:D0~7=数据
  • 写数据
    • 输入:RS=H; RW=L; E=下降沿脉冲; D0~7=数据
    • 输出:null
时序图

1602字符液晶显示_第5张图片

时序参数

1602字符液晶显示_第6张图片

字符代码与字符图形对应关系

1602字符液晶显示_第7张图片

使用样例

比如要输出A,查询表可知对应代码为0100_0001,而后显示时模块把地址41H中的点阵字符图形显示出来,我们就可以看到A

头文件

#include
#include //使用_nop_();
#include

宏定义

// RS为寄存器选择,高电平时选择寄存器,低电平时选择指令寄存器
sbit RS = P2^0;
// RW为读写信号线,高电平时进行读操作,低电平时进行写操作 
sbit RW = P2^1;
// EN为使能端,当EN端由高电平跳变成低电平时,液晶模块执行命令
sbit EN = P2^2;

初始化函数

/**
* LCD初始化
*
* @return
*/
void init()
{
	/*
	  0011_1000 置功能
 	  DL=1 --> 8位总线
	  N=0  --> 单行显示
	  F=0  -->	显示5x7的点阵字符
	*/	
	write_cmd(0x38);
	
	/*
	  0000_0001 清显示
	  指令码01H,光标复位到地址00H位置
	*/ 
	write_cmd(0x01);
	
	/*
	  0000_0110 置输入模式
	  I/D=1 --> 光标右移
	  S=0   --> 屏幕上所有文字左移或右移
	*/
	write_cmd(0x06);
	
	/*
	  0000_1100	显示开/关控制
	  D=1 --> 开显示
	  C=0 --> 无光标
	  B=0 --> 光标不闪烁
	*/
	write_cmd(0x0C);
}

检测BF(busy flag)位状态

/*
* 检测BF(busy flag)位状态
* 
* @return
*/
void test_BF()
{
	unsigned char LCD_status;
	do{
		P0 = 0xFF; // LCD1602读取状态数据,必须有一个上拉电平
		EN = 0; RS = 0; RW = 1; // RS为0时,P0的数据为命令
		EN=1;// 让RS和RW设置有效
		LCD_status = P0;
		_nop_(); _nop_();
		EN = 0;
	}while(LCD_status&0x80); // 1000_0000 忙碌状态
}

写数据

/*
* 写数据(一位一位的写)
*
* @param data8 八位数据
* @return
*/
void write_data(unsigned char data8)
{
	test_BF();
	EN = 0; RS = 1; RW = 0;
	P0 = data8;
	EN = 1; _nop_(); EN = 0;
}

写命令

/*
* 写命令
*
* @param cmd8 八位命令
* @return
*/
void write_cmd(unsigned char cmd8)
{
	test_BF();
	EN = 0; RS = 0; RW = 0;
	P0 = cmd8;
	EN = 1; _nop_(); EN = 0;
}

写字符串

/**
* 写字符串
*
* @param r row
* @param c column
* @param str 字符串
* @return
*/
void write_str(int r, int c, char *str)
{
	int i=0;	
	unsigned char Addressx[] = {0x80, 0xC0};
	unsigned char StartAdd = (Addressx[r] | c);//按位或

	write_cmd(StartAdd);
	
	for(i = 0; i < 16; i++){
		if(str[i]==0) break;
		write_data(str[i]);
	}
	// 如果不够16位,用空格填充
	for(;i < 16; i++){
		write_data(' '); 	
	}
}

主函数编写

头文件

#include
#include
#include
#include
#include

宏定义

sbit switch1 = P3^0;
sbit switch2 = P3^1;
sbit switch3 = P3^2;
sbit switch4 = P3^3;

unsigned char *strCode="                I Love You!";

引入外部函数

extern void delay_ms(int ms);
extern void init();
extern void write_cmd(unsigned char cmd8);
extern void write_str(int r, int c, char *str);
extern void write_data(unsigned char data8);

功能1:水平滚动文字

void h_scroll_words()
{
	int i;
	init();
	write_str(0,0, "    Example-1   ");
	while(1)
	{
		/*
		  fun1
		*/
		for(i = 0; i<strlen(strCode); i++)
		{
			write_str(1, 0, strCode + i);
			delay_ms(100);
		}
		
		if(switch1 != 0) break;
	}

}

功能2:随机数相加

void random_words()
{
	int a,b,i;
	unsigned char tempStr[17];

	init();
	write_cmd(0x0F); //0000_1111:显示开/关控制
	write_str(0,0, "    Example-2   ");

	while(1)
	{
		//srand(TH0);
		a = rand()%10;
		b = rand()%10;
		sprintf(tempStr, "%d+%d=%d", a, b, a+b);
		write_cmd(0xC0|0x05); //1100_0101
		for(i = 0; i < 11; i++)
		{
			if(tempStr[i]) write_data(tempStr[i]); 
			else write_data(' ');
			delay_ms(150);
		}
		write_str(1, 0, "           ");
		delay_ms(150);
		if(switch2 != 0) break;
	}

}

功能3:全码显示

void all_str_code()
{
 	int i,j;
	init();
	write_cmd(0x0F);//0000_1111:显示开/关控制 
	write_str(0,0, "    Example-3   "); 	
	while(1)
	{
		write_cmd(0xC0);
		for(i = 0x20; i <= 0xFF; i++)
		{
			if(switch3) return;
			if(i >= 0x80 && i < 0xa0) continue;

			if((++j) == 16)
			{
				write_str(1, 0, "           ");
				j = 0;
				//如果命令让它从第二行写,就重置到第二行第一个地址
				write_cmd(0xC0);
			}
			//if(i == 0xFF) i = 0x20;
			write_data(i);
			delay_ms(50);
		}
	
	}

}

功能4:自定义字符显示

void character_str_code()
{
  	int i = 0;
  	unsigned char CC[] = {0x1F,0x11,0x1F,0x11,0x1F,0x11,0x1F,0x00};
  	init();
	write_cmd(0x0F); // 0000_1111:显示开关控制
	write_str(0, 0, "    Example-4   ");
	write_cmd(0x40); //0100_0000:置字符发生存贮器地址
	for(i = 0; i < 8; i++)
	{
		// 通过上面write_LCD_CMD(0x40); 把数组写到CGRAM
		write_data(CC[i]);	
	}
	while(1)
	{
		write_cmd(0xC0);
		for(i = 0; i < 16; i++)
		{
			if(switch4) return;
			write_data(0);
			delay_ms(50);
		}
		//当满行显示后清屏
		write_str(1, 0, "                ");
		delay_ms(150);
	}
	

}

主函数

void main()
{
	while(1)
	{
		if(switch1 == 0)
		{
			h_scroll_words();
		}
		else if(switch2 == 0)
		{
			random_words();
		}
		else if(switch3 == 0)
		{
			all_str_code();
		}
		else if(switch4 == 0)
		{
			character_str_code();
		}
	}
}

你可能感兴趣的:(8051单片机,stc,lcd1602,单片机,嵌入式)