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

这里将我写的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_();
	}
}

 

  • 12
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
好的,我理解了你的问题。首先,我们需要了解一些基本概念: 1. 1602LCD:1602LCD是一种常见的字符型液晶显示屏,能够显示16列2行字符。 2. 定时器中断:定时器中断是指在一定时间间隔内定时触发中断,可以用于定时任务的实现。 3. 按键:按键是一种常见的输入设备,可以用于控制程序的执行。 现在我们开始编写程序: 首先,我们需要定义一些常量和变量,如下所示: ```c #include <reg51.h> #define LCD1602_DATAPORT P0 //1602LCD数据口 #define LCD1602_CMDPORT P2 //1602LCD命令口 unsigned char code table[] = " 0123456789"; // 数码管显示表 unsigned long second = 0; // 秒数 unsigned char flag = 0; // 暂停标志位 ``` 其中,LCD1602_DATAPORT 和 LCD1602_CMDPORT 分别代表1602LCD的数据口和命令口。table 数组是用来将数字转换为字符。second 是计时器的秒数,flag 是暂停标志位。 然后,我们需要定义一些函数,如下所示: ```c void delay(unsigned int i); // 延时函数 void write_cmd(unsigned char cmd); // 写命令函数 void write_data(unsigned char dat); // 写数据函数 void init_lcd(void); // 初始化LCD函数 void display_time(unsigned long time); // 显示时间函数 void timer0_init(void); // 定时器初始化函数 void key_scan(void); // 按键扫描函数 void timer0_isr(void) interrupt 1; // 定时器中断处理函数 ``` 其中,delay 函数是一个简单的延时函数,write_cmd 和 write_data 函数用于向1602LCD发送命令和数据,init_lcd 函数用于初始化1602LCD,display_time 函数用于将秒数转换为时分秒并显示在1602LCD上,timer0_init 函数用于初始化定时器,key_scan 函数用于扫描按键,timer0_isr 函数是定时器中断处理函数,用于在每秒钟更新秒数。 下面,我们开始编写这些函数。首先是 delay 函数: ```c void delay(unsigned int i){ unsigned int j; while(i--){ j = 120; while(j--); } } ``` delay 函数使用了一个嵌套循环实现了延时功能。 然后是 write_cmd 和 write_data 函数: ```c void write_cmd(unsigned char cmd){ LCD1602_CMDPORT &= 0x0f; LCD1602_CMDPORT |= cmd & 0xf0; LCD1602_CMDPORT &= 0xfe; delay(5); LCD1602_CMDPORT |= 0x01; delay(5); LCD1602_CMDPORT &= 0xfe; delay(5); LCD1602_CMDPORT &= 0x0f; LCD1602_CMDPORT |= (cmd << 4) & 0xf0; LCD1602_CMDPORT &= 0xfe; delay(5); LCD1602_CMDPORT |= 0x01; delay(5); LCD1602_CMDPORT &= 0xfe; } void write_data(unsigned char dat){ LCD1602_CMDPORT &= 0x0f; LCD1602_CMDPORT |= dat & 0xf0; LCD1602_CMDPORT |= 0x04; delay(5); LCD1602_CMDPORT &= 0xfb; delay(5); LCD1602_CMDPORT &= 0x0f; LCD1602_CMDPORT |= (dat << 4) & 0xf0; LCD1602_CMDPORT |= 0x04; delay(5); LCD1602_CMDPORT &= 0xfb; } ``` write_cmd 和 write_data 函数分别用于向1602LCD发送命令和数据,具体实现可以参考1602LCD的数据手册。 接下来是 init_lcd 函数: ```c void init_lcd(void){ write_cmd(0x02); // 返回光标和显示起始地址为00H write_cmd(0x0c); // 1602LCD显示开,光标关闭 write_cmd(0x06); // 入口方式为增加,不移动屏幕 write_cmd(0x28); // 显示模式为2行显示,5*7点阵字符 write_cmd(0x01); // 显示清屏 } ``` init_lcd 函数用于初始化1602LCD,具体实现可以参考1602LCD的数据手册。 然后是 display_time 函数: ```c void display_time(unsigned long time){ unsigned char hour, minute, second; hour = time / 3600; time = time % 3600; minute = time / 60; second = time % 60; write_cmd(0x80); // 显示位置为第一行第一列 write_data(table[hour / 10]); // 显示小时的十位数 write_data(table[hour % 10]); // 显示小时的个位数 write_data(':'); // 显示冒号 write_data(table[minute / 10]); // 显示分钟的十位数 write_data(table[minute % 10]); // 显示分钟的个位数 write_data(':'); // 显示冒号 write_data(table[second / 10]); // 显示秒数的十位数 write_data(table[second % 10]); // 显示秒数的个位数 } ``` display_time 函数用于将秒数转换为时分秒并显示在1602LCD上。 然后是 timer0_init 函数: ```c void timer0_init(void){ TMOD = 0x01; // 定时器0工作在模式1,16位定时器模式 TH0 = 0xfc; // 定时器0初始值为65536-50000=15536 TL0 = 0x00; ET0 = 1; // 允许定时器0中断 TR0 = 1; // 启动定时器0 EA = 1; // 开启总中断 } ``` timer0_init 函数用于初始化定时器0,定时周期为50ms,用于计时。 然后是 key_scan 函数: ```c void key_scan(void){ if(!P3_1){ // 暂停/继续计时 while(!P3_1); flag = !flag; } if(!P3_0){ // 清零计时 while(!P3_0); second = 0; flag = 0; display_time(second); } } ``` key_scan 函数用于扫描按键,如果按下了暂停/继续按键,则将 flag 标志位取反;如果按下了清零按键,则将 second 变量清零并显示在1602LCD上。 最后是 timer0_isr 函数: ```c void timer0_isr(void) interrupt 1{ TH0 = 0xfc; // 定时器0初始值为65536-50000=15536 TL0 = 0x00; if(flag){ // 如果暂停标志位为真,则不更新计时器数值 return; } second++; display_time(second); } ``` timer0_isr 函数是定时器中断处理函数,用于在每秒钟更新秒数,并将更新后的秒数显示在1602LCD上。 最后,我们在 main 函数中调用上述函数即可: ```c void main(void){ init_lcd(); timer0_init(); display_time(second); while(1){ key_scan(); } } ``` 至此,一个简单的秒表程序就完成了。当按下暂停/继续按键时,计时器会暂停或继续计时;当按下清零按键时,计时器会清零并重新开始计时。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

刺客阿瑞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值