51单片机万年历设计

目录

功能设计

实现原理

使用说明

        1.按键设置

        2.串口数据设定

        3.细节设置

代码


功能设计

  1. 液晶屏显示当前日期,时间,可以通过按键修改日期时间。
  2. 可以设置闹钟时间,到点蜂鸣器鸣叫,直至手动关闭。
  3. 具有计时器功能。计时结束蜂鸣器报警指定时间提醒,无需手动取消。
  4. 每次有按键按下时,蜂鸣器以短“滴”声报警。
  5. 可以通过电脑串口通信调整时间,闹钟,计时器有关参数。

实现原理

  1. 单片机型号:STC89C51RC2;开发板:普中A2;开发软件:Keil4(因为内置无本芯片头文件,所以部分地址需要重新定义)
  2. 显示模块:采用LCD1602显示。
  3. 时间显示功能:采用DS1302实现时钟显示功能。
  4. 蜂鸣器模块:由于开发板自带无源蜂鸣器引脚与LCD1602引脚冲突,采用外接有源蜂鸣器完成对应功能。
  5. 计时器功能:采用单片机内部定时器实现计时。
  6. 串口通信:采用单片机自带串口配合定时器中断实现通信。

使用说明

        1.按键设置

按键号对应功能MenuFunction
K1

按下循环切换对应功能菜单界面

0显示时间
1串口调整模式
2时间调整
3闹钟调整
4计时器模式
备注
K2数值加具有越界判断功能,仅在选中时有效
K3数值减具有越界判断功能,仅在选中时有效
K4控制调整内容

仅在调整页面有效,控制内容时闪烁显示

        2.串口数据设定

用户须发送两次数据:第一次发送要控制的内容编码(对应值见下表),第二次发送调整的数值(16进制)。接收成功会返回“FF”。

注意:串口调整仅在调整页面有效,需手动切换至调整界面。

编码(16进制)模块对应数据
1时钟
2
3
4
5
6
7星期
8闹钟
9
a计时器
b
c

        3.细节设置

  1. 闹钟响时按下任意按键即可关闭,且不改变闹钟的运行状态,可实现每天提醒。
  2. 计时器运行状态中按下任意按键可暂停倒计时,再次按下任意按键可以恢复。运行状态中无法切换功能界面。

代码

主函数:main.c

#include <at89c51RC2.h>
#include "LCD1602.h"
#include "Hardware.h"
#include "DS1302.h"


sbit beep=P1^7;

char keynum,menu,mode1,mode2,mode3,flash;
int timer_flag;         //1=打开,0=关闭
int timer_time[6]={0,0,0,0,1,0};     //计时器时间设定
int alarm_flag;         //1=打开,0=关闭
int alarm_time[6]={0,0,0,8,0,0};     //闹钟时间设定
int run1;    //计时器运行标志位(0为暂停运行,1为运行)
int buzzer,temp;    //闹钟声响标志位
int uart[3]={0,0,0};


/*******************************************************************************
* 函 数 名         : Beep_Delay
* 函数功能         : 延时函数@12.000MHz 1ms
* 输    入         : y
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void Beep_Delay(int y)		
{
	unsigned char n, m;

	n = 2;
	m = 239;
	while(y--)
	{
		while (--n);
	} while (--m);
}

/*******************************************************************************
* 函 数 名         : Timer_Init
* 函数功能         : 计时器界面初始化
* 输    入         : void
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void Timer_Init()
{
	LCD_Clean();
	LCD_ShowString(1,1,"Set Timer:");
	LCD_ShowNum(2,1,timer_time[3],2);
	LCD_ShowString(2,3,":");
	LCD_ShowNum(2,4,timer_time[4],2);
	LCD_ShowString(2,6,":");
	LCD_ShowNum(2,7,timer_time[5],2);
	if(timer_flag == 0)
	{
		LCD_ShowString(2,13,"OFF");
	}else{
		LCD_ShowString(2,13,"ON ");
	}
}
/*******************************************************************************
* 函 数 名         : Timer_Set
* 函数功能         : 计时器设置
* 输    入         : void
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void Timer_Set(void)
{
	if(run1==0&&keynum == 4)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
		mode3++;
		if(mode3>3)
		{
			mode3=0;
			timer_flag=!timer_flag;
			if(timer_flag == 0)
			{
				LCD_ShowString(2,13,"OFF ");
			}else
			{
				LCD_ShowString(2,13,"ON  ");
			}
		}
	}
	if(run1==0&&keynum == 2)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
		timer_time[mode3+2]++;
		if(timer_time[3]>23){timer_time[3]=0;}
		if(timer_time[4]>59){timer_time[4]=0;}
		if(timer_time[5]>59){timer_time[5]=0;}
	}
	if(run1==0&&keynum == 3)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
		timer_time[mode3+2]--;
		if(timer_time[3]<0){timer_time[3]=23;}		
		if(timer_time[4]<0){timer_time[4]=59;}
		if(timer_time[5]<0){timer_time[5]=59;}
	}	
	//更新显示
	if(run1==0 && mode3==1 && flash==1){LCD_ShowString(2,1,"  ");}
	else {LCD_ShowNum(2,1,timer_time[3],2);}
	if(run1==0 && mode3==2 && flash==1){LCD_ShowString(2,4,"  ");}
	else {LCD_ShowNum(2,4,timer_time[4],2);}
	if(run1==0 && mode3==3 && flash==1){LCD_ShowString(2,7,"  ");}
	else {LCD_ShowNum(2,7,timer_time[5],2);}
}

/*******************************************************************************
* 函 数 名         : Alarm_Init
* 函数功能         : 闹钟界面初始化
* 输    入         : void
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void Alarm_Init(void)
{
	LCD_Clean();
	LCD_ShowString(1,1,"Set Alarm: ");
	LCD_ShowNum(2,1,alarm_time[3],2);
	LCD_ShowString(2,3,":");
	LCD_ShowNum(2,4,alarm_time[4],2);
	if(alarm_flag == 0)
	{
		LCD_ShowString(2,13,"OFF");
	}else{
		LCD_ShowString(2,13,"ON ");
	}
}
/*******************************************************************************
* 函 数 名         : Alarm_Set
* 函数功能         : 闹钟设置
* 输    入         : none
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void Alarm_Set(void)
{
	if(buzzer==0&&keynum == 4)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
		mode2++;
		if(mode2==3)
		{
			mode2=0;
			alarm_flag=!alarm_flag;
			if(alarm_flag == 0)
			{
				LCD_ShowString(2,13,"OFF");
			}else
			{
				LCD_ShowString(2,13,"ON ");
			}
		}		
	}
	if(buzzer==0&&keynum == 2)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
		alarm_time[mode2+2]++;
		if(alarm_time[3]<0){alarm_time[3]=23;}
		if(alarm_time[3]>23){alarm_time[3]=0;}
	}
	if(buzzer==0&&keynum == 3)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
		alarm_time[mode2+2]--;
		if(alarm_time[4]<0){alarm_time[4]=59;}
		if(alarm_time[4]>59){alarm_time[4]=0;}
	}
	//更新显示
	if(buzzer==0 && mode2==1 && flash==1){LCD_ShowString(2,1,"  ");}
	else {LCD_ShowNum(2,1,alarm_time[3],2);}
	if(buzzer==0 && mode2==2 && flash==1){LCD_ShowString(2,4,"  ");}
	else {LCD_ShowNum(2,4,alarm_time[4],2);}
}
/*******************************************************************************
* 函 数 名         : Clock_Show
* 函数功能         : 时钟显示
* 输    入         : none
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void Clock_Show()
{
		DS1302_Return();
		LCD_ShowNum(1,1,20,2);
		LCD_ShowNum(1,3,time[0],2);
		LCD_ShowString(1,5,"-");
		LCD_ShowNum(1,6,time[1],2);
		LCD_ShowString(1,8,"-");
		LCD_ShowNum(1,9,time[2],2);
		switch(time[6])
		{
			case 1:LCD_ShowString(1,13,"MON");break;	
			case 2:LCD_ShowString(1,13,"TUE");break;
			case 3:LCD_ShowString(1,13,"WED");break;
			case 4:LCD_ShowString(1,13,"THU");break;
			case 5:LCD_ShowString(1,13,"FRI");break;
			case 6:LCD_ShowString(1,13,"SAT");break;
			case 7:LCD_ShowString(1,13,"SUN");break;	
		}
		
		LCD_ShowNum(2,1,time[3],2);
		LCD_ShowString(2,3,":");		
		LCD_ShowNum(2,4,time[4],2);
		LCD_ShowString(2,6,":");
		LCD_ShowNum(2,7,time[5],2);
		if(alarm_flag==1){LCD_ShowString(2,13," # ");	}    //闹钟开启主页面显示#
		else{LCD_ShowString(2,13,"   ");	}
}

/*******************************************************************************
* 函 数 名         : Clock_Set
* 函数功能         : 按键设置时钟时间
* 输    入         : none
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void Clock_Set()
{

	if(run1==0&&buzzer==0&&keynum == 4)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
		mode1++;
		if(mode1>7)
		{
			mode1=0;
			DS1302_Set();   //发送调节后的时间
		}
	}
	if(run1==0&&buzzer==0&&keynum == 2)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块		
		
		time[mode1-1]++;
		
		if(time[0]>99){time[0]=0;}        //年越界判断
		if(time[1]>12){time[1]=1;}				//月越界判断
		if( time[1]==1 || time[1]==3 || time[1]==5 || time[1]==7 || 
			time[1]==8 || time[1]==10 || time[1]==12)//日越界判断
		{
			if(time[2]>31){time[2]=1;}//大月
		}
		else if(time[1]==4 || time[1]==6 || time[1]==9 || time[1]==11)
		{
			if(time[2]>30){time[2]=1;}//小月
		}
		else if(time[1]==2)
		{
			if(time[0]%4==0)
			{
				if(time[2]>29){time[2]=1;}//闰年2月
			}
			else
			{
				if(time[2]>28){time[2]=1;}//平年2月
			}
		}
		if(time[3]>23){time[3]=0;}			//时越界判断
		if(time[4]>59){time[4]=0;}			//分越界判断
		if(time[5]>59){time[5]=0;}			//秒越界判断
		if(time[6]>8){time[6]=1;}				//星期越界判断		
	}
	if(run1==0&&buzzer==0&&keynum == 3)
	{
		beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
		
		time[mode1-1]--;
		
		if(time[0]<0){time[0]=99;}        //年越界判断
		if(time[1]<1){time[1]=12;}				//月越界判断
		if( time[1]==1 || time[1]==3 || time[1]==5 || time[1]==7 || 
			time[1]==8 || time[1]==10 || time[1]==12)//日越界判断
		{
			if(time[2]<1){time[2]=31;}//大月
			if(time[2]>31){time[2]=1;}//大月
		}
		else if(time[1]==4 || time[1]==6 || time[1]==9 || time[1]==11)
		{
			if(time[2]<1){time[2]=30;}//小月
			if(time[2]>30){time[2]=1;}//小月
		}
		else if(time[1]==2)
		{
			if(time[0]%4==0)
			{
				if(time[2]<1){time[2]=29;}//闰年2月
				if(time[2]>29){time[2]=1;}//闰年2月
			}
			else
			{
				if(time[2]<1){time[2]=28;}//平年2月
				if(time[2]>28){time[2]=1;}//平年2月
			}
		}
		if(time[3]<0){time[3]=23;}			//时越界判断
		if(time[4]<0){time[4]=59;}			//分越界判断
		if(time[5]<0){time[5]=59;}			//秒越界判断
		if(time[6]<1){time[6]=7;}				//星期越界判断		
	}
	
	//更新显示,根据mode和flash判断可完成闪烁功能
	if(mode1==1 && flash==1){LCD_ShowString(1,3,"  ");}
	else {LCD_ShowNum(1,3,time[0],2);}
	if(mode1==2 && flash==1){LCD_ShowString(1,6,"  ");}
	else {LCD_ShowNum(1,6,time[1],2);}
	if(mode1==3 && flash==1){LCD_ShowString(1,9,"  ");}
	else {LCD_ShowNum(1,9,time[2],2);}
	if(mode1==7 && flash==1){LCD_ShowString(1,13,"   ");}
	else 
	{		
		switch(time[6])
		{
			case 1:LCD_ShowString(1,13,"MON");break;	
			case 2:LCD_ShowString(1,13,"TUE");break;
			case 3:LCD_ShowString(1,13,"WED");break;
			case 4:LCD_ShowString(1,13,"THU");break;
			case 5:LCD_ShowString(1,13,"FRI");break;
			case 6:LCD_ShowString(1,13,"SAT");break;
			case 7:LCD_ShowString(1,13,"SUN");break;	
		}
	}
	if(mode1==4 && flash==1){LCD_ShowString(2,1,"  ");}
	else {LCD_ShowNum(2,1,time[3],2);}
	if(mode1==5 && flash==1){LCD_ShowString(2,4,"  ");}
	else {LCD_ShowNum(2,4,time[4],2);}
	if(mode1==6 && flash==1){LCD_ShowString(2,7,"  ");}
	else {LCD_ShowNum(2,7,time[5],2);}
}

/*******************************************************************************
* 函 数 名         : Uart_Change
* 函数功能         : 电脑通过串口设置时钟时间
* 输    入         : none
* 输    出         : void
* 说    明         : 第一个发送的数据指定修改的内容(1~7对应为时钟修改,8~9对应为闹钟修改,10~12为计时器修改),
										 第二次发送的数据为要修改的数据
*******************************************************************************/
void Uart_Change()
{
	switch(uart[0])
	{
		case 1:time[0]=uart[1];break;   
		case 2:time[1]=uart[1];break;
		case 3:time[2]=uart[1];break;
		case 4:time[3]=uart[1];break;
		case 5:time[4]=uart[1];break;
		case 6:time[5]=uart[1];break;
		case 7:time[6]=uart[1];break;
		case 8:alarm_time[3]=uart[1];break;    
		case 9:alarm_time[4]=uart[1];break;
		case 10:timer_time[3]=uart[1];break;    
		case 11:timer_time[4]=uart[1];break; 
		case 12:timer_time[5]=uart[1];break;
		default: break;
	}
}

/*******************************************************************************
*主函数
*******************************************************************************/
void main()
{
	LCD_Init();        //LCD屏幕初始化
	Timer0_Init();		 //定时器初始化
	DS1302_Init();		 //DS1302初始化
	DS1302_Set();      //DS1302初始时间设定
	UART_Init();		   //串口初始化
	
	while(1)
	{
		keynum = Key();   //读取按键键码

		
		if(run1==0&&keynum == 1)
		{
			beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
			menu++;              //调整菜单
			if(menu>6)
			{
				menu=0;DS1302_Set();
			}
		}
		switch(menu)
		{
			case 0:
			Clock_Show();break;   //显示时间
			case 1:
			Uart_Change();break;  //串口调整模式
			case 2:
			Clock_Set();break;    //串口调整时间
			case 3:
			Alarm_Init();	break;	//显示闹钟调节页面
			case 4:
			Alarm_Set();break;	  //调节闹钟	 
			case 5:
			Timer_Init();break;   //显示计时器调节页面
			case 6:
			Timer_Set();break;		//调节计时器
			
		}
		
		if(run1==1)               //定时器中断程序
		{
			if(keynum==1||keynum==2||keynum==3||keynum==4)   //任意一个按键按下
			{
				beep=0;Beep_Delay(20);beep=1;   //蜂鸣器模块
				timer_flag=!timer_flag;      
//				run1=!run1;						 
				if(timer_flag==0&&beep==1&&timer_time[5]!=0)         
				{
					LCD_ShowString(2,13,"STOP");
				}else{LCD_ShowString(2,13,"ON  ");}		
			}
		}
		
		if(buzzer==1&&temp==0)              //闹钟响铃程序
		{
			beep=0;             //蜂鸣器响
			if(keynum==1||keynum==2||keynum==3||keynum==4)   //任意一个按键按下
			{
				beep=1;
				temp=1;
				buzzer=0;
			}
		}
	}
}

/*******************************************************************************
*定时器0中断函数
*******************************************************************************/
void Timer0_Routine()  interrupt 1
{
	static unsigned int cnt;
	TL0 = 0x18;
	TH0 = 0xFC;
	cnt++;
	if(cnt>=1000)    //1s
	{
		cnt=0;
		
		/*计时器*/
		if(timer_flag==1)
		{
			run1=1;
			if(timer_time[5]>0) timer_time[5]--;
			else
			{
				if(timer_time[4]>0){timer_time[4]--;timer_time[5]=59;}
				else
				{
					if(timer_time[3]>0){timer_time[3]--;timer_time[4]=59;}
				}
			}
			if(timer_time[3]==0&&timer_time[4]==0&&timer_time[5]==0)
			{
				timer_flag=0;      //标志位 置零
				run1=0;						 //运行位 置零
				if(timer_flag == 0)
				{
					LCD_ShowString(2,13,"OFF ");
				}else{
					LCD_ShowString(2,13,"ON  ");
				}
				beep=0;
				Beep_Delay(500);
				beep=1;
				Beep_Delay(500);
				beep=0;
				Beep_Delay(500);
				beep=1;

			}
		}
		
		/*闹钟检测*/
		if(time[3]==alarm_time[3]&&time[4]==alarm_time[4]&&alarm_flag==1)
		{
			buzzer=1;
		}else {buzzer=0;temp=0;}

	

	}else if(cnt==249||cnt==499||cnt==749||cnt==999){flash=!flash;}    //实现闪烁显示0.5s
}

/*******************************************************************************
*串口定时器1中断函数
*******************************************************************************/
void UART_Routine() interrupt 4
{
	static int i;
	if(RI==1)					//如果接收标志位为1,接收到了数据
	{
		uart[i]=SBUF;    //将接收到的数据存入数组中
		i++;
		if(i==2)         
		{
			i=0;
			UART_Send(0xFF);    //设置一次后返回值做参考
		}
		RI=0;					//接收标志位清0
	}
}

头文件

/*******************************************************************************
*Hardware.h
*******************************************************************************/
#ifndef __HARDWARE_H__
#define __HARDWARE_H__

char Key(void);
void Timer0_Init(void);
void UART_Init(void);
void UART_Send(char Data);

#endif	

/*******************************************************************************
*LCD1602.h
*******************************************************************************/
#ifndef __LCD1602_H__
#define __LCD1602_H__

void LCD_Init(void);
void LCD_ShowString(unsigned char row,unsigned char col,unsigned char String[]);
void LCD_ShowNum(unsigned char row,unsigned char col,unsigned int Number,unsigned char Length);
void LCD_Clean(void);

#endif

/*******************************************************************************
*DS1302.h
*******************************************************************************/
#ifndef __DS1302_H__
#define __DS1302_H__

extern int time[7];

void DS1302_Init();
void DS1302_Write(char Command,Data);
char DS1302_Read(char Command);
void DS1302_Set();
void DS1302_Return();

#endif

LCD1602驱动函数

#include <at89c51RC2.h>

//引脚定义
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_E=P2^7;

void LCD_Delay()		//@12.000MHz 1ms
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}


/*******************************************************************************
* 函 数 名         : LCD_WriteCommand
* 函数功能         : 写命令字
* 输    入         : Command
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	P0=Command;
	LCD_E=1;
	LCD_Delay();
	LCD_E=0;
	LCD_Delay();
}

/*******************************************************************************
* 函 数 名         : LCD_SetCursor
* 函数功能         : 设置光标范围
* 输    入         : 行(1~2),列(1~16)
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void LCD_SetCursor(unsigned char row,unsigned char col)
{
	if(row==1)
	{
		LCD_WriteCommand(0x80|(col-1));
	}
	else
	{
		LCD_WriteCommand(0x80|(col-1)+0x40);
	}
}

/*******************************************************************************
* 函 数 名         : LCD_WriteData
* 函数功能         : 写数据
* 输    入         : Data
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	P0=Data;
	LCD_E=1;
	LCD_Delay();
	LCD_E=0;
	LCD_Delay();
}

/*******************************************************************************
* 函 数 名         : LCD_Init
* 函数功能         : 初始化
* 输    入         : none
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void LCD_Init(void)
{
	LCD_WriteCommand(0x38);    //模式:八位数据
	LCD_WriteCommand(0x0C);    //显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);    //读写操作后,光标自动加一
	LCD_WriteCommand(0x01);    //清屏
}

/*******************************************************************************
* 函 数 名         : LCD_Clean
* 函数功能         : 清屏
* 输    入         : none
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void LCD_Clean(void)
{
	LCD_WriteCommand(0x01);
}

/*******************************************************************************
* 函 数 名         : LCD_ShowString
* 函数功能         : 显示字符串
* 输    入         : 行(1~2),列(1~16),字符串
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void LCD_ShowString(unsigned char row,unsigned char col,unsigned char String[])
{
	unsigned char i;
	LCD_SetCursor(row,col);             //设置光标位置
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);      //依次取出字符串的每一位
	}
}

int LCD_Pow(int X,int Y)       //X的Y次方代码实现
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}
/*******************************************************************************
* 函 数 名         : LCD_ShowNum
* 函数功能         : 显示数字
* 输    入         : 行(1~2),列(1~16),字符串,位数
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void LCD_ShowNum(unsigned char row,unsigned char col,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(row,col);				//设置光标位置
	for(i=Length;i>0;i--)
	{
		LCD_WriteData('0'+Number/LCD_Pow(10,i-1)%10);  //依次取出数字的每一位
	} 
}

DS1302驱动函数

#include <at89c51RC2.h>

//引脚定义
sbit DS1302_SCLK = P3^6;
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;

//命令字定义
#define SECOND 	0x80
#define MINUTE 	0x82
#define HOUR 		0x84
#define DATE 		0x86
#define MONTH 	0x88
#define DAY 		0x8A
#define YEAR 		0x8C
#define WP 			0x8E

//默认上电时间
int time[7]={24,1,1,8,0,0,1};

/*******************************************************************************
* 函 数 名         : DS1302_Init
* 函数功能         : 芯片初始化
* 输    入         : void
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void DS1302_Init(void)
{
	DS1302_CE = 0;
	DS1302_SCLK = 0;
}

/*******************************************************************************
* 函 数 名         : DS1302_Write
* 函数功能         : 芯片写入
* 输    入         : command(命令字),Data(数据帧)
* 输    出         : void
* 说    明         : none
*******************************************************************************/
void DS1302_Write(unsigned char Command,Data)
{
	int i=0;
	DS1302_CE = 1;     //开启
	for(i;i<8;i++)
	{
		DS1302_IO = Command&(0x01<<i);    //顺序取出命令的每一位
		DS1302_SCLK = 1;                  //时钟上升沿读取
		DS1302_SCLK = 0;									//时钟恢复低电平
	}
	for(i=0;i<8;i++)
	{
		DS1302_IO = Data&(0x01<<i);    //顺序取出数据的每一位
		DS1302_SCLK = 1;                  //时钟上升沿读取
		DS1302_SCLK = 0;									//时钟恢复低电平
	}
	DS1302_CE = 0;     //关闭
}

/*******************************************************************************
* 函 数 名         : DS1302_Read
* 函数功能         : 芯片读出
* 输    入         : command
* 输    出         : Data
* 说    明         : none
*******************************************************************************/
char DS1302_Read(char Command)
{
	int i = 0;
	char Data = 0x00;
	Command|=0x01;     //末位置一,转为读的命令
	DS1302_CE = 1;     //根据芯片手册开启
	for(i = 0;i<8;i++)
	{
		DS1302_IO = Command&(0x01<<i);    //顺序取出命令的每一位
		DS1302_SCLK = 0;                  
		DS1302_SCLK = 1;									
	}
	for(i = 0;i<8;i++)
	{
		DS1302_SCLK = 1;                  
		DS1302_SCLK = 0;
		if(DS1302_IO)
		{
			Data|=(0x01<<i);
		}
	}
	DS1302_CE = 0;     //根据芯片手册关闭
	DS1302_IO = 0;
	return Data;
}

/*******************************************************************************
* 函 数 名         : DS1302_Set
* 函数功能         : 设置时间
* 输    入         : none
* 输    出         : none
* 说    明         : none
*******************************************************************************/
void DS1302_Set(void)
{
	DS1302_Write(WP,0x00);    //关闭写保护
	DS1302_Write(YEAR,time[0]/10*16+time[0]%10);  //十进制转BCD
	DS1302_Write(MONTH,time[1]/10*16+time[1]%10);
	DS1302_Write(DATE,time[2]/10*16+time[2]%10);
	DS1302_Write(HOUR,time[3]/10*16+time[3]%10);
	DS1302_Write(MINUTE,time[4]/10*16+time[4]%10);
	DS1302_Write(SECOND,time[5]/10*16+time[5]%10);
	DS1302_Write(DAY,time[6]/10*16+time[6]%10);
	DS1302_Write(WP,0x80);    //打开写保护
}

/*******************************************************************************
* 函 数 名         : DS1302_Return
* 函数功能         : DS1302读取时间,调用之后,DS1302中的数据会被读取到time数组中
* 输    入         : none
* 输    出         : none
* 说    明         : none
*******************************************************************************/
void DS1302_Return()
{
	int temp = 0;
	temp = DS1302_Read(YEAR);
	time[0] = temp/16*10+temp%16;    //BCD转十进制
	temp = DS1302_Read(MONTH);
	time[1] = temp/16*10+temp%16;    //BCD转十进制
	temp = DS1302_Read(DATE);
	time[2] = temp/16*10+temp%16;    //BCD转十进制
	temp = DS1302_Read(HOUR);
	time[3] = temp/16*10+temp%16;    //BCD转十进制
	temp = DS1302_Read(MINUTE);
	time[4] = temp/16*10+temp%16;    //BCD转十进制
	temp = DS1302_Read(SECOND);
	time[5] = temp/16*10+temp%16;    //BCD转十进制
	temp = DS1302_Read(DAY);
	time[6] = temp/16*10+temp%16;    //BCD转十进制
}

单片机自带外设驱动

#include <at89c51RC2.h>

/*******************************************************************************
* 功    能         : 定义本芯片所用的定时器相关地址
* 说    明         : 地址定义来自芯片手册
*******************************************************************************/
Sfr	( IPH , 0xB7);

Sfr	( XICON , 0xC0);

Sfr	( IP , 0xB8); 
Sbit (PT2, 0xB8, 5);
Sbit (PS , 0xB8, 4);
Sbit (PT1 , 0xB8, 3);
Sbit (PX1 , 0xB8, 2);
Sbit (PT0 , 0xB8, 1);
Sbit (PX0 , 0xB8, 0);


/*******************************************************************************
* 函 数 名         : Hardware_Delay
* 函数功能         : 延时函数
* 输    入         : x(ms)
* 输    出         : void
* 说    明         : @12.000MHz 1ms
*******************************************************************************/
void Hardware_Delay(int x)		
{
	unsigned char a, b;


	a = 2;
	b = 239;
	while(x--)
	{
			while (--a);
			while (--b);
	}
}
/*******************************************************************************
* 函 数 名         : Key
* 函数功能         : 读取按键键码
* 输    入         : none
* 输    出         : void
* 说    明         : Delay与while的作用为延时消抖
*******************************************************************************/
char Key()
{
	char key=0;
	if(P3_1==0){Hardware_Delay(20);while(P3_1==0);Hardware_Delay(20);key=1;}
	if(P3_0==0){Hardware_Delay(20);while(P3_0==0);Hardware_Delay(20);key=2;}
	if(P3_2==0){Hardware_Delay(20);while(P3_2==0);Hardware_Delay(20);key=3;}
	if(P3_3==0){Hardware_Delay(20);while(P3_3==0);Hardware_Delay(20);key=4;}
	return key;
}
/*******************************************************************************
* 函 数 名         : Timer0_Init
* 函数功能         : 定时器0初始化
* 输    入         : none
* 输    出         : void
* 说    明         : 中断函数模板
void Timer0_Routine() interrupt 1
{
	static int cnt;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	cnt++;
	if(T0Count>=1000)
	{
		cnt=0;
		
	}
}
*******************************************************************************/
void Timer0_Init(void)  
{
	/*TMOD&=0xF0
	  TMOD|=0x01*/
	TMOD=0x01;     //设置定时器模式
	TF0=0;         //开启定时器0
	TR0=1;         //开启定时器0
//	TH0=64535/256;
//	TL0=64535%256;
	TH0=0xFC;      //初始化计数值
	TL0=0x18;			 //初始化计数值
	EA=1;          //打开全部中断
	ET0=1;         //打开计时器0中断
	IPH=0x00;			 //设置中断优先级
	PT0=0;         //设置中断优先级
}
/*******************************************************************************
* 函 数 名         : UART_Init
* 函数功能         : 初始化串口通信
* 输    入         : none
* 输    出         : void
* 说    明         : 通过软件生成——9600bps
*******************************************************************************/
void UART_Init(void)  
{
	/*串口设置*/
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,接收模式
	/*定时器设置*/
	AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;			//设定定时初值
	TH1 = 0xFD;			//设定定时器重装值
	ET1 = 0;			//禁止定时器1中断
	TR1 = 1;			//启动定时器1
	/*中断设置*/
	EA=1;     			//打开全部中断
	ES=1;				//允许串行口中断
	PS=1;				//中断优先级设置为1
	IPH=0x00;
}
/*******************************************************************************
* 函 数 名         : UART_Send
* 函数功能         : 单片机向电脑发送字节
* 输    入         : Data:数据帧
* 输    出         : void
* 说    明         : SBUF为串口数据缓存器,TI为发送标志位,RI为接收标志位
* 中断接收函数模板
void UART_Routine() interrupt 4
{
	if(RI==1)
	{
		P2=SBUF;
		UART_Send(SBUF);
		RI=0;    //复位清零
	}
}
*******************************************************************************/
void UART_Send(char Data)
{
	SBUF=Data;
	while(TI==0);     //标志位检测
	TI=0;							//复位
}

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值