RYMCU

Nebula Pi 开发板评测报告(十三)——实时时钟(RTC)DS1302功能测试

ii11nnocent 3 月前
# DS1302 # 实时时钟 # Nebula Pi # 评测报告

RTC(Real Time Clock)是实时时钟的简称,可以为我们提供精确的实时时间,其中具有代表性的就是 DS1302 数字时钟芯片,通过单片机与 DS1302 的通信就可以读取 DS1302 中存储的时间信息。利用下面的程序可以实现在 LCD1602 上显示当前的时间(Brust 模式):

ds1302.h:

#ifndef _DS1302_H
#define _DS1302_H

#include "reg52.h"

extern unsigned char *week;

void WriteByte_1302(unsigned char dat);
unsigned char ReadByte_1302(void);
void Write_1302( unsigned char addr , unsigned char dat );
unsigned char Read_1302( unsigned char addr );
void DS1302_Init( unsigned char *InitTime );
void GetCurrentTime( unsigned char *CurrentTime );
void BurstWrite_1302( unsigned char *Time );
void BrustRead_1302( unsigned char *CurrentTime );
void WeekTransform( unsigned char w );

#endif

ds1302.c:

#include "ds1302.h"

sbit CE 	= P0^5;			//位定义DS1302CE、I/O和SCLK引脚
sbit IO 	= P0^4;
sbit SCLK = P0^3;
unsigned char *week;

//向DS1302写入一个字节的函数
void WriteByte_1302(unsigned char dat)
{
	unsigned char i;
	bit flag;

	for(i=0;i<8;i++)
	{
		//写入数据时候从低位到高位
		flag = dat & 0x01;		//待传送的数据的低位存入flag等待传输
		
		IO = flag;
		SCLK = 0;
		SCLK = 1;		//在SCLK上产生一个上升沿,完成一位数据写入
		
		dat = dat >>1;		//将dat右移一位,继续写入
	}
}

//从DS1302读出一个字节的函数,返回值为一个字节的数据
unsigned char ReadByte_1302(void)
{
	unsigned char i,flag,dat;
	
	for(i=0;i<8;i++)
	{
		SCLK = 1;
		SCLK = 0;		//在SCLK上产生一个下降沿,完成一位数据的读出
		
		flag = IO;	//将读出的一位数据放入flag中
		
		dat = ( dat >>1 ) | ( flag <<7 );			//循环8次,每次都将读出的数据放入最高位
	}
	return dat;		//将读出的数据返回
}

//向固定地址写入单字节数据的函数
void Write_1302( unsigned char addr , unsigned char dat )
{
	CE = 1;		//拉高CE引脚
	WriteByte_1302( addr );		//写入地址数据
	WriteByte_1302( dat );		//写入数据
	CE = 0;		//拉低CE引脚
	SCLK = 0;	//拉低SCLK,为下一次传输做准备
}

//从固定地址读出数据
unsigned char Read_1302( unsigned char addr )
{
	unsigned char dat;
	
	CE = 1;		//拉高CE引脚
	WriteByte_1302( addr );		//写入地址数据
	dat = ReadByte_1302();		//将读出的数据存放到dat中
	CE = 0;		//拉低CE引脚

	return dat;
}

//DS1302初始化,写入初始化时间
void DS1302_Init( unsigned char *InitTime )
{
//	unsigned char i;
	
	CE = 0;		//拉低CE引脚
	SCLK = 0;	//拉低SCLK引脚
	Write_1302( 0x8E , 0x00 );	//向0x8E寄存器写入0,解除写保护
	
	/****
	for( i=0;i<7;i++ )
	{
		Write_1302( 0x80 + 2*i , InitTime[i] );	//依次写入秒、分、时、日、月、星期、年的数据
	}
	****/
	BurstWrite_1302( InitTime );
}

//获取当前时间
void GetCurrentTime( unsigned char *CurrentTime )
{
	//unsigned char i;
	
	CE = 0;		//拉低CE引脚
	SCLK = 0;	//拉低SCLK引脚
	
	/****
	for( i=0;i<7;i++ )
	{
		*CurrentTime = Read_1302( 0x81 + 2*i );	//依次读取秒、分、时、日、月、星期、年的数据
		CurrentTime ++;		//地址+1,存储数据
	}
	****/
	BrustRead_1302( CurrentTime );
}

/****下面是突发模式下的读写函数****/

//突发写数据函数
void BurstWrite_1302( unsigned char *Time )
{
	unsigned char i;
	
	CE = 1;		//拉高CE引脚
	WriteByte_1302(0xBE);		//突发模式专用写指令
	for( i=0;i<7;i++ )
	{
		WriteByte_1302(Time[i]);	//向1302写入时间数据
	}
	WriteByte_1302(0);					//向第八个寄存器写入0,防止出错
	CE = 0;		//拉低CE引脚
}

//突发读数据函数
void BrustRead_1302( unsigned char *CurrentTime )
{
	unsigned char i;
	
	CE = 1;		//拉高CE引脚
	WriteByte_1302(0xBF);		//突发模式专用写指令
	for( i=0;i<7;i++ )
	{
		*CurrentTime = ReadByte_1302();	//读取一个字节的数据
		CurrentTime ++;								//地址+1
	}
	CE = 0;		//拉低CE引脚
}

void WeekTransform( unsigned char w )
{
	switch( w )
	{
		case 1:week = "Mon";break;
		case 2:week = "Tue";break;
		case 3:week = "Wed";break;
		case 4:week = "Thu";break;
		case 5:week = "Fri";break;
		case 6:week = "Sat";break;
		case 7:week = "Sun";break;
		default: week = "error";break;
	}
}

main.c:

#include "reg52.h"  
#include "intrins.h"  
#include "stdio.h"  
#include "LCD1602.h"  
#include "ds1302.h"  
  
bit flag;       //定时500ms标志位  
  
//定义初始时间,秒、分、时、日、月、星期、年  
unsigned char code InitTime[7] = { 0x55,0x15,0x08,0x21,0x05,0x04,0x21 };      
  
//存储获取时间的数组  
unsigned char CurrentTime[7];  
  
//显示字符存储变量  
unsigned char DisplayString[20];    
  
void Timer0_Init(void)  
{  
    TMOD |= 0x01;       //配置定时器工作模式  
    TH0 = 0x4C;  
    TL0 = 0x00;         //定时50ms初值    
    TR0 = 1;  
    ET0 = 1;  
    EA = 1;                 //启动定时器,开定时器中断和总中断  
}   
  
  
void main()  
{  
    LCD_Init();             //初始化LCD1602  
    Timer0_Init();      //初始化定时器  
    DS1302_Init(InitTime);  //初始化时钟  
      
    while(1)  
    {         
        if( flag )      //flag=1时,即500ms定时时间到时  
        {  
            flag = 0;       //标志位清零  
            GetCurrentTime(CurrentTime);    //获取当前时间  
              
            DisplayString[0] = '2';DisplayString[1] = '0';  
              
            //取出年的十位、个位,然后转换成对应数字的ASCII码  
            DisplayString[2] = (CurrentTime[6]>>4)+'0';       DisplayString[3] = (CurrentTime[6]&0x0F)+'0';                 
            DisplayString[4] = '-';  
              
            //取出月的十位、个位,然后转换成对应数字的ASCII码  
            DisplayString[5] = (CurrentTime[4]>>4)+'0';       DisplayString[6] = (CurrentTime[4]&0x0F)+'0';         
            DisplayString[7] = '-';  
              
            //取出日的十位、个位,然后转换成对应数字的ASCII码  
            DisplayString[8] = (CurrentTime[3]>>4)+'0';       DisplayString[9] = (CurrentTime[3]&0x0F)+'0';         
            DisplayString[10] = '\0';       //结束  
              
            //取出时的十位、个位,然后转换成对应数字的ASCII码  
            DisplayString[11] = (CurrentTime[2]>>4)+'0';      DisplayString[12] = (CurrentTime[2]&0x0F)+'0';        
            DisplayString[13] = ':';  
              
            //取出分的十位、个位,然后转换成对应数字的ASCII码  
            DisplayString[14] = (CurrentTime[1]>>4)+'0';      DisplayString[15] = (CurrentTime[1]&0x0F)+'0';        
            DisplayString[16] = ':';  
              
            //取出秒的十位、个位,然后转换成对应数字的ASCII码  
            DisplayString[17] = (CurrentTime[0]>>4)+'0';      DisplayString[18] = (CurrentTime[0]&0x0F)+'0';        
            DisplayString[19] = '\0';       //结束  
						
						WeekTransform( ( (CurrentTime[5]&0x0F) ) );	//将星期转换成对应的英文
              
            LCD_WriteString(1,2,DisplayString);  
            LCD_WriteString(2,2,DisplayString+11);        						
	    LCD_WriteString(2,12,week);            //分两行显示
        }         
    }  
}  
  
void Timer0(void) interrupt 1 using 1  
{  
    static unsigned int i;    
    TH0 = 0x4C;  
    TL0 = 0x00;         //重新赋初值  
    i++;  
    if( i == 10 )       //10次50ms就到了500ms  
    {  
        i=0;  
        flag = 1;           //500ms定时到,标志位置1,由main函数置0  
    }  
  
}

DS1302.mp4

后发布评论