89C52单片机实现万年历

这个实验的内容是:利用DS1302芯片,实现万年历。从DS1302芯片读取的时间数值,以滚显的方式在四位数码管上显示,并使用Proteus仿真。

Proteus图:
89C52单片机实现万年历_第1张图片

具体实现方式请看下面的程序:

#include"main.h"

unsigned char DisplayData[20];  //显示时间年-周-月-日-时-分-秒
unsigned char digitvalue[4]={
     0xff,0xff,0xff,0xff};  //采用共阳数码管,让四个数码管初始的时候什么也不显示
unsigned char temp;
unsigned char t;
unsigned char i;
unsigned int s;

void delay(unsigned int i){
       //延时函数
	while(i--);
}
//数码管段码0~9
unsigned char code smgduan[10]={
     0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

void datapros(unsigned char *TIME)  //将16进制数处理成10进制	 
{
     
	DisplayData[0] = smgduan[TIME[6]/16];				//年,年的十位
	DisplayData[1] = smgduan[TIME[6]&0x0f];			//年的个位,下面同理	 
	DisplayData[2] = ~(0x40);  //分隔符
	DisplayData[3] = smgduan[TIME[5]/16];				//周
	DisplayData[4] = smgduan[TIME[5]&0x0f];	
	DisplayData[5] = ~(0x40);
	DisplayData[6] = smgduan[TIME[4]/16];				//月
	DisplayData[7] = smgduan[TIME[4]&0x0f];
	DisplayData[8] = ~(0x40);
	DisplayData[9] = smgduan[TIME[3]/16];				//日
	DisplayData[10] = smgduan[TIME[3]&0x0f];	
	DisplayData[11] = ~(0x40);
	DisplayData[12] = smgduan[TIME[2]/16];				//时
	DisplayData[13] = smgduan[TIME[2]&0x0f];
	DisplayData[14] = ~(0x40);
	DisplayData[15] = smgduan[TIME[1]/16];				//分
	DisplayData[16] = smgduan[TIME[1]&0x0f];	
	DisplayData[17] = ~(0x40);
	DisplayData[18] = smgduan[TIME[0]/16];				//秒
	DisplayData[19] = smgduan[TIME[0]&0x0f];
}

void DigDisplay(unsigned char *DisplayData)
{
     
	for(t=0;t<20;t++){
       //循环20次,以滚显的方式在数码管上显示时间年-周-月-日-时-分-秒,共有20个数
		temp=DisplayData[t];  
		digitvalue[3]=digitvalue[2];
		digitvalue[2]=digitvalue[1];
		digitvalue[1]=digitvalue[0];
		digitvalue[0]=temp;
    for(s=0;s<250;s++){
     	 //循环显示,延时一下	
	    for(i=0;i<4;i++)
	    {
     
		    switch(i){
                //位选,选择点亮的数码管,  
          case(0): 
            LSA=0;LSB=0;LSC=0;LSD=1; break;//显示第 0 位 
          case(1): 
            LSA=0;LSB=0;LSC=1;LSD=0; break;//显示第 1 位 
          case(2): 
            LSA=0;LSB=1;LSC=0;LSD=0; break;//显示第 2 位 
          case(3): 
            LSA=1;LSB=0;LSC=0;LSD=0; break;//显示第 3 位 
		    }
		    P0=digitvalue[i];//发送数据		    
				delay(100); //间隔一段时间扫描	
				P0=0xFF;//消隐
	    }
	  }
  }	
}

void main(){
     
	Ds1302Init();  //DS1302芯片初始化,写入初始值
	while(1){
     
		Ds1302ReadTime();  //读取DS1302芯片的时间的值
		datapros(TIME);    //将16进制数处理成10进制
		DigDisplay(DisplayData);  //将读取到的值在数码管上显示出来
	}
}
#ifndef __MAIN_H__
#define __MAIN_H__
		 
	#include"ds1302.h"
	#include"timer0.h"
	extern unsigned char TIME[7];
	sbit LSA=P1^3; 
	sbit LSB=P1^2; 
	sbit LSC=P1^1; 
	sbit LSD=P1^0;

#endif
#include"ds1302.h"

//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
unsigned char code READ_RTC_ADDR[7] = {
     0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
unsigned char code WRITE_RTC_ADDR[7] = {
     0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
unsigned char TIME[7] = {
     0x00, 0x00, 0x12, 0x09, 0x12, 0x07, 0x19};	 //初始化的时间,秒 分 时 日 月 周 年

//下面要用到SPI总线的时序来发送和接收数据
void Ds1302Write(unsigned char addr, unsigned char dat)  //要给函数传入地址和数据
{
     
	unsigned char n;
	RST = 0;  
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1; //然后将RST置高电平。
	_nop_();

	for (n=0; n<8; n++)//开始传送八位地址命令
	{
     
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();
	}
	for (n=0; n<8; n++)//写入8位数据
	{
     
		DSIO = dat & 0x01;
		dat >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();	
	}	
		 
	RST = 0;//传送数据结束
	_nop_();
}


unsigned char Ds1302Read(unsigned char addr)
{
     
	unsigned char n,dat,dat1;
	RST = 0;
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1;//然后将RST置高电平。
	_nop_();

	for(n=0; n<8; n++)//开始传送八位地址命令
	{
     
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}
	_nop_();
	for(n=0; n<8; n++)//读取8位数据
	{
     
		dat1 = DSIO;//从最低位开始接收
		dat = (dat>>1) | (dat1<<7);
		SCLK = 1;
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}

	RST = 0;
	_nop_();	//以下为DS1302复位的稳定时间,必须的。
	SCLK = 1;
	_nop_();
	DSIO = 0;
	_nop_();
	DSIO = 1;
	_nop_();
	return dat;	
}

void Ds1302Init()
{
     
	unsigned char n;
	Ds1302Write(0x8E,0X00);		 //禁止写保护,就是关闭写保护功能
	for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
	{
     
		Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);	
	}
	Ds1302Write(0x8E,0x80);		 //打开写保护功能
}

void Ds1302ReadTime()
{
     
	unsigned char n;
	for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
	{
     
		TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
	}
		
}
#ifndef __DS1302_H__
#define __DS1302_H__

	#include "reg52.h"
	#include   //_nop_()函数要用到这个头文件
	sbit DSIO=P3^4;
  sbit RST=P3^5;
  sbit SCLK=P3^6;
	void Ds1302Write(unsigned char addr, unsigned char dat);
	unsigned char Ds1302Read(unsigned char addr);
	void Ds1302Init();
	void Ds1302ReadTime();

#endif

你可能感兴趣的:(单片机)