51_LCD1602 - DS1302可调时钟

DS1302.c

#include "DS1302.h"
#include "lcd1602.h"

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

//寄存器写入地址/指令定义
#define DS1302_miao		0x80
#define DS1302_feng		0x82
#define DS1302_shi			0x84
#define DS1302_ri			0x86
#define DS1302_yue		0x88
#define DS1302_xingqi			0x8A
#define DS1302_nian			0x8C
#define DS1302_WP			0x8E       //写保护


//时间数组,索引0~6分别为年、月、日、时、分、秒、星期,设置为有符号的便于<0的判断
char  DS1302_Time[]={19,11,16,22,56,0,6};

void DS1302_Init(void)  //DS1302初始化
{
	DS1302_CE=0;
	DS1302_SCLK=0;  
}

void DS1302_WriteByte(unsigned char Command,Data) //DS1302写一个字节 Command 命令字/地址 Data 要写入的数据
{
	unsigned char i;
	DS1302_CE=1;                    //CE时钟高开始写数据
	for(i=0;i<8;i++)                //写命令
	{
//		DS1302_IO=Command&(0x01<<i);  //最低位开始写
    DS1302_IO=Command&0x01;    //读数据
    Command >>= 1;
		DS1302_SCLK=1;               //SCLK高写数据
		DS1302_SCLK=0;
	}
	for(i=0;i<8;i++)              //写数据
	{
		DS1302_IO=Data&(0x01<<i);   //最低位开始写
//     DS1302_IO=Data&0x01;    //读数据
//     Data >>= 1;
		DS1302_SCLK=1;             //SCLK高写数据
		DS1302_SCLK=0; 
	}
	DS1302_CE=0;                //写完释放时钟CE置零
}

unsigned char DS1302_ReadByte(unsigned char Command)  //DS1302读一个字节 Command 命令字/地址
{
	unsigned char i,Data=0x00;

	Command|=0x01;	//将指令转换为读指令
	DS1302_CE=1;       //CE时钟高开始读数据a
	for(i=0;i<8;i++)               //读命令
	{
		DS1302_IO=Command&(0x01<<i);    //读数据
//    DS1302_IO=Command&0x01;    //读数据
//    Command >>= 1;
		DS1302_SCLK=0;
		DS1302_SCLK=1;  //SCLK高写数据
	}
	for(i=0;i<8;i++)    //读数据
	{
   
		DS1302_SCLK=1;   
		DS1302_SCLK=0;     //SCLK读数据

   if(DS1302_IO){Data|=(0x01<<i);} //{Data=Data|(0x01<<i);}  读出端口是1就置1
//     Data>>=1; 
//    if(DS1302_IO){Data|=0x80;} //{Data=Data|(0x01<<i);}  读出端口是1就置1


	}
	DS1302_CE=0;       //读完释放时钟CE置零
	DS1302_IO=0;	//读取后将IO设置为0,否则读出的数据会出错
	return Data;

}

uchar dat_to_BCD(uchar dat)//数据转BCD码
{
	uchar dat1,dat2;
	dat1 = dat / 10;
	dat2 = dat % 10;
	dat2 = dat2 + dat1 * 16;
	return dat2;
}

uchar BDD_to_dat(uchar dat)//BCD码转数据
{
	uchar dat1,dat2;
	dat1 = dat /16;
	dat2 = dat % 16;
	dat2 = dat2 + dat1 * 10;
	return dat2;
}

void DS1302_SetTime(void)  //十进制转BCD码后写入DS1302中
{
	DS1302_WriteByte(DS1302_WP,0x00);  //WP=0 写操作
	DS1302_WriteByte(DS1302_nian,dat_to_BCD(DS1302_Time[0]));//
	DS1302_WriteByte(DS1302_yue,dat_to_BCD(DS1302_Time[1])); //
	DS1302_WriteByte(DS1302_ri	,dat_to_BCD(DS1302_Time[2]));//
	DS1302_WriteByte(DS1302_shi	,dat_to_BCD(DS1302_Time[3]));//
	DS1302_WriteByte(DS1302_feng,dat_to_BCD(DS1302_Time[4]));//
	DS1302_WriteByte(DS1302_miao,dat_to_BCD(DS1302_Time[5]));//
	DS1302_WriteByte(DS1302_xingqi,dat_to_BCD(DS1302_Time[6]));//星期
	DS1302_WriteByte(DS1302_WP,0x80);    //WP=0x80打开写保护功能

}

void DS1302_ReadTime(void)  //BCD码转十进制后保存到数组准备读取
{
  DS1302_Time[0]=BDD_to_dat(DS1302_ReadByte(DS1302_nian));
  DS1302_Time[1]=BDD_to_dat(DS1302_ReadByte(DS1302_yue));
  DS1302_Time[2]=BDD_to_dat(DS1302_ReadByte(DS1302_ri));
  DS1302_Time[3]=BDD_to_dat(DS1302_ReadByte(DS1302_shi));
  DS1302_Time[4]=BDD_to_dat(DS1302_ReadByte(DS1302_feng));
  DS1302_Time[5]=BDD_to_dat(DS1302_ReadByte(DS1302_miao));
  DS1302_Time[6]=BDD_to_dat(DS1302_ReadByte(DS1302_xingqi));
}

void TimeShow(void)//时间显示功能
{
	DS1302_ReadTime();//读取时间
	LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年
	LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月
	LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日
	LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时
	LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分
	LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒
}

DS1302.h

#include "system.h"

//外部可调用时间数组,索引0~6分别为年、月、日、时、分、秒、星期,设置为有符号的便于<0的判断
extern char DS1302_Time[];

void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);

uchar dat_to_BCD(uchar dat);//数据转BCD码
uchar BDD_to_dat(uchar dat);//BCD码转数据

void TimeShow(void);//时间显示功能;

#endif

key.c

#include "key.h"	 //把led.h文件包含进来
#include "system.h"	   //把timer0.h文件包含进来
#include "led.h"

#include "DS1302.h"
#include "lcd1602.h"
uchar p=0;

unsigned char TimeSetSelect;
uchar flag,wei;	   //在其他模块中寻找其定义。另外,extern也可用来进行链接指定。

u8 KeyScan ()		//按键扫描函数
{
	static	uint timer=0;

	if(k1==0)
	{  
		timer++;
		if(timer==10){return 1;} //定时10毫秒返回
    else if(timer==1000){timer=500;return 1;} //否则长按不停加1
	}
	else if(k2==0)
	{
		timer++;  
		if(timer==10){return 2;} //定时10毫秒返回
		//else if(timer==1000){timer=900;return 2;} //否则长按不停加1
		else if(timer==1000){timer=500;return 2;} //否则长按不停加1
	}
	else if(k3==0)
	{
		timer++;
		if(timer==10){return 3;} //定时10毫秒返回
		else if(timer==1000){timer=500;return 3;} //否则长按不停加1
	}
	else if(k4==0)
	{
		timer++;
		if(timer==10){return 4;}  //定时10毫秒返回
    else if(timer==1000){timer=500;return 4;} //否则长按不停加1
	}
	else
	{
		timer=0;	   //定时清0
	}
	return 0;	
}

void datapros()
{
	uchar key;
	key=KeyScan();	 //key=调用检测按键函数
	
	if(key==1)	   
	{
		p++;
	
	 if(p>1){p=0;}
//     p%=2;//越界清零
//     p=p%2;//越界清零
  }
  	if(flag==1)	//加了我之后,我的大括号里面的东西,被定期的1ms执行一次,反复执行	 	
		{
      lcd_sansuo();  //lcd选中的位闪烁
     
	   if(key==2)
			{
				wei++;//设置选择位加1
        wei%=6;//位选越界清零

        LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年
				LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月
				LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日
				LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时
				LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分
				LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒					
	  	}
		 if(key==3)
			{
       switch(wei)	//选中的位选--
				{
					case 0:  DS1302_Time[0]++; break;  //++
					case 1:  DS1302_Time[1]++; break;  //++
					case 2:  DS1302_Time[2]++; break;  //++
          case 3:  DS1302_Time[3]++; break;  //++
					case 4:  DS1302_Time[4]++; break;  //++
					case 5:  DS1302_Time[5]++; break;  //++
				}	
			if(DS1302_Time[0]>99){DS1302_Time[0]=0;}//年越界判断
			if(DS1302_Time[1]>12){DS1302_Time[1]=1;}//月越界判断
			if(DS1302_Time[2]>12){DS1302_Time[2]=0;}//日越界判断
			if(DS1302_Time[3]>23){DS1302_Time[3]=0;}//时越界判断
			if(DS1302_Time[4]>59){DS1302_Time[4]=0;}//分越界判断
			if(DS1302_Time[5]>59){DS1302_Time[5]=0;}//秒越界判断
			LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年
			LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月
			LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日
			LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时
			LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分
			LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒					
				
			DS1302_SetTime(); //十进制转BCD码后写入
		 }
		 if(key==4)
			{
			  switch(wei)	//选中的位选--
				{
					case 0:  DS1302_Time[0]--; break;  //++
					case 1:  DS1302_Time[1]--; break;  //++
					case 2:  DS1302_Time[2]--; break;  //++
          case 3:  DS1302_Time[3]--; break;  //++
					case 4:  DS1302_Time[4]--; break;  //++
					case 5:  DS1302_Time[5]--; break;  //++
				}	
      if(DS1302_Time[0]<0){DS1302_Time[0]=99;}//年越界判断
			if(DS1302_Time[1]<1){DS1302_Time[1]=12;}//月越界判断
			if(DS1302_Time[2]<0){DS1302_Time[2]=31;}//时越界判断
			if(DS1302_Time[3]<0){DS1302_Time[3]=23;}//时越界判断
			if(DS1302_Time[4]<0){DS1302_Time[4]=59;}//分越界判断
			if(DS1302_Time[5]<0){DS1302_Time[5]=59;}//秒越界判断

			LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年
			LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月
			LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日
			LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时
			LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分
			LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒					
				
			DS1302_SetTime(); //十进制转BCD码后写入
		 }
   }
}

void moshi()  //模式切换
{
//  uchar key;
//  key=KeyScan();	 //key=调用检测按键函数

//	if(key==1)
//	 {
//	 p++;

//	 if(p>1){p=0;}
////     p%=2;//越界清零
////     p=p%2;//越界清零
//	 }
	switch(p)
		{
			case 0:	TimeShow();flag=0; break;//时间显示功能	
			case 1:;flag=1;break;    
		}
}

void lcd_sansuo()
{
 static uint i;
	 i++;
	if(i==500)//500ms
	{  
		switch(wei)	   //选中的位选
		{
      case 0:  LCD_ShowString(1,1,"  "); break;  //++
			case 1:  LCD_ShowString(1,4,"  "); break;  //++
			case 2:  LCD_ShowString(1,7,"  "); break;  //++
			case 3:  LCD_ShowString(2,1,"  "); break;  //++
			case 4:  LCD_ShowString(2,4,"  "); break;  //++
			case 5:  LCD_ShowString(2,7,"  "); break;  //++
  	}	
	}
	if(i==1000)   //1000ms
	{
		i=0;
		switch(wei)	 //选中的位选
		{
		  case 0:  LCD_ShowNum(1,1,DS1302_Time[0],2); break;  //++
			case 1:  LCD_ShowNum(1,4,DS1302_Time[1],2); break;  //++
			case 2:  LCD_ShowNum(1,7,DS1302_Time[2],2); break;  //++
			case 3:  LCD_ShowNum(2,1,DS1302_Time[3],2); break;  //++
			case 4:  LCD_ShowNum(2,4,DS1302_Time[4],2); break;  //++
			case 5:  LCD_ShowNum(2,7,DS1302_Time[5],2); break;  //++
  	}			
	}

}

key.h

#include "system.h"	   //把timer0.h文件包含进来

sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;	 //定义按键端口
		
u8 KeyScan ();		//按键扫描函数
void datapros();


void moshill();    //模式切换
void lcd_sansuo(); //lcd选中的位闪烁

main.c

#include "system.h"
#include "key.h"
#include "led.h"
#include "lcd1602.h"
#include "system.h"
#include "DS1302.h"

extern	uchar flag_1ms;	   //在其他模块中寻找其定义。另外,extern也可用来进行链接指定。

void main(void)			//程序的主函数
{
	Timer0_Init(); ////定时器0函数调用
  LCD_Init();
	DS1302_Init();
  LCD_ShowString(1,1,"  -  -  ");//静态字符初始化显示
	LCD_ShowString(2,1,"  :  :  ");
	DS1302_SetTime();//设置时间

  
	while(1)  			//大括号里面的东西,被不停的循环执行
	{ 

		//1ms进入一次
		if(flag_1ms==1)	//加了我之后,我的大括号里面的东西,被定期的1ms执行一次,反复执行	 	
		{
			flag_1ms=0;

      moshi(); //	时钟模式切换

		}

	}
}

system.h

#include "reg51.h"


#define	uchar unsigned char	//定义无符号字符
#define	uint  unsigned int	//定义无符号整形

#define	u8 unsigned char	//定义无符号字符
#define	u16  unsigned int	//定义无符号整形

#define	FOSC	12000000L	//定义晶振频率		   
#define	T1MS	(65536-FOSC/12/1000)  //定时1毫秒的时候,计数器要写入的值

void	Delay_us(uint xus);	//us级延时
void	Delay_ms(uint xms);	//ms级延时
void	Timer0_Init(void);  	//定时器初始化

system.c

#include "system.h"

uchar flag_1ms=0;

void	Timer0_Init(void)
{
	TH0 = T1MS>>8; //赋初值
	TL0 = T1MS;	   //赋初值
	TMOD = 0x01;  //设置定时器0用十六位定时器方式
    EA = 1;			 //打开总中断
  	ET0 = 1;		 //打开定时器0中断
  	TR0 = 1;		 //启动定时器0		
}

void Timer0() interrupt 1		 //中断号1
{	
	TH0 = T1MS>>8; //赋初值
	TL0 = T1MS;	   //赋初值
	flag_1ms=1;
 
  datapros();

}

void	Delay_us(uint xus)
{
	for(;xus>0;xus--);
}

void	Delay_ms(uint xms)
{
	for(;xms>0;xms--)
	{
		Delay_us(1000);
	}
}
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值