单片机控制LCD2004液晶屏之模块化编程

这里将我写的STC12C5A60S2单片机控制LCD2004液晶屏的程序共享一下,如有不足,敬请指出!

代码结构图:

程序下载链接:https://download.csdn.net/download/yagnruinihao/16682925点击下载

Proteus仿真图下载链接:https://download.csdn.net/download/yagnruinihao/16682933点击下载

测试程序:LCD2004测试.c

#include <stdlib.h> 
#include "common.h"  
#include "lcd2004.h"  

void main(void)  
{     
    unsigned short int i ;  
    unsigned char  author[]="Author:YangRui" ;  
  
    LCD2004_Init();  
    for(i=0 ; i<sizeof(author)-1 ; i++)  
    {  
        LCD2004_AddressWriteByte(LCD2004_ROW0,i,author[i]);  
    }  
    LCD2004_AddressWriteString(LCD2004_ROW1,0,"QQ:279729201");  
    LCD2004_AddressWriteString(LCD2004_ROW2,0,"yangrui90s@163.com");  
    LCD2004_AddressWriteString(LCD2004_ROW3,0,"Date:2014/02/26");       
    while(1);     
}  

/*################lcd2004.h################*/ 

#ifndef __LCD2004_H__
#define __LCD2004_H__

#include "common.h"

//硬件接口定义,与硬件电路相对应
sbit LCD2004_RS_Bit = P2^6;//LCD2004的RS端口,高电平表示数据、低电平表示命令
sbit LCD2004_RW_Bit = P2^5;//LCD2004的RW端口,高电平表示读操作、低电平表示写操作
sbit LCD2004_EN_Bit = P2^7;//LCD2004的EN端口,高电平表示读状态或读数据、高脉冲表示写指令或写数据
#define LCD2004_DATA_PORT	P0//LCD2004的数据口D0~D7,其中Px^0端口接DB0,Px^7端口接DB7,其他接口以此类推

/*  
    RS          Rw  
    0           0   ---->写命令
    0           1   ---->读状态
    1           0   ---->写数据
    1           1   ---->读数据
          
*/ 

//LCD2004的RS端口选择
#define LCD2004_DATA_OPERATION		1//数据模式
#define LCD2004_COMMAND_OPERATION	0//命令模式

//LCD2004的RW端口选择
#define LCD2004_READ_OPERATION		1//读操作
#define LCD2004_WRITE_OPERATION		0//写操作

//LCD2004的EN端口选择
#define LCD2004_ENABLE				1//允许操作LCD2004
#define LCD2004_DISABLE				0//禁止操作LCD2004


//显示模式:16X2个字符, 5X7点阵,8位数据口
#define LCD2004_DEFAULT_DISPALY_MODE	0x38

/*
====================================================
LCD2004设置:显示允许或禁止、光标显示或禁止、光标闪烁或禁止  
====================================================
/*  
0   0   0   0   1   D   C   B     
                    |   |   |------光标闪烁  : 1-->允许 ; 0-->禁止  
                    |   |----------光标显示	 : 1-->允许 ; 0-->禁止  
                    |-------------液晶屏显示 : 1-->允许 ; 0-->禁止   
      
*/
#define LCD2004_DISPLAY_ENABLE			0X04				 //允许液晶显示
#define LCD2004_DISPLAY_DISABLE			(0X04 & (~(0x01<<2)))//禁止液晶显示

#define LCD2004_CURSOR_DISPLAY_ENABLE	0X02				 //允许光标显示
#define LCD2004_CURSOR_DISPLAY_DISABLE	(0X02 & (~(0x01<<1)))//禁止光标显示

#define LCD2004_CURSOR_BLINK_ENABLE 	0X01				 //允许光标闪烁
#define LCD2004_CURSOR_BLINK_DISABLE 	(0X01 & (~(0x01<<0)))//禁止光标闪烁

//默认设置:lcd显示,光标不显示,光标不闪烁
#define LCD2004_DEFAULT_DISPLAY_AND_CURSOR_MODE 0x08 				 | \
										LCD2004_DISPLAY_ENABLE		 | \
										LCD2004_CURSOR_DISPLAY_DISABLE| \
										LCD2004_CURSOR_BLINK_DISABLE

/*
====================================================
LCD2004设置:指针加一或减一、光标位置加一或减一
==================================================== 
0   0   0   0   0   1   N   S  
                        |   |-----  屏幕移动:1-->允许 ; 0-->禁止 
                        |---------  N=1:读或者写一个字符后地址指针加1,且光标加1  
                                    N=0:度或者写一个字符后地址指针减1,且光标减1  

                        当S=1时 :  
                            若N=1,整屏幕左移  
                              N=0,整屏幕右移   
                            以达到光标不移动,而整个屏幕移动的效果  
*/   	 	
									
#define LCD2004_POINT_AND_CURSOR_PLUS		0X02				 //指针加一、光标加一
#define LCD2004_POINT_AND_CURSOR_MINUS		(0X02 & (~(0X01<<1)))//指针减一、光标减一

#define LCD2004_SCREEN_MOVE_ENABLE			0x01				 //允许屏幕移动
#define LCD2004_SCREEN_MOVE_DISABLE			(0x01 & (~(0X01<<0)))//禁止屏幕移动

//默认设置:光标和指针加一,屏幕不移动
#define LCD2004_DEFAULT_POINT_AND_POINT_ADDRESS_MODE 0X04				 | \
											LCD2004_POINT_AND_CURSOR_PLUS| \
											LCD2004_SCREEN_MOVE_DISABLE

//行位置参数,注意行地址从0开始
#define LCD2004_ROW0	0				//第0行
#define LCD2004_ROW1	1				//第1行
#define LCD2004_ROW2	2				//第2行
#define LCD2004_ROW3	3				//第3行
#define LCD2004_MIN_ROW LCD2004_ROW0	//行数的最小值,为LCD2004_ROW0,即0
#define LCD2440_MAX_ROW	LCD2004_ROW3	//行数的最小值,为LCD2004_ROW3,即3

//列位置参数,注意列地址从0开始
#define LCD2004_ROW_LENGHT	0X14 		//每一行的长度为0x14,即20

//每一行的起始地址
#define LCD2004_ROW0_ADDRESS_START (0X80)											//第0行起始地址
#define LCD2004_ROW1_ADDRESS_START (0X80+0X40)										//第1行起始地址
#define LCD2004_ROW2_ADDRESS_START (LCD2004_ROW0_ADDRESS_START+LCD2004_ROW_LENGHT)	//第2行起始地址
#define LCD2004_ROW3_ADDRESS_START (LCD2004_ROW1_ADDRESS_START+LCD2004_ROW_LENGHT)	//第3行起始地址

//命令集指令
#define LCD2004_CLEAN_ALL_DISPALY			0x01//清屏指令
#define LCD2004_CURSOR_RETURN_TO_ORIGIN		0x02//光标归位指令

/*****************外部接口函数******************/
//lcd2004初始化
extern void LCD2004_Init(void) ;

//lcd20041清屏
extern void LCD2004_CleanAll(void) ;

//光标归位
extern void LCD2004_CursorHoming(void);

//lcd2004地址写字节
extern void LCD2004_AddressWriteByte(unsigned char Row,unsigned char Column,unsigned char DataValue);

//lcd2004地址写字符串
extern void LCD2004_AddressWriteString(unsigned char Row,unsigned char Column,unsigned char *String);

//写命令
extern void LCD2004_WriteCommand(unsigned char CommandValue);

//写数据
extern void LCD2004_WriteData(unsigned char DataValue);

#endif	/*__LCD2004_H__*/

/*################lcd2004.c################*

/***************************************************************************
模    块:LCD2004.c  
说    明:LCD2004驱动程序
版    本:Version3.0		2021/01/01 06:00
编译环境:Keil_C51  V9.55
主控芯片:STC12C5A60S2  	@11.0592MHZ
		 STC89C52RC     @11.0592MHZ
		 AT89C51		@11.0592MHZ	@Proteus8.9仿真
作    者:杨瑞
联系方式:【 QQ 】279729201
		 【邮箱】279729201@qq.com            
		          yangrui90s@163.com
		 【电话】13630279531
		 							
	经过测试J204A(也称2004A,每行20字符,显示4行)液晶屏和1602液晶屏的
	使用方法几乎是一样的,不过也是有区别的,在1602液晶屏中,用来寄存待显
	示字符代码的DDRAM共有80个字节,而J204A能够一次性显示的字符是80字
	节,这里不是巧合,即J204A只是将LCD1602的DDRAM的80个字符全部显示出
	来而已。
	
	第一行首地址	:0x80
	第二行首地址	:0x80+0x40
	第三行首地址	:0x80+20
	第四行首地址	:0x80+0x40+20

	可以注意到,第一行和第三行、第二行和第四行的地址是分别连续的。 经过
	实验验证,可以得出这样的结论:J204A是将LCD1602的DDRAM的0~19地址
	的数据映射显示在J204A的第一行,LCD1602的DDRAM的20~39地址的数据映
	射显示在第三行 ; LCD1602的DDRAM的40~59地址的数据映射显示在J204A
	的第二行,将LCD1602的DDRAM的60~79地址的数据映射显示在J204A的第四行。
	
----------------------------------------------------------------------------
	J204A的程序和LCD1602的程序很相似,这里的程序是由LCD1602程序修改而来。
----------------------------------------------------------------------------

修改记录:
=================
	2021/01/01 06:00
	记录:
		1.规范部分函数。
		2.取消Delay80usForLcd2004(),调用函数Delay_SomeNop(10)代替消Delay80usForLcd2004()函数。
		3.增加ST89C52RC @11.0592MHZ 和AT89C51 @11.0592MHZ @Proteus8.9仿真测试,经测试此代码
		  均可适用。
=================
=================
	2017/01/6 12:08
	记录:
		1.增加中文注释。
		2.修改函数名称模式,由"模块名称"(大写)+"_"+功能函数名称构成,例如lcd2004ReadStatus修改为LCD2004_ReadStatus。
		3.修改延时函数,将Delay1msForLcd2004函数修改为Delay80usForLcd2004函数。注意,这两个函数都是
		  由STC-ISP生成,Delay80usForLcd2004函数由STC-ISP V6.85Q的“软件延时计算器”针对STC-Y3指令集
		  @11.0592MHZ自动生成。经过测试,延时59us可能会出现只书写部分内容的情况,延时60us正好可以。
		  为了安全,也可以将此延时修改的更长。
=================
=================
	2014/04/31 20:09
	记录:
		1.解决大工程中,因未安装LCD2004而导致的工程卡死在函数
		lcd2004CheckBusy()的问题,将
		do{
				;
		}while( (lcd2004ReadStatus()) & 0x80));
		修改为
			do{
			i++;
		}while( ((lcd2004ReadStatus()) & 0x80)  && (i<10));
		因为在未安装LCD2004时,通过"读状态"函数lcd2004ReadStatus()读回来的是0xff,
		如果采用第一种算法,会导致程序"卡死"。

=================

=================
	2014/02/27 08:25
	记录:
		1.修改函数char lcd2004AddressWriteByte(...)
			{
				if(column<0|| column > 19|| \
			   		( (row != LCD2004_ROW0) &&(row != LCD2004_ROW1))&& \ 
			   		  (row != LCD2004_ROW2) &&(row != LCD2004_ROW3)) \
			   		)
				{
					return -1;
				}
				......

				return 0 ;
			}
			为
			void lcd2004AddressWriteByte(unsigned char row,unsigned char column,unsigned char dataCode)
			{
				//省略if判断

				//无返回值
			}	

			这里省略判断是因为LCD2004和LCD1602的特殊关系,在LCD1602的DDRAM中
			共有80个字符,每一行的显示缓存有40个字符长度,为了调用的安全性,
			在lcd1602.c中相同功能的函数是有if判断,但是对于LCD2004,第三行和
			第四行所显示的内容分别就是LCD1602的DDRAM的第一行的显示缓冲DDRAM的
			后20个字符、第二行的显示缓冲DDRAM的后20个字符。这可以通过以下方法
			验证:
				首先,省略if判断,然后调用函数
				lcd2004AddressWriteString(LCD2004_ROW2,0,"2014/02/27");
				和调用函数
				lcd2004AddressWriteString(LCD2004_ROW0,20,"2014/02/27");
				效果是一样的

			为了调用的灵活性,这里省略了if判断,并将函数改为无返回值的类型。			
=================


=================
	2014/02/24 23:44
	记录:
		1.增加函数lcd2004AddressWriteString(...)
=================

***************************************************************************/
#include <string.h>
#include "lcd2004.h"

/*外部接口函数在lcd2004.h中声明*/
/*****************内部函数******************/
unsigned char LCD2004_ReadStatus(void) ;
void LCD2004_CheckBusy(void) ;
/**********************************************/

/******************************************************************
 - 函数名称:LCD2004_ReadStatus
 - 功能描述:读取LCD2004状态值
 - 函数属性:内部函数
 - 参数说明:无
 - 返回说明:LCD2004的状态值
 ******************************************************************/
unsigned char LCD2004_ReadStatus(void)
{
	unsigned char statusCode ;

	LCD2004_EN_Bit = LCD2004_DISABLE ;			//禁止操作LCD2004
	LCD2004_RS_Bit = LCD2004_COMMAND_OPERATION ;//命令模式
	LCD2004_RW_Bit = LCD2004_READ_OPERATION ;	//读操作

	LCD2004_DATA_PORT = 0XFF ;					
	Delay_SomeNop(10);							//注意:这里延时不能少,否则不会有效果
	LCD2004_EN_Bit = LCD2004_ENABLE ;			//允许操作LCD2004
	Delay_SomeNop(10);							//注意:这里延时不能少,否则不会有效果
	
	statusCode = LCD2004_DATA_PORT ;			//读取状态值	
	LCD2004_EN_Bit = LCD2004_DISABLE ;			//禁止操作LCD2004

	return statusCode ;
}

/******************************************************************
 - 函数名称:LCD2004_CheckBusy
 - 功能描述:判断LCD2004是否忙碌:若忙碌则等待;若空闲则执行任务
 - 函数属性:内部函数
 - 参数说明:无
 - 返回说明:无
 - 注	   :当LCD2004_DATA_PORT[7]等于1,表示LCD2004忙碌,则需要等待一会儿
			 当LCD2004_DATA_PORT[7]等于0,表示LCD2004空闲,则需要继续执行后面的任务
				  LCD2004_DATA_PORT[7]==0,lcd2004 is free.
 - 补    充:这里的“10”是经过测试的,测试中,利用串口打印i的值为1,这里写10已经足够大了。
 ******************************************************************/
void LCD2004_CheckBusy(void)
{
	unsigned short int i=0 ;
	do{
		i++;
	}while( (LCD2004_ReadStatus() & 0x80) && (i<10));
}

/******************************************************************
 - 函数名称:LCD2004_WriteCommand
 - 功能描述:LCD2004写命令
 - 函数属性:外部函数,供用户调用
 - 参数说明:需要发送给LCD2004的指令值
 - 返回说明:无
 ******************************************************************/
void LCD2004_WriteCommand(unsigned char CommandValue)
{
	
	LCD2004_CheckBusy();
	LCD2004_EN_Bit = LCD2004_DISABLE ;			//禁止操作LCD2004
	LCD2004_RS_Bit = LCD2004_COMMAND_OPERATION ;//命令模式
	LCD2004_RW_Bit = LCD2004_WRITE_OPERATION ;	//写操作

	LCD2004_DATA_PORT = CommandValue ;			//发送指令值
	//Delay_SomeNop(10);
	LCD2004_EN_Bit = LCD2004_ENABLE ;			//允许操作LCD2004
	//Delay_SomeNop(10);
	
	LCD2004_EN_Bit = LCD2004_DISABLE ;			//禁止操作LCD2004
}

/******************************************************************
 - 函数名称:LCD2004_WriteData
 - 功能描述:LCD2004写数据
 - 函数属性:外部函数,供用户调用
 - 参数说明:需要发送给LCD2004的数据
 - 返回说明:无
 ******************************************************************/
void LCD2004_WriteData(unsigned char DataValue)
{	
	
	LCD2004_CheckBusy() ;	
	LCD2004_EN_Bit = LCD2004_DISABLE ;			//禁止操作LCD2004
	LCD2004_RS_Bit = LCD2004_DATA_OPERATION ;	//数据模式
	LCD2004_RW_Bit = LCD2004_WRITE_OPERATION ;	//写操作

	LCD2004_DATA_PORT = DataValue;				//发送数据
	//Delay_SomeNop(10);
	LCD2004_EN_Bit = LCD2004_ENABLE ;			//允许操作LCD2004
	//Delay_SomeNop(10);
	
	LCD2004_EN_Bit = LCD2004_DISABLE ;	  		//禁止操作LCD2004 
}

/******************************************************************
 - 函数名称:LCD2004_CleanAll
 - 功能描述:清除屏幕显示
 - 函数属性:外部函数,供用户调用
 - 参数说明:无
 - 返回说明:无
 - 注	   :清除屏幕显示,光标归位(左上角),地址计数器AC设为0
 ******************************************************************/
void LCD2004_CleanAll(void)
{
	LCD2004_WriteCommand(LCD2004_CLEAN_ALL_DISPALY);
}

/******************************************************************
 - 函数名称:LCD2004_CursorHoming
 - 功能描述:光标归位
 - 函数属性:外部函数,供用户调用
 - 参数说明:无
 - 返回说明:无
 - 注	   :光标归位,当屏幕移动显示时,lcd2004显示所有数据后,
			 调用此函数,屏幕显示的所有东西都会归位。光标在第一
			 个位置(0x80)。
 ******************************************************************/
void LCD2004_CursorHoming(void)
{
	LCD2004_WriteCommand(LCD2004_CURSOR_RETURN_TO_ORIGIN);
}

/******************************************************************
 - 函数名称:LCD2004_Init
 - 功能描述:LCD2004初始化
 - 函数属性:外部函数,供用户调用
 - 参数说明:无
 - 返回说明:无
 - 注	   :设置(1)显示模式
            (2)液晶显示允许或禁止、光标显示允许或禁止、光标闪烁允许或禁止
		    (3)地址指针加一或减一、光标指针加一或减一、屏幕左移或右移
		   
		    可通过修改LCD2004.H中的LCD2004_DEFAULT_DISPALY_MODE、LCD2004_DEFAULT_DISPLAY_AND_CURSOR_MODE、
		    LCD2004_DEFAULT_POINT_AND_POINT_ADDRESS_MODE达到不同的显示效果。
 ******************************************************************/
void LCD2004_Init(void)
{
	LCD2004_CleanAll();
	LCD2004_WriteCommand(LCD2004_DEFAULT_DISPALY_MODE);
	LCD2004_WriteCommand(LCD2004_DEFAULT_DISPLAY_AND_CURSOR_MODE);
	LCD2004_WriteCommand(LCD2004_DEFAULT_POINT_AND_POINT_ADDRESS_MODE);

	/*可忽略,在LCD2004_CleanAll()中隐含了该功能*/
	LCD2004_CursorHoming();
}

/******************************************************************
 - 函数名称:LCD2004_AddressWriteByte
 - 功能描述:在LCD2004的Row行Column列写入数据DataValue
 - 函数属性:外部函数,供用户调用
 - 参数说明:Row-->行地址。
			 Column-->列地址。
			 DataValue-->需要写入的数据。
 - 返回说明:无
 - 注	   :行地址和列地址都是从0开始的。
       
			 想在LCD2004的第0行第2列显示阿里伯数字5,调用方式为
			 LCD2004_AddressWriteByte(LCD2004_ROW0,2,‘5’);
 ******************************************************************/
void LCD2004_AddressWriteByte(unsigned char Row,unsigned char Column,unsigned char DataValue)
{
	
	if(LCD2004_ROW0 == Row)	//注意这里==的两边顺序,技巧!
		LCD2004_WriteCommand(LCD2004_ROW0_ADDRESS_START+Column) ;
	else if(LCD2004_ROW1 == Row)//注意这里==的两边顺序,技巧!
		LCD2004_WriteCommand(LCD2004_ROW1_ADDRESS_START+Column) ;
	else if(LCD2004_ROW2 == Row)//注意这里==的两边顺序,技巧!
		LCD2004_WriteCommand(LCD2004_ROW2_ADDRESS_START+Column) ;
	else if(LCD2004_ROW3 == Row)//注意这里==的两边顺序,技巧!
		LCD2004_WriteCommand(LCD2004_ROW3_ADDRESS_START+Column) ;
	
	LCD2004_WriteData(DataValue);
}

/******************************************************************
 - 函数名称:LCD2004_AddressWriteString
 - 功能描述:从LCD2004的Row行Column列开始写入字符串String
 - 函数属性:外部函数,供用户调用
 - 参数说明:Row-->行地址。
			 Column-->列地址。
			 String-->需要写入的字符串。
 - 返回说明:无
 - 注	   :行地址和列地址都是从0开始的。
 
			 想在LCD2004的第0行第2列显示"test",调用方式为
			 LCD2004_AddressWriteString(LCD2004_ROW0,2,"test");
	   
			 这里使用的是strlen,而不是sizeof。
 ******************************************************************/
void LCD2004_AddressWriteString(unsigned char Row,unsigned char Column,unsigned char *String)
{
	unsigned char length = strlen(String) ;
	
	if(LCD2004_ROW0 == Row)//注意这里==的两边顺序,技巧!
		LCD2004_WriteCommand(LCD2004_ROW0_ADDRESS_START+Column) ;
	else if(LCD2004_ROW1 == Row)//注意这里==的两边顺序,技巧!
		LCD2004_WriteCommand(LCD2004_ROW1_ADDRESS_START+Column) ;
	else if(LCD2004_ROW2 == Row)//注意这里==的两边顺序,技巧!
		LCD2004_WriteCommand(LCD2004_ROW2_ADDRESS_START+Column) ;
	else if(LCD2004_ROW3 == Row)//注意这里==的两边顺序,技巧!
		LCD2004_WriteCommand(LCD2004_ROW3_ADDRESS_START+Column) ;
	
	while(length--) 
	{
		LCD2004_WriteData(*String);
		String++;
	}
}

/*################common.h################*/ 

#ifndef __COMMON_H__
#define __COMMON_H__

#include <reg51.h>

#define DEBUG  1	//用于前期调试,后期可以屏蔽本行代码,达到减少目标文件大小的目标


/*****************外部接口函数******************/
//延时(不精准延时)函数
void Delay_SomeNop(long  time);


#endif /*__COMMON_H__*/

/*################common.c################*/ 

#include <intrins.h> 
#include "common.h"

/******************************************************************
 - 函数名称:Delay_SomeNop
 - 功能描述:延时函数(不精准延时)
 - 函数属性:外部函数,供用户调用
 - 参数说明:time需要延时时间		 
 - 返回说明:无
 - 注	   :无
 ******************************************************************/
void Delay_SomeNop(long  time)
{
	while(time--)
	{
		_nop_();
	}
}

 

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刺客阿瑞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值