这里将我写的STC12C5A60S2控制LCD1602的程序共享一下,如有不足,敬请指出!
代码结构图:
程序下载链接:https://download.csdn.net/download/yagnruinihao/16676666点击下载
Proteus仿真图下载链接:https://download.csdn.net/download/yagnruinihao/16676677点击下载
测试程序:LCD1602测试.c
#include <string.h>
#include "common.h"
#include "LCD1602.h"
void main(void)
{
unsigned char i ;
unsigned char author[] = "Author:YangRui" ;
LCD1602_Init();
for(i=0 ; i<strlen(author) ; i++)
{
LCD1602_AddressWriteByte(LCD1602_ROW0,i,author[i]);
}
LCD1602_AddressWriteString(LCD1602_ROW1,0,"QQ:279729201") ;
while(1);
}
/*################LCD1602.h ################*/
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include "common.h"
//硬件接口定义,与硬件电路相对应
sbit LCD1602_RS_Bit = P2^6;//LCD1602的RS端口,高电平表示数据、低电平表示命令
sbit LCD1602_RW_Bit = P2^5;//LCD1602的RW端口,高电平表示读操作、低电平表示写操作
sbit LCD1602_EN_Bit = P2^7;//LCD1602的EN端口,高电平表示读状态或读数据、高脉冲表示写指令或写数据
#define LCD1602_DATA_PORT P0//LCD1602的数据口D0~D7,其中Px^0端口接DB0,Px^7端口接DB7,其他接口以此类推
/* RS与RW的设置:
RS Rw
0 0 ---->写命令
0 1 ---->读状态
1 0 ---->写数据
1 1 ---->读数据
*/
//LCD1602的RS端口选择
#define LCD1602_DATA_OPERATION 1//数据模式
#define LCD1602_COMMAND_OPERATION 0//命令模式
//LCD1602的RW端口选择
#define LCD1602_READ_OPERATION 1//读操作
#define LCD1602_WRITE_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_DISPLAY_DISABLE (0X04 & (~(0x01<<2)))//禁止液晶显示
#define LCD1602_CURSOR_DISPLAY_ENABLE 0X02 //允许光标显示
#define LCD1602_CURSOR_DISPLAY_DISABLE (0X02 & (~(0x01<<1)))//禁止光标显示
#define LCD1602_CURSOR_BLINK_ENABLE 0X01 //允许光标闪烁
#define LCD1602_CURSOR_BLINK_DISABLE (0X01 & (~(0x01<<0)))//禁止光标闪烁
//默认设置:lcd显示,光标不显示,光标不闪烁
#define LCD1602_DEFAULT_DISPLAY_AND_CURSOR_MODE 0x08 | \
LCD1602_DISPLAY_ENABLE | \
LCD1602_CURSOR_DISPLAY_DISABLE | \
LCD1602_CURSOR_BLINK_DISABLE
/*
====================================================
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_POINT_AND_CURSOR_MINUS (0X02 & (~(0X01<<1)))//指针减一、光标减一
#define LCD1602_SCREEN_MOVE_ENABLE 0x01 //允许屏幕移动
#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//光标归位指令
/*****************外部接口函数******************/
//LCD1602初始化函数
extern void LCD1602_Init(void) ;
//清屏操作
extern void LCD1602_CleanAll(void) ;
//光标归位操作
extern void LCD1602_CursorHoming(void);
//LCD1602地址写字节操作
extern char LCD1602_AddressWriteByte(unsigned char Row,unsigned char Column,unsigned char DataValue);
//LCD1602地址写字符串操作
extern char LCD1602_AddressWriteString(unsigned char Row,unsigned char Column,unsigned char *String);
//写命令操作
extern void LCD1602_WriteCommand(unsigned char CommandValue);
//写数据操作
extern void LCD1602_WriteData(unsigned char DataValue);
/**********************************************/
#endif /*__LCD1602_H__*/
/*################ LCD1602.c################*/
/***************************************************************************
模 块:LCD1602.c
说 明:LCD1602驱动程序
版 本: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
修改记录:
=================
2021/01/01 06:06
记录:
1.规范部分函数。
2.取消Delay80usForLcd1602(),调用函数Delay_SomeNop(10)代替消Delay80usForLcd1602()函数。
3.增加ST89C52RC @11.0592MHZ 和AT89C51 @11.0592MHZ @Proteus8.9仿真测试,经测试此代码
均可适用。
=================
=================
2017/01/6 12:08
记录:
1.增加中文注释。
2.修改函数名称模式,由"模块名称"(大写)+"_"+功能函数名称构成,例如lcd1602ReadStatus修改为LCD1602_ReadStatus.
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 <string.h>
#include "lcd1602.h"
/*外部接口函数在lcd1602.h中声明*/
/*****************内部函数******************/
unsigned char LCD1602_ReadStatus(void) ;
void LCD1602_CheckBusy(void) ;
/**********************************************/
/******************************************************************
- 函数名称:LCD1602_ReadStatus
- 功能描述:读取LCD1602状态值
- 函数属性:内部函数
- 参数说明:无
- 返回说明:LCD1602的状态值
******************************************************************/
unsigned char LCD1602_ReadStatus(void)
{
unsigned char StatusCode ;
LCD1602_EN_Bit = LCD1602_DISABLE ; //禁止操作LCD1602
LCD1602_RS_Bit = LCD1602_COMMAND_OPERATION ;//命令模式
LCD1602_RW_Bit = LCD1602_READ_OPERATION ; //读操作
LCD1602_DATA_PORT = 0xff ;
Delay_SomeNop(10); //注意:这里延时不能少,否则不会有效果
LCD1602_EN_Bit = LCD1602_ENABLE ; //允许操作LCD1602
Delay_SomeNop(10); //注意:这里延时不能少,否则不会有效果
StatusCode = LCD1602_DATA_PORT ; //读取状态值*/
LCD1602_EN_Bit = LCD1602_DISABLE ; //禁止操作LCD1602
return StatusCode ;
}
/******************************************************************
- 函数名称:LCD1602_CheckBusy
- 功能描述:判断LCD1602是否忙碌:若忙碌则等待;若空闲则执行任务
- 函数属性:内部函数
- 参数说明:无
- 返回说明:无
- 注 :当LCD1602_DATA_PORT[7]等于1,表示LCD1602忙碌,则需要等待一会儿
当LCD1602_DATA_PORT[7]等于0,表示LCD1602空闲,则可以继续执行后面的任务
- 补 充:这里的“10”是经过测试的,测试中,利用串口打印i的值为1,这里写10已经足够大了。
******************************************************************/
void LCD1602_CheckBusy(void)
{
unsigned char i=0;
do{
i++;
}while( ((LCD1602_ReadStatus()) & 0x80) && (i<10));
}
/******************************************************************
- 函数名称:LCD1602_WriteCommand
- 功能描述:LCD1602写命令
- 函数属性:外部函数,供用户调用
- 参数说明:CommandValue,需要发送给LCD1602的指令值
- 返回说明:无
******************************************************************/
void LCD1602_WriteCommand(unsigned char CommandValue)
{
LCD1602_CheckBusy();
LCD1602_EN_Bit = LCD1602_DISABLE ; /*禁止操作LCD1602*/
LCD1602_RS_Bit = LCD1602_COMMAND_OPERATION ;/*命令模式*/
LCD1602_RW_Bit = LCD1602_WRITE_OPERATION ; /*写操作*/
LCD1602_DATA_PORT = CommandValue ; /*发送指令值*/
//Delay_SomeNop(10);
LCD1602_EN_Bit = LCD1602_ENABLE ; /*允许操作LCD1602*/
//Delay_SomeNop(10);
LCD1602_EN_Bit = LCD1602_DISABLE ; /*禁止操作LCD1602*/
}
/******************************************************************
- 函数名称:LCD1602_WriteData
- 功能描述:LCD1602写数据
- 函数属性:外部函数,供用户调用
- 参数说明:DataValue,需要发送给LCD1602的数据
- 返回说明:无
******************************************************************/
void LCD1602_WriteData(unsigned char DataValue)
{
LCD1602_CheckBusy() ;
LCD1602_EN_Bit = LCD1602_DISABLE ; /*禁止操作LCD1602*/
LCD1602_RS_Bit = LCD1602_DATA_OPERATION ; /*数据模式*/
LCD1602_RW_Bit = LCD1602_WRITE_OPERATION ; /*写操作*/
LCD1602_DATA_PORT = DataValue; /*发送数据*/
//Delay_SomeNop(10);
LCD1602_EN_Bit = LCD1602_ENABLE ; /*允许操作LCD1602*/
//Delay_SomeNop(10);
LCD1602_EN_Bit = LCD1602_DISABLE ; /*禁止操作LCD1602*/
}
/******************************************************************
- 函数名称:LCD1602_CleanAll
- 功能描述:清除屏幕显示
- 函数属性:外部函数,供用户调用
- 参数说明:无
- 返回说明:无
- 注 :清除屏幕显示,光标归位(左上角),地址计数器AC设为0
******************************************************************/
void LCD1602_CleanAll(void)
{
LCD1602_WriteCommand(LCD1602_CLEAN_ALL_DISPALY);
}
/******************************************************************
- 函数名称:LCD1602_CursorHoming
- 功能描述:光标归位
- 函数属性:外部函数,供用户调用
- 参数说明:无
- 返回说明:无
- 注 :光标归为,当屏幕移动显示时,lcd1602显示所有数据后,
调用此函数,屏幕显示的所有东西都会归位。光标在第一
个位置(0x80)。
******************************************************************/
void LCD1602_CursorHoming(void)
{
LCD1602_WriteCommand(LCD1602_CURSOR_RETURN_TO_ORIGIN);
}
/******************************************************************
- 函数名称:LCD1602_Init
- 功能描述:LCD1602初始化
- 函数属性:外部函数,供用户调用
- 参数说明:无
- 返回说明:无
- 注 :设置(1)显示模式
(2)液晶显示允许或禁止、光标显示允许或禁止、光标闪烁允许或禁止
(3)地址指针加一或减一、光标指针加一或减一、屏幕左移或右移
可通过修改LCD1602.H中的LCD1602_DEFAULT_DISPALY_MODE、LCD1602_DEFAULT_DISPLAY_AND_CURSOR_MODE、
LCD1602_DEFAULT_POINT_AND_POINT_ADDRESS_MODE达到不同的显示效果。
******************************************************************/
void LCD1602_Init(void)
{
LCD1602_CleanAll();
LCD1602_WriteCommand(LCD1602_DEFAULT_DISPALY_MODE);
LCD1602_WriteCommand(LCD1602_DEFAULT_DISPLAY_AND_CURSOR_MODE);
LCD1602_WriteCommand(LCD1602_DEFAULT_POINT_AND_POINT_ADDRESS_MODE);
/*可忽略,在LCD1602_CleanAll()中隐含了该功能*/
LCD1602_CursorHoming();
}
/******************************************************************
- 函数名称:LCD1602_AddressWriteByte
- 功能描述:在LCD1602的Row行Column列写入数DataValue
- 函数属性:外部函数,供用户调用
- 参数说明:Row-->行地址,有效值为LCD1602_ROW0或LCD1602_ROW1
Column-->列地址,有效值为0~39之间的整数
DataValue-->需要写入的数据。
- 返回说明:0(成功)或者-1(失败)
- 注 :1.行地址和列地址都是从0开始的。
需要在LCD1602的第0行第2列显示阿里伯数字5,调用方式为
LCD1602_AddressWriteByte(LCD1602_ROW0,2,‘5’);
2.在DEBUG模式下,会对入参进行有效性判断,协助分析。调试后期可通过
屏蔽common.h中的"#define DEBUG 1"减小目标文件的大小。
******************************************************************/
char LCD1602_AddressWriteByte(unsigned char Row,unsigned char Column,unsigned char DataValue)
{
#ifdef DEBUG
if((Column< LCD1602_MIN_COLUMN)|| (Column > LCD1602_MAX_COLUMN)|| \
( (Row != LCD1602_ROW0) &&(Row != LCD1602_ROW1)))
return -1 ;
#endif
if(LCD1602_ROW0 == Row) //注意这里==的两边顺序,技巧!
LCD1602_WriteCommand(LCD1602_ROW0_ADDRESS_START+Column) ;
else if(LCD1602_ROW1 == Row)//注意这里==的两边顺序,技巧!
LCD1602_WriteCommand(LCD1602_ROW1_ADDRESS_START+Column) ;
LCD1602_WriteData(DataValue);
return 0;
}
/******************************************************************
- 函数名称:LCD1602_AddressWriteString
- 功能描述:从LCD1602的Row行Column列开始写入字符串String
- 函数属性:外部函数,供用户调用
- 参数说明:Row-->行地址,有效值为LCD1602_ROW0或LCD1602_ROW1
Column-->列地址,有效值为0~39之间的整数
String-->需要写入的字符串。
- 返回说明:0(成功)或者-1(失败)
- 注 :行地址和列地址都是从0开始的。
想在LCD1602的第0行第2列显示"test",调用方式为
LCD1602_AddressWriteString(LCD1602_ROW0,2,"test");
这里使用的是strlen,而不是sizeof。
在DEBUG模式下,会对入参进行有效性判断,协助分析。调试后期可通过
屏蔽common.h中的"#define DEBUG 1"减小目标文件的大小。
******************************************************************/
char LCD1602_AddressWriteString(unsigned char Row,unsigned char Column,unsigned char *String)
{
unsigned char length = strlen(String) ;
#ifdef DEBUG
if(Column< LCD1602_MIN_COLUMN|| (Column+strlen(String)-1) > LCD1602_MAX_COLUMN|| \
( (Row != LCD1602_ROW0) &&(Row != LCD1602_ROW1)))
return -1 ;
#endif
if(LCD1602_ROW0 == Row) //注意这里==的两边顺序,技巧!
LCD1602_WriteCommand(LCD1602_ROW0_ADDRESS_START+Column) ;
else if(LCD1602_ROW1 == Row)//注意这里==的两边顺序,技巧!
LCD1602_WriteCommand(LCD1602_ROW1_ADDRESS_START+Column) ;
while(length--)
LCD1602_WriteData(*String++);
return 0;
}
/*################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_();
}
}