proteus仿真51单片机实时时钟

实现功能:

1、时间和日期的加减调节

2、秒表开始、停止、继续、复位计时

3、闹钟设置

4、整点闹铃

仿真原理图

实现代码

#include <REGX51.H>
//命名LCD引脚
#define RS  P3_5         //1602液晶的RS脚接在P3.5口上
#define RW  P3_6         //1602液晶的RW脚接在P3.6口上
#define E   P3_7         //1602液晶的E脚接在P3.7口上
//按键变量定义
#define key0  P1_0         //模式键,点击可以转化不同的模式
#define key1  P1_1         //开始键,加减时间用的
#define key2  P1_2         //用于转换下一个修改参数
enum key{KEY_no,KEY_mode,KEY_start,KEY_rest};//无按键操作,模式键按下,开始键按下,切换键按下
unsigned key_flag = 0;
//模式变量定义
enum mode{time,cout,alarm,set_time};//时间显示模式,计时模式,设置闹钟模式,调整时间模式
enum dis{start_count,stop_count,dis_data,dis_alarm};//开始计时,停止计时,显示日期
//日期时间变量
bit Runnian_flag = 0;
unsigned int year = 2024;//年计数
unsigned char month = 11;//月计数
unsigned char day = 18;//日计数
unsigned char second = 0;//秒计数
unsigned char minute = 0;//分计数
unsigned char hour = 0;//小时计数
unsigned char count = 0;//计数变量

//延时函数定义
void delay1ms(unsigned int n)   //误差 0us ,延时n毫秒
{
    unsigned int a,b,c;
		for(c=n;c>0;c--)
				for(b=199;b>0;b--)
						for(a=1;a>0;a--);
}
/LCD相关函数///
//---------------------------------------
//名称:等待1602之前的写操作已经完成
//---------------------------------------
void lcd_wait(void)
{ 
     RS=0;                //选择数据状态寄存器
     RW=1;                //选择读入状态
     P0=0xff;             //P0口输出高电平,准备输入
     while (1) {
         E=1;                 //E高电平使能1602读
         if(!P0_7) break;     //写操作已经完成
         E=0;                 //读完以后,恢复E的电平
     }
     E=0;                 //读完以后,恢复E的电平
}

//---------------------------------------
//名称:1602写命令函数
//---------------------------------------
void lcd_cmd(unsigned char cmd)
{ 
     lcd_wait();          //等待1602空闲
     RS=0;                //选择指令寄存器
     RW=0;                //选择写状态
     P0=cmd;              //将命令字通过P0口送至DB
     E=1;                 //E高电平将命令字写入1602
     E=0;                 //写完以后,恢复E的电平
}

//---------------------------------------
//名称:1602写数据函数
//---------------------------------------
void lcd_data(unsigned char buf)
{ 
     lcd_wait();          //等待1602空闲
     RS=1;                //选择数据寄存器
     RW=0;                //选择写状态
     P0=buf;              //将数据通过P0口送至DB
     E=1;                 //E高电平将命令字写入1602液晶
     E=0;                 //写完以后,恢复E的电平
} 

//---------------------------------------
//名称:1602液晶初始化函数
//---------------------------------------
void lcd_init(void)
{ 
     lcd_cmd(0x38);       //8位数据总线,两行显示模式,5*7点阵显示
     lcd_cmd(0x0C);       //显示功能开,无光标
     lcd_cmd(0x01);       //清屏
     lcd_cmd(0x06);       //写入新的数据后,光标右移,显示屏不移动
} 

void lcd_string(unsigned char x, unsigned char y, char *str) 
{	
		int i = 0;
    lcd_cmd(0x80 + x + y*0x40); // 设置起始位置(行和列)
    for (i = 0; str[i] != '\0'; i++) {
        lcd_data(str[i]); // 逐个字符写入数据
    }
}

const unsigned char code HEX[]="0123456789ABCDEF"; //16进制字符表,用于数字到显示字符转换
按键检测函数///
int key_in(void)
{
	if(P1 != 0xFF)
	{
		delay1ms(5);//延时5ms,进行按键消抖
		switch(P1)
		{
			case 0xFE : return KEY_mode; //切换模式键按下
			case 0xFD : return KEY_start;//开始键按下
			case 0xFB : return KEY_rest; //切换修改参数键按下
			default:return KEY_no;
		}
	}
	else
	{
		return KEY_no;
	}
}

主函数/
void main(void)
{	
	//unsigned char mode_flag;
	unsigned char mode_display = 0;//显示模式
	bit count_flag = 0;
	/按键IO口读模式
	P1 = 0xFF;
	/lcd初始化
	lcd_init();
	/时间定时器:定时器0的配置
	TMOD |= 0x01;//定时器工作方式1;
	//定时10ms
	TH0 = (65536 - 10000)/256;
	TL0 = (65536 - 10000)%256;
	TR0 = 1;//开始计时
	ET0 = 1;//允许定时器0产生中断
	EA = 1;//打开总中断
	/显示闪烁定时器,定时器1的配置
	
	
	while(1)
	{	
		//设置光标位置为第1行,1列,显示年		
		lcd_cmd(0x80);             
      	lcd_data(HEX[year/1000]);
		lcd_data(HEX[(year/100)%10]);
		lcd_data(HEX[(year/10)%10]);
		lcd_data(HEX[year%10]);
		//设置光标位置为第1行,6列,显示月		
		lcd_cmd(0x85);             
		lcd_data(HEX[month/10]);
		lcd_data(HEX[month%10]);
		//设置光标位置为第1行,6列,显示月		
		lcd_cmd(0x88);             
		lcd_data(HEX[day/10]);
		lcd_data(HEX[day%10]);
		
		//设置光标位置为第2行,1列,显示小时		
		lcd_cmd(0xC0);             
		lcd_data(HEX[hour/10]);
		lcd_data(HEX[hour%10]);
		lcd_data(':');		     
		lcd_data(HEX[minute/10]);
		lcd_data(HEX[minute%10]);
		lcd_data(':');		     
		lcd_data(HEX[second/10]);
		lcd_data(HEX[second%10]);
	}
}

//定时器0中断服务函数
void T0_ISR(void) interrupt 1
{
//重装定时器0的初始值
	TH0 = (65536 - 10000)/256;
	TL0 = (65536 - 10000)%256;
//对计数变量进行赋值
	if(count==99)
	{
		count = 0;
		if(second == 59)
		{
			second = 0;
			if(minute == 59)
			{
				minute = 0;
				if(hour == 23)
				{
					hour = 0;
					if(Runnian_flag)
					{
						if((day == 28)&&(month==2))//闰年闰月
						{
							day = 1;
							month++;
						}	
					}
					else
					{
						if((day == 29)&&(month==2))
						{
							day = 1;
							month++;
						}
					}
					if((day == 30)&&((month==2)|(month==4)|(month==6)|(month==9)|(month==11)))
					{
						day = 1;
						month++;
					}
					else if(day == 31)
					{
						day = 1;
						if(month == 12)
						{
							month = 1;
							year++;
							Runnian_flag = ((year%4==0) && (year%100!=0)) || (year%4000);//计数是否是闰年
						}
						else 
						{
							month++;
						}
					}
				}
				else
				{
					hour++;
				}
			}
			else
			{
				minute++;
			}
		}
		else
		{
			second++;
		}
	}
	else
	{
		count = 0;
	}
}

	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值