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

这里将我写的STC12C5A60S2控制LCD1602的程序共享一下,是希望前辈们指点。

(说明:以下代码只需要修改.h文件中含有 “【根据实际需要修改】” 字样的部分,就可以达到复用的效果)

 (提示:因为其中的宏较多,建议source insight查看代码)


测试程序main.c:

#include <string.h>
#include "common.h"
#include "LCD1602.h"
void main(void)
{
	UB8 i ;
	UB8 author[] = "Author:YangRui" ;
	Lcd1602Init();
	for(i=0 ; i<sizeof(author)-1 ; i++)
	{
	Lcd1602AddressWriteByte(LCD1602_ROW0,i,author[i]);
	}
	Lcd1602AddressWriteString(LCD1602_ROW1,0,"QQ:279729201") ;
	while(1);
}

/*################lcd1602.h start ################*/  

#ifndef __LCD1602_H__
#define __LCD1602_H__

#include "common.h"

sbit lcd1602_rs_bit = P2^6;/*【根据实际需要修改】*/
sbit lcd1602_rw_bit = P2^5;/*【根据实际需要修改】*/
sbit lcd1602_en_bit = P2^7;/*【根据实际需要修改】*/
 

#define LCD1602_DATA_PORT	P0/*【根据实际需要修改】*/
/*default type:  
px^0---DB0(LSB)  
px^1---DB1  
px^2---DB2  	   
px^3---DB3  
px^4---DB4  
px^5---DB5  
px^6---DB6  
px^7---DB7(MSB)  
*/

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

/*LCD1602 RW 引脚选择*/
#define LCD1602_READ_OPERATION		1/*读操作*/
#define LCD1602_WRITE_OPERATION		0/*写操作*/

/*LCD1602 RS 引脚选择*/
#define LCD1602_DATA_OPERATION		1/*数据模式*/
#define LCD1602_COMMAND_OPERATION	0/*命令模式*/

/*LCD1602 EN 引脚选择*/
#define LCD1602_ENABLE				1/*允许操作LCD1602*/
#define LCD1602_DISABLE				0/*禁止操作LCD1602*/


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

/*
====================================================
LCD1602设置:显示允许或禁止、光标显示或禁止、光标闪烁或禁止  
====================================================
/*  
0   0   0   0   1   D   C   B     
                    |   |   |------光标闪烁  : 1-->允许 ; 0-->禁止  
                    |   |----------光标显示	 : 1-->允许 ; 0-->禁止  
                    |-------------液晶屏显示 : 1-->允许 ; 0-->禁止   
      
*/
#define LCD1602_DISPLAY_ENABLE			0X04				 /*允许液晶显示*/
#define LCD1602_CURSOR_DISPLAY_ENABLE	0X02				 /*允许光标显示*/
#define LCD1602_CURSOR_BLINK_ENABLE 	0X01				 /*允许光标闪烁*/

#define LCD1602_DISPLAY_DISABLE			(0X04 & (~(0x01<<2)))/*禁止液晶显示*/
#define LCD1602_CURSOR_DISPLAY_DISABLE	(0X02 & (~(0x01<<1)))/*禁止光标显示*/
#define LCD1602_CURSOR_BLINK_DISABLE 	(0X01 & (~(0x01<<0)))/*禁止光标闪烁*/

/*默认设置:lcd显示,光标显示,光标闪烁*/					 /*【根据实际需要修改】*/
#define LCD1602_DEFAULT_DISPLAY_AND_CURSOR_MODE 0x08 				 | \
										LCD1602_DISPLAY_ENABLE		 | \
										LCD1602_CURSOR_DISPLAY_ENABLE| \
										LCD1602_CURSOR_BLINK_ENABLE

/*
====================================================
LCD1602设置:指针加一或减一、光标位置加一或减一
==================================================== 
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 LCD1602_POINT_AND_CURSOR_PLUS		0X02				 /*指针加一、光标加一*/
#define LCD1602_SCREEN_MOVE_ENABLE			0x01				 /*允许屏幕移动*/

#define LCD1602_POINT_AND_CURSOR_MINUS		(0X02 & (~(0X01<<1)))/*指针减一、光标减一*/
#define LCD1602_SCREEN_MOVE_DISABLE			(0x01 & (~(0X01<<0)))/*禁止屏幕移动*/

/*默认设置:光标和指针加一,屏幕不移动*/						     /*【根据实际需要修改】*/
#define LCD1602_DEFAULT_POINT_AND_POINT_ADDRESS_MODE 0X04				 | \
											LCD1602_POINT_AND_CURSOR_PLUS| \
											LCD1602_SCREEN_MOVE_DISABLE

/*行位置参数,注意行地址从0开始*/											
#define LCD1602_ROW0	0										/*第0行*/		
#define LCD1602_ROW1	1										/*第1行*/		
#define LCD1602_MIN_ROW	LCD1602_ROW0							/*行数的最小值,为LCD1602_ROW0,即0*/
#define LCD1602_MAX_ROW	LCD1602_ROW1							/*行数的最大值,为LCD1602_ROW1,即1*/

/*列位置参数,注意列地址从0开始*/
#define LCD1602_ROW_LENGHT	0x28 								/*每一行的长度为0x28,即40*/
#define LCD1602_MIN_COLUMN	0									/*列数的最小值,为0*/
#define LCD1602_MAX_COLUMN	(LCD1602_ROW_LENGHT-1)				/*列数的最大值,为39*/

/*每一行的起始地址*/
#define LCD1602_ROW0_ADDRESS_START	0X80						/*第0行起始地址*/
#define LCD1602_ROW1_ADDRESS_START	(0X80+0X40)					/*第1行起始地址*/

/*每一行的结束地址*/
#define LCD1602_ROW0_ADDRESS_END (LCD1602_ROW0_ADDRESS_START+LCD1602_ROW_LENGHT)/*第0行结束地址*/
#define LCD1602_ROW1_ADDRESS_END (LCD1602_ROW1_ADDRESS_START+LCD1602_ROW_LENGHT)/*第1行结束地址*/


/*命令集指令*/
#define LCD1602_CLEAN_ALL_DISPALY			0x01				/*清屏指令*/
#define LCD1602_CURSOR_RETURN_TO_ORIGIN		0x02				/*光标归位指令*/

/*错误返回值*/
#define LCD1602_ROW_OR_COLUMN_OVERFLOW 		-1



/*****************外部接口函数******************/
//写命令
extern void Lcd1602WriteCommand(UB8 commandCode);

//写数据
extern void Lcd1602WriteData(UB8 dataCode);

//清屏
extern void Lcd1602CleanAll(void) ;

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

//LCD1602初始化
extern void Lcd1602Init(void) ;

//LCD1602地址写字节
extern SB8 Lcd1602AddressWriteByte(UB8 row,UB8 column,UB8 dataCode);

//LCD1602地址写字符串
extern SB8 Lcd1602AddressWriteString(UB8 row,UB8 column,UB8 *stringCode);

/**********************************************/
 

#endif	/*__LCD1602_H__*/

/*################lcd1602.h end ################*/

/*################ lcd1602.c start################*/ 

/***************************************************************************
模    块:LCD1602.c  

说    明:LCD1602驱动程序

版    本:Version2.0.0		2016/01/06 12:08(OK)

编译环境:Keil 8051 C complier V9.01

主控芯片:STC12C5A60S2  		@11.0592MHZ

作    者:杨瑞

联系方式:【QQ】279729201

		 【Email】[email protected]            
		          [email protected]
		 

修改记录:
=================
	2017/01/6 12:08
	记录:
		1.增加中文注释。
		2.修改函数名称模式,首写字母改为大写,例如lcd1602ReadStatus修改为Lcd1602ReadStatus。
		3.修改延时函数,将Delay1msForLcd1602函数修改为Delay80usForLcd1602函数。注意,这两个函数都是
		  由STC-ISP生成,Delay80usForLcd1602函数由STC-ISP V6.85Q的“软件延时计算器”针对STC-Y3指令集
		  @11.0592MHZ自动生成。经过测试,延时59us可能会出现只书写部分内容的情况,延时60us正好可以。
		  为了安全,也可以将此延时修改的更长。
=================

=================
	2014/04/31 20:09
	记录:
		1.解决大工程中,因未安装LCD1602而导致的工程卡死在函数
		lcd1602CheckBusy()的问题,将
		do{
				;
		}while( (lcd1602ReadStatus()) & 0x80));
		修改为
		do{
			i++;
		}while( ((lcd1602ReadStatus()) & 0x80)  && (i<10));
		因为在未安装LCD1602时,通过"读状态"函数lcd1602ReadStatus()读回来的永远是0xff,
		如果采用第一种算法,会导致程序"卡死"。

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

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

=================
	2014/02/24 15:00
	记录:
		1.增加函数delay1msForLcd1602()
		  STC12C5A60S2单片机操作速度快比传统8051快,某些操作延时必须足够。
=================


***************************************************************************/
#include <intrins.h>
#include <string.h>
#include "lcd1602.h"

/*外部接口函数在lcd1602.h中声明*/

/*****************内部函数******************/
static void Delay80usForLcd1602(void) ;
static UB8 Lcd1602ReadStatus(void) ;
static void Lcd1602CheckBusy(void) ;

/**********************************************/


/******************************************************************
 - 函数名称:Delay80usForLcd1602
 - 功能描述:延时函数
 - 隶属模块:LCD1602模块
 - 函数属性:内部函数
 - 参数说明:无
 - 返回说明:无
 - 注:此函数由STC-ISP V6.85Q的“软件延时计算器”针对STC-Y3指令集 @11.0592MHZ自动生成,若
      指令集或晶振不同,需稍作修改。
 ******************************************************************/
static void Delay80usForLcd1602(void)
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 1;
	j = 216;
	do
	{
		while (--j);
	} while (--i);
}

/******************************************************************
 - 函数名称:Lcd1602ReadStatus
 - 功能描述:读取LCD1602状态值
 - 隶属模块:LCD1602模块
 - 函数属性:内部函数
 - 参数说明:无
 - 返回说明:LCD1602的状态值
 ******************************************************************/
static UB8 Lcd1602ReadStatus(void)
{
	UB8 statusCode ;

	lcd1602_en_bit = LCD1602_DISABLE ;			/*禁止操作LCD1602*/
	lcd1602_rs_bit = LCD1602_COMMAND_OPERATION ;/*命令模式*/
	lcd1602_rw_bit = LCD1602_READ_OPERATION ;	/*读操作*/

	LCD1602_DATA_PORT = 0xff ;
	Delay80usForLcd1602() ;
	lcd1602_en_bit = LCD1602_ENABLE ;			/*允许操作LCD1602*/
	Delay80usForLcd1602() ;
	statusCode = LCD1602_DATA_PORT ;			/*读取状态值*/
	lcd1602_en_bit = LCD1602_DISABLE ;			/*禁止操作LCD1602*/

	return statusCode ;
}

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

/******************************************************************
 - 函数名称:Lcd1602WriteCommand
 - 功能描述:LCD1602写命令
 - 隶属模块:LCD1602模块
 - 函数属性:外部函数,供用户调用
 - 参数说明:需要发送给LCD1602的指令值
 - 返回说明:无
 ******************************************************************/
void Lcd1602WriteCommand(UB8 commandCode)
{
	Lcd1602CheckBusy();
	
	lcd1602_en_bit = LCD1602_DISABLE ;			/*禁止操作LCD1602*/
	lcd1602_rs_bit = LCD1602_COMMAND_OPERATION ;/*命令模式*/
	lcd1602_rw_bit = LCD1602_WRITE_OPERATION ;	/*写操作*/

	LCD1602_DATA_PORT = commandCode ;			/*发送指令值*/
	Delay80usForLcd1602();
	lcd1602_en_bit = LCD1602_ENABLE ;			/*允许操作LCD1602*/
	Delay80usForLcd1602();

	lcd1602_en_bit = LCD1602_DISABLE ;			/*禁止操作LCD1602*/
}

/******************************************************************
 - 函数名称:Lcd1602WriteData
 - 功能描述:LCD1602写数据
 - 隶属模块:LCD1602模块
 - 函数属性:外部函数,供用户调用
 - 参数说明:需要发送给LCD1602的数据
 - 返回说明:无
 ******************************************************************/
void Lcd1602WriteData(UB8 dataCode)
{	
	Lcd1602CheckBusy() ;
	
	lcd1602_en_bit = LCD1602_DISABLE ;			/*禁止操作LCD1602*/
	lcd1602_rs_bit = LCD1602_DATA_OPERATION ;	/*数据模式*/
	lcd1602_rw_bit = LCD1602_WRITE_OPERATION ;	/*写操作*/

	LCD1602_DATA_PORT = dataCode;				/*发送数据*/
	Delay80usForLcd1602();
	lcd1602_en_bit = LCD1602_ENABLE ;			/*允许操作LCD1602*/
	Delay80usForLcd1602();

	lcd1602_en_bit = LCD1602_DISABLE ;	 		/*禁止操作LCD1602*/  
}

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

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

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

	/*可忽略,在Lcd1602CleanAll()中隐含了该功能*/
	//Lcd1602CursorHoming(); 
	
	lcd1602_en_bit = LCD1602_DISABLE ;
}

/******************************************************************
 - 函数名称:Lcd1602AddressWriteByte
 - 功能描述:在LCD1602的row行column列写入数据dataCode
 - 隶属模块:LCD1602模块
 - 函数属性:外部函数,供用户调用
 - 参数说明:row-->行地址,有效值为LCD1602_ROW0或LCD1602_ROW1
			 column-->列地址,有效值为0~39之间的整数
			 dataCode-->需要写入的数据。
 - 返回说明:0(成功)或者-1(失败)
 - 注:行地址和列地址都是从0开始的。
       
	   想在LCD1602的第0行第2列显示阿里伯数字5,调用方式为
	   Lcd1602AddressWriteByte(LCD1602_ROW0,2,‘5’);
 
	   在DEBUG模式下,会对入参进行有效性判断,协助分析。调试后期可通过
       屏蔽common.h中的"#define DEBUG  1"减小目标文件的大小。   
 ******************************************************************/
SB8 Lcd1602AddressWriteByte(UB8 row,UB8 column,UB8 dataCode)
{
	#ifdef   DEBUG
		if(column< LCD1602_MIN_COLUMN|| column > LCD1602_MAX_COLUMN|| \
		   ( (row != LCD1602_ROW0) &&(row != LCD1602_ROW1)))
		{
			return LCD1602_ROW_OR_COLUMN_OVERFLOW ;
		}
	#endif /*DEBUG*/
	
	if(row == LCD1602_ROW0)
	{
		Lcd1602WriteCommand(LCD1602_ROW0_ADDRESS_START+column) ;
	}
	else if(row == LCD1602_ROW1)
	{
		Lcd1602WriteCommand(LCD1602_ROW1_ADDRESS_START+column) ;
		
	}
	
	Lcd1602WriteData(dataCode);

	return 0;
}

/******************************************************************
 - 函数名称:Lcd1602AddressWriteString
 - 功能描述:从LCD1602的row行column列开始写入字符串stringCode
 - 隶属模块:LCD1602模块
 - 函数属性:外部函数,供用户调用
 - 参数说明:row-->行地址,有效值为LCD1602_ROW0或LCD1602_ROW1
			 column-->列地址,有效值为0~39之间的整数
			 stringCode-->字符串
 - 返回说明:0(成功)或者-1(失败)
 - 注:行地址和列地址都是从0开始的。
 
 	   想在LCD1602的第0行第2列显示"test",调用方式为
	   Lcd1602AddressWriteString(LCD1602_ROW0,2,"test");
	   
	   这里使用的是strlen,而不是sizeof。
 
	   在DEBUG模式下,会对入参进行有效性判断,协助分析。调试后期可通过
       屏蔽common.h中的"#define DEBUG  1"减小目标文件的大小。
 ******************************************************************/
SB8 Lcd1602AddressWriteString(UB8 row,UB8 column,UB8 *stringCode)
{
	UB8 length = strlen(stringCode) ; 
	
	#ifdef DEBUG
		if(column< LCD1602_MIN_COLUMN|| (column+strlen(stringCode)-1) > LCD1602_MAX_COLUMN|| \
		   ( (row != LCD1602_ROW0) &&(row != LCD1602_ROW1)))
		{
			return LCD1602_ROW_OR_COLUMN_OVERFLOW ;
		}
	#endif	/*DEBUG*/

	if(row == LCD1602_ROW0)
	{
		Lcd1602WriteCommand(LCD1602_ROW0_ADDRESS_START+column) ;
	}
	else if(row == LCD1602_ROW1)
	{
		Lcd1602WriteCommand(LCD1602_ROW1_ADDRESS_START+column) ;
		
	}
	while(length--)
	{
		Lcd1602WriteData(*stringCode);
		stringCode++;
	}

	return 0;
}


/*################lcd1602.c end################*/

 

 

补充:common.h 

#ifndef __COMMON_H__
#define __COMMON_H__


#include <reg51.h>

typedef unsigned char UB8 ;
typedef unsigned short int UW16 ;
typedef unsigned long UL32 ;

typedef char SB8;
typedef short int SW16 ;
typedef long SL32 ;

#define DEBUG  1   /*测试模式,用于前期调试,后期可以屏蔽以此减少目标文件大小*/


#endif	/*__COMMON_H__*/




希望大家给予指正!!!

猜你喜欢

转载自blog.csdn.net/yagnruinihao/article/details/18559309