⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ds1303_.c

📁 这是我看了《十天学会单片机》(郭天祥的教程)/*这个程序
💻 C
字号:
/*这个程序,是我用51电子网,298元C51学习板调试通的单片机控制DS1303时钟芯片
一个时钟程序,它能实现断电走时(用纽扣电池),显示和设置年月日星期时分秒(8位数码管)。
*/

#include<reg51.h>
#define uchar unsigned char//宏定义字符型
#define uint unsigned int//宏定义长整型

sbit CE=P3^5;//
sbit IO=P3^4;//
sbit SCLK=P3^3;//
int yr,mn,dy,date,hr,min,sec,gnj,wz;//分别代表年月日星期时分秒功能键,wz是判断键盘输入的

uchar code table[]={//定义字串数组数码管显示用分别是 0123456789_和全灭,这个数码管是共阳极的
0x12,0xfa,0x1c,0x98,
0xf0,0x91,0x11,0xda,
0x10,0x90,0xbf,0xff};

uchar code table2[]={//字串数组 数码管段位用,通74HC164N芯片控制8个数码管,的段显示
0x80,0x40,0x20,0x10,
0x08,0x04,0x02,0x01};

/***************************************************************************/

void delay()//延时函数,很短的延时
{ ;; }

void delay1(uint x)//延时函数
{
	uint a,b;
	for(a=x;a>0;a--)for(b=110;b>0;b--);
}

void xianshi(uchar s,uchar f,uchar m,uchar t)//显示函数,显示0-8个数码管,分别是四组两位数。
{
	uint ssw,sgw,fsw,fgw,msw,mgw,tsw,tgw;//分别代表四组数的十位和个位

		if(s==0xff)//当变量=0xff时数码管显示 _ 表示光标。 
		{
			ssw=10;
			sgw=10;
		}
		else
		{
			ssw=s/10;
			sgw=s%10;
		}
		if(f==0xff)
		{
			fsw=10;
			fgw=10;
		}
		else
		{
			fsw=f/10;
			fgw=f%10;
		}
		if(m==0xff)
		{
			msw=10;
			mgw=10;
		}
		else
		{
			msw=m/10;
			mgw=m%10;
		}
		if(t==0xff)
		{
			tsw=10;
			tgw=10;
		}
		else
		{
			tsw=t/10;
			tgw=t%10;
		}
		if(t==0xfd)//最后一组数码管不显示。
		{
			tsw=11;
			tgw=11;

		}
	REN=1;//打开74H164N芯片写入口
	SBUF=table2[0];//发送数据,数码管第一位亮
	delay();
	P1=table[ssw];//显示第一组数的十位
	delay1(3);
	P1=0xff;      //消除数码管光影。
	SBUF=table2[1];
	delay();
	P1=table[sgw];//第一组数的个位
	delay1(3);
	P1=0xff;
	
	SBUF=table2[2];
	delay();
	P1=table[fsw];
	delay1(3);
	P1=0xff;
	SBUF=table2[3];
	delay();
	P1=table[fgw];
	delay1(3);
	P1=0xff;
	
	SBUF=table2[4];
	delay();
	P1=table[msw];
	delay1(3);
	P1=0xff;
	SBUF=table2[5];
	delay();
	P1=table[mgw];
	delay1(3);
	P1=0xff;
	
	SBUF=table2[6];//
	delay();
	P1=table[tsw];//
	delay1(3);
	P1=0xff;
	SBUF=table2[7];
	delay();
	P1=table[tgw];//
	delay1(3);
	P1=0xff;
	
	REN=0;
}






void reset_3w()   /* ----- 时钟芯片通信口初始化 ------ */

{

   SCLK = 0;

   CE = 0;

   CE = 1;

}

void wbyte_3w(uchar W_Byte) /* ------ 写一个字节的数据到时钟芯片 ------- */

{

uchar i;

    for(i = 0; i < 8; ++i)//几次循环8次,发送8位数据

    {

       IO = 0;

       if(W_Byte & 0x01)

       {

           IO = 1;    /* 当IO口位高电平时发送数据 */

       }

       SCLK = 0;

       SCLK = 1;

       W_Byte >>= 1;//数据右移

      }

}

uchar  rbyte_3w() /* ------- 读芯片一个字节的数据 -------- */

{

uchar i,j;

uchar R_Byte;//用作存储读出的数据

uchar TmpByte;//临时变量


 


    R_Byte = 0x00;

    IO = 1;//初始化数据口

    for(i = 0; i < 8; i++)

    {

       SCLK = 1;

       SCLK = 0;

       TmpByte = (uchar)IO;//读出数据

       TmpByte <<= 7;//移到高位

       R_Byte >>= 1;

       R_Byte |= TmpByte; 

    }



   j=R_Byte>>4;//以下是将BCD码转换位正常十六进制数。(BCD码0x16,的意思是十进制的16转换后0x0f)	
	j*=10;
	R_Byte=R_Byte&0x0f;
	R_Byte+=j;
    return R_Byte;

}


uchar ask_bcd(uchar ask)//把正常十六进制数转换成BCD码
{
	uchar g4,d4,bcd;
	g4=ask/10;//取出十位数例如0x0f,十进制为16
	d4=ask%10;//取出个位数    g4=0x01,d4=0x06
	bcd=g4<<4;//把十位数移到高位g4=0x10,
	bcd=bcd+d4;//得出BCD码       bcd=0x16
   return bcd;
}

void   writebyte(uchar ClkAdd,uchar ClkData)   /* --- 在指定位置写入一个字节数据 --- */

{

    reset_3w();

    wbyte_3w(ClkAdd);//地址

    wbyte_3w(ClkData);//数据

    reset_3w();

}

uchar dusj(uchar add)//在指定位置读出数据用来读时钟芯片内部存储器的数据add是地址数据
{
uchar j;
   reset_3w();
	wbyte_3w(add);
	j= rbyte_3w();
    reset_3w();

return j;


}


void read_clk_regs() /* ---- 读出年周月日时分秒---- */

{

       reset_3w();//初始化数据口

       wbyte_3w(0xBF);   /* 写入读命令 */

       sec = rbyte_3w();

       min = rbyte_3w();

       hr = rbyte_3w();

       dy = rbyte_3w();

       mn= rbyte_3w();

       date = rbyte_3w();

       yr = rbyte_3w();

          reset_3w();

}



void   write_clk_regs(uchar  yr2,date2, mn2, dy2,hr2,min2,sec2) 

/*一次性写入年周月日时分秒 */

{


    reset_3w();

    wbyte_3w(0x8e);   /* 置写入命令 */

    wbyte_3w(0);      /* 打开写保护 */

    reset_3w();

    wbyte_3w(0x90);   /* 容许时钟芯片给纽扣电池充电 */

    wbyte_3w(0xab);   /* 容许读写时钟芯片外部寄存器 */

    reset_3w();

    wbyte_3w(0xbe);   /* 命令时钟芯片一次接收8组数据分别是秒分时日月周年*/

    wbyte_3w(sec2);

    wbyte_3w(min2);

    wbyte_3w(hr2);

    wbyte_3w(dy2);

    wbyte_3w(mn2);

    wbyte_3w(date2);

    wbyte_3w(yr2);

    wbyte_3w(0);      /* 最后一位结束位发0*/

    reset_3w();

}
uchar key()//键盘扫描程序
{
	uchar fhz;//返回值
	wz=0;//设置键盘控制变量初始化
	fhz=0;
	P0=0xfe;//P0 口的矩阵键盘(这里只用了4个键盘k4,k8,k12,k16)
	/*k4为加号键。k8是减号键。K12是功能键(gnj变量是1,正常显示时分秒,gnj是2,设置年
	gnj是3,设置月。gnj是4,设置日,。gnj是5,设置 星期,。gnj是6,设置 时,。gnj是7,设置
	分。gnj是8,设置秒*/
	while(P0==0xee)//k16按下显示年月日星期
	{
		if(sec==1)read_clk_regs();
			xianshi(yr,mn,dy,date);
	}
	if(P0==0xde)//k12按下设置功能
	{
			delay1(5);//等待5毫秒
			if(P0==0xde)//判断真的按键了
			{
				gnj++;
				if(gnj==9)gnj=1;
			}
			while(P0==0xde);//等待松手
			fhz=0;
	}

   
	if(P0==0x7e)//k4,返回值=2为减号键
	{
		delay1(15);
		if(P0==0x7e)
		{
		   while(P0==0x7e);
			fhz=2;
		}
		
	}

	if(P0==0xbe)//k8,返回值=1为加号键
	{
		delay1(15);
		if(P0==0xbe)
		{
			while(P0==0xbe);
			fhz=1;
		}
		
	}
	return fhz;
}

int suanxingqi(int y,int m,int d)//计算星期函数变量为年月日,例如2009,1,18
{
	int w;
	if(m<2)m=m+12;
	w= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
	if(w==0)w=7;
	return w;
}

uchar runnian(uchar nian)//计算闰年函数判断变量nian是否是闰年。如2009
{
	if((nian%400==0) || (nian%100!=0) && (nian%4==0))
	{
		return 1;//是闰年
 	}
	else
	{
		return 0;//不是闰年 
   }
}

void main() 
{
	uint san;//这个变量是用来起到光标闪烁效果的,san=0到10时显示正常,san=10-20显示光标
	uint yr1,mn1,dy1,date1,hr1,min1,sec1;//年月日时分秒星期临时变量,转换BCD码用的。
	gnj=1;//初始化功能键变量
	while(1)//进入大循环
	{
		
		while(gnj==1)//正常显示(时分秒)
		{
			read_clk_regs();
			xianshi(hr,min,sec,0xfd);
			delay1(1);
			wz=key();
		}
		
		while(gnj==2)//功能键=2时设置年
		{
			
		   if(san<20)//闪烁显示秒
			{
				xianshi(yr,mn,dy,date);
			}
			if(san>30)
			{
				xianshi(0xff,mn,dy,date);//让显示函数,在年的位置显示光标
			}
		
		   san++;
			if(san>40)
			{
				san=0;
		   }
			
			wz=key();

			if(wz==1)//按了加号键
			{
				yr++;//年加一(年的数值范围00-99)
				if(yr==100)
				{
					yr=0;
				}	
			}
			if(wz==2)//按了减号键
			{
				if(yr==0)
				{
					yr=100;
				}	
			  yr--;

			}
		}	
		while(gnj==3)//功能键=3时设置几月
		{
			
		   if(san<20)//闪烁显示秒
			{
				xianshi(yr,mn,dy,date);
			}
			if(san>30)
			{
				xianshi(yr,0xff,dy,date);//让显示函数,在月的位置显示点
			}
		
		   san++;
			if(san>40)
			{
				san=0;
		   }
			wz=key();
			if(wz==1)
			{
				mn++;
				if(mn>12)
				mn=1;
		
			}
			if(wz==2)
			{
				mn--;
				if(mn<1)
				mn=12;
			}
		
		}	
	
		while(gnj==4)//功能键=4时设置日期
		{
			
		   if(san<20)//闪烁显示秒
			{
				xianshi(yr,mn,dy,date);
			}
			if(san>30)
			{
				xianshi(yr,mn,0xff,date);//让显示函数,在日期的位置显示光标
			}
		
		   san++;
			if(san>40)
			{
				san=0;
		   }
			wz=key();
			if(wz==1)
			{
				dy++;
				
			}
			if(wz==2)
			{
				if(dy<=1)
				{dy=32;}

				dy--;
			
			}
			yr1=2000+yr;
			
			if((dy>28)&&(runnian(yr1)==0)&&(mn==2))//判断不是闰年且是2月份只有28天
			{
				 if(wz==1)
				 {
				 	dy=1;
				 }
				 else
				 {
				 	dy=28;
				 }
			}
			if((dy>29)&&(mn==2))//判断是闰年且是2月份,最多29天
			{
				 if(wz==1)
				 {
				 	dy=1;
				 }
				 else
				 {
				 	dy=29;
				 }
			}
			if(dy>30)
			{
				if((mn==4)||(mn==6)||(mn==9)||(mn==11))//判断是小月的话只有30天
				{
					if(wz==1)
					{
					dy=1;
					}
					else
					{
					dy=30;
					}
					
				}
			}
			if(dy>31)//剩下最后的大月才有31天
			{
				if(wz==1)//判断按的是加号键31天归1
				{
				dy=1;
				}
				else//否则按的是减号键1回到31
				{
				dy=31;
				}
				
  			}
			



		
		}	
		while(gnj==5)//功能键=5时设置星期
		{
			
			date1=2000+yr;
			date=suanxingqi(date1,mn,dy);//自动算出星期

		   if(san<20)//闪烁显示秒
			{
				xianshi(yr,mn,dy,date);
			}
			if(san>30)
			{
				xianshi(yr,mn,dy,0xff);//让显示函数,在星期的位置显示点
			}
		
		   san++;
			if(san>40)
			{
				san=0;
		   }
			wz=key();//不能调节
		
		
		}	
	
		while(gnj==6)//功能键=6时设置小时
		{
			
		   if(san<20)//闪烁显示秒
			{
				xianshi(hr,min,sec,0xfd);
			}
			if(san>30)
			{
				xianshi(0xff,min,sec,0xfd);//让显示函数,在秒的位置显示光标,0xfd让数码管无显示
			}
		
		   san++;
			if(san>40)
			{
				san=0;
		   }
			wz=key();
			if(wz==1)
			{
				hr++;
				if(hr>23)
				{hr=0;}
		
			}
			if(wz==2)
			{
				
				if(hr==0)
				{hr=24;}
				hr--;
			}
		
		}	
		while(gnj==7)//功能键=7时设置分钟
		{
			
		   if(san<20)//闪烁显示秒
			{
				xianshi(hr,min,sec,0xfd);
			}
			if(san>30)
			{
				xianshi(hr,0xff,sec,0xfd);//让显示函数,在分的位置显示点
			}
		
		   san++;
			if(san>40)
			{
				san=0;
		   }
			wz=key();
			if(wz==1)
			{
				min++;
				if(min>59)
				{min=0;}
			}
			if(wz==2)
			{
				
				if(min==0)
				{min=60;}
				min--;
			}
		
		}	
	
		while(gnj==8)//功能键=8时设置秒钟
		{
			
		   if(san<20)//闪烁显示秒
			{
				xianshi(hr,min,sec,0xfd);
			}
			if(san>30)
			{
				xianshi(hr,min,0xff,0xfd);//让显示函数,在秒的位置显示光标
			}
		
		   san++;
			if(san>40)
			{
				san=0;
		   }
			wz=key();
			if(gnj==1)//完成设置存入DS1303芯片
			{
					date1=2000+yr;
					date=suanxingqi(date1,mn,dy);//根据年月日算出星期

					yr1=ask_bcd(yr);//转换成BCD码
					mn1=ask_bcd(mn);
					dy1=ask_bcd(dy);
					date1=ask_bcd(date);
					hr1=ask_bcd(hr);
					min1=ask_bcd(min);
					sec1=ask_bcd(sec);
					
					write_clk_regs(yr1,date1,mn1,dy1,hr1,min1,sec1);//写入数据
					delay1(20);
			}
			if(wz==1)
			{
				sec++;
				if(sec>59)
				{sec=0;}
		
			}
			if(wz==2)
			{
				
				if(sec==0)
				{sec=60;}
				sec--;
			}
		
		}	
	
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -