DS1302时钟程序详解,每一步都有讲解

首先附上DS1302的时序图和它的寄存器图,程序中写的不好的地方希望大家多多谅解,谢谢~在这里插入图片描述在这里插入图片描述

#include<reg52.h>			//头文件预编译
#define uchar unsigned char //宏定义
#define uint unsigned int   //宏定义
uint DisplayData[8];	    //无符号整型数码管显示的总位数
uint code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴极数码管0-9的全数组
uint code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};  //读寄存器的秒分钟日月周年
uint code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c}; //写寄存器的秒分钟日月周年
uint TIME[7] = {0x50, 0x43, 0x21, 0x25, 0x07, 0x06, 0x20};				  //数码管显示的时间2020年7月25日星期六21点43分50秒
sbit SCLK=P3^6;				//位选时钟线
sbit IO=P3^4;				//位选输出输出
sbit CE=P3^5;				//位选复位
sbit LSA=P2^2;				//数码管端口A
sbit LSB=P2^3;				//数码管端口B
sbit LSC=P2^4;				//数码管端口C

void write1302(uchar add,uchar dat)	//DS1302的写操作(写地址,写数据)
{
	uchar i;
	CE=0;							//一开始CE为0
	SCLK=0;							//时钟线为0
	CE=1;							//过段时间CE为1开始工作
	for(i=0;i<8;i++)				//FOR循环八次,写八次地址
	{
		
		IO=add&0x01;				//从最低位开始接收
		add>>=1;					//右移一位,执行8次
		SCLK=1;						//时钟线升高,上升沿
		SCLK=0;						//时钟线降低,为下一次for循环的上升沿做准备
	}
	for(i=0;i<8;i++)			    //与上同理
	{
		
		IO=dat&0x01;
		dat>>=1;
		SCLK=1;
		SCLK=0;	
	}
	CE=0;							//CE为0,停止工作
}

uint read1302(uchar add)			//DS1302的读操作,注意因为是读操作,所以有返回值,不能为void而是需要unsigned,形参为之前的地址
{
	uchar i,dat,dat1;
	SCLK=0;
	CE=0;
	CE=1;
	for(i=0;i<8;i++)
	{
		IO=add&0x01;				//与上同理
		add>>=1;
		SCLK=1;						//读操作时,时钟线做下降沿
		SCLK=0;	
	}
	for(i=0;i<8;i++)
	{
		dat1 = IO;
		dat = (dat>>1) | (dat1<<7);	//dat1左移7位变成最高位,dat1右移一位变成次高位,循环操作就能够将数据完整的读出
		SCLK = 1;
		SCLK = 0;
			
	}
		CE = 0;	
		return dat;					//返回dat值
}

void init1302()						//初始化ds1302
{
	uchar i;
	write1302(0x8e,0);				//去除写保护
	for(i=0;i<7;i++)
	{
		write1302(WRITE_RTC_ADDR[i],TIME[i]);//循环七次的目的就是为了能够将秒分钟日月周年输入,括号内就是为之前的写地址和写数据	
	}
	write1302(0x8e,0x80);			//重新赋予写保护
}

void read1302time()					//读取ds1302的数据
{
	uchar i;
	for(i=0;i<7;i++)
	{
		TIME[i]=read1302(READ_RTC_ADDR[i]) ;//读七次,依次输出秒分钟日月周年,但是要注意的是,由于八段数码管数量有限,只能显示出时分秒
	}
}

void delay(uint i)				    //延时函数,当i为1时,延时大概10ms
{
	while(i--);	
}

void datapros() 	 				//数据处理函数
{
   	read1302time();
	DisplayData[0] = smgduan[TIME[2]/16];				//显示小时的整数位
	DisplayData[1] = smgduan[TIME[2]&0x0f];				//显示小时的低位 
	DisplayData[2] = 0x40;								//显示“-”
	DisplayData[3] = smgduan[TIME[1]/16];				//同理
	DisplayData[4] = smgduan[TIME[1]&0x0f];	
	DisplayData[5] = 0x40;
	DisplayData[6] = smgduan[TIME[0]/16];				//同理
	DisplayData[7] = smgduan[TIME[0]&0x0f];
}



void DigDisplay()										//八段数码管的位选显示
{
	uchar i;
	for(i=0;i<8;i++)
	{
		switch(i)	 
		{
			case(0):
				LSA=1;LSB=1;LSC=1; break;//显示第0位
			case(1):
				LSA=0;LSB=1;LSC=1; break;//显示第1位
			case(2):
				LSA=1;LSB=0;LSC=1; break;//显示第2位
			case(3):
				LSA=0;LSB=0;LSC=1; break;//显示第3位
			case(4):
				LSA=1;LSB=1;LSC=0; break;//显示第4位
			case(5):
				LSA=0;LSB=1;LSC=0; break;//显示第5位
			case(6):
				LSA=1;LSB=0;LSC=0; break;//显示第6位
				case(7):
				LSA=0;LSB=0;LSC=0; break;//显示第7位
		}
		P0=DisplayData[i];				 //发送数据
		delay(100); 					 //间隔一段时间扫描	
		P0=0x00;						 //消隐
	}		
}
void main()
{	
	init1302();	   						
	while(1)
	{
		datapros();	 					 //数据处理函数
		DigDisplay();					 //数码管显示函数		
	}		
}

猜你喜欢

转载自blog.csdn.net/weixin_49046017/article/details/107591744
今日推荐