DS1302時鐘芯片驅動(3線串行通信)

 

/*****************************************************************************
FileName : DS1302.c
Function : DS1302驅動
Author   : mike
Email    : [email protected]	
Version  : V1.0
Date     : 2019-10-21

注意:DS1302寫寄存器是地址是偶數,讀的時候地址+1
比如:往0x80地址寫入0x01,讀取時需要從0x81讀取

DS1302控制字:

bit7  bit6     bit5   bit4    bit3    bit2    bit1     bit0

1    RAM/-CK    A4     A3      A2      A1      A1     RD/-WR

[7]  :控制字的最高有效位(位7)必須是邏輯1,如果它爲 0 則不能把數據寫入DS1302;
[6]  :如果爲0,則表示存取日曆時鐘數據,爲1表示存取RAM數據;
[5:1]:指示操作單元的地址;
[0]  :0表示要進行寫操作,爲1表示進行讀操作;

控制字總是從最低位開始輸出.在控制字指令輸入後的下一個SCLK時鐘的上升沿時數據
被寫入DS1302,數據輸入從最低位(0位)開始.同樣,在緊跟8位的控制字指令後的下一個
SCLK脈衝的下降沿,讀出DS1302的數據,讀出的數據也是從最低位到最高位.

存取日曆時鐘(BCD碼):其中9~31地址不能存儲數據
寫入地址:0x00|0x80~0x3E|0x80   =    0x80~0xBE(取偶數)
讀取地址:0x00|0x81~0x3E|0x81   =    0x81~0xBF(取奇數)

存取RAM:其中31地址不能存儲數據
寫入地址:0x00|0xC0~0x3E|0xC0   =    0xC0~0xFE(取偶數)
讀取地址:0x00|0xC1~0x3E|0xC1   =    0xC1~0xFF(取奇數)

0x80---秒寄存器的BIT7表示時間暫停位,BIT7爲1時停止工作,0時開始工作
0x84---小時寄存器的BIT表示12/24小時制,BIT7爲1表示12時制,爲0表示24時制;
        BIT5爲AM/PM位,BIT5爲1表示PM,0表示AM
0x8E---寫保護<寫入0x00表示允許進行寫操作,0x80表示不允許寫操作>

寫日期時間寄存器:
0x80---秒
0x82---分
0x84---時
0x86---日
0x88---月
0x8A---星期
0x8C---年

讀日期時間寄存器:
0x81---秒
0x83---分
0x85---時
0x87---日
0x89---月
0x8B---星期
0x8D---年
*****************************************************************************/
#include "include.h"
#include "DS1302.h"

type_time t_time;

#if 0
u8 max_day[12]={31,28,31,30,31,30,31,31,30,31,30,31}; //各月的天數
/**********************************************************
檢查是否潤年,返回當前二月最大天數
判斷潤年的完整公式爲A=X4*10+X3,B=4,A/B;A=B*10+X2,B=4,A/B;A=B*10+X1,B=4,A/B
**********************************************************/
u8 chk_max_day(void)
{
    if(t_time.month == 2)
    {
        if(t_time.year % 4) //t_time.year取值00~99
            return (29);  //如果是潤年,返回29天。
        else
            return (28);  //否則爲28天。
    }
    else
    {
        return max_day[t_time.month-1];
    }
}	
#endif

void ds1302_write_byte(u8 dat)//寫一個字節
{
    u8 i;
    DS1302_IO_OUT();
    delay(5);
    for(i = 8;i > 0;i --)
    {
        if(dat & 0x01)
        {
            DS1302_IO_HIGH();
        }
        else
        {
            DS1302_IO_LOW();
        }
        dat >>= 1;
        DS1302_CLK_HIGH();
        delay(5);
        DS1302_CLK_LOW();
        delay(5);
    }
}

u8 ds1302_read_byte(void)//讀一個字節
{
    u8 i = 0;
    u8 dat = 0;	
    DS1302_IO_IN();
    delay(5);
    for(i = 8;i > 0;i --)
    {
        dat >>= 1;
        if(DS1302_IO_IS_HIGH())
        {
            dat |= BIT(7);
        }
        else
        {
            dat &= ~BIT(7);
        }
        DS1302_CLK_HIGH(); //下降沿讀取數據
        delay(5);
        DS1302_CLK_LOW();	
        delay(5);
    }
    return dat;
}

void ds1302_write(u8 adr,u8 dat)//向1302芯片寫函數,指定寫入地址,數據
{
    DS1302_RST_LOW();
    DS1302_CLK_LOW();	
    DS1302_RST_HIGH();
    ds1302_write_byte(adr);
    ds1302_write_byte(dat);
    DS1302_RST_LOW();
    DS1302_CLK_HIGH();
}

u8 ds1302_read(u8 adr)//從1302讀數據函數,指定讀取數據來源地址
{
    u8 temp = 0;

    DS1302_RST_LOW();
    DS1302_CLK_LOW();	
    DS1302_RST_HIGH();
    ds1302_write_byte(adr);
    temp = ds1302_read_byte();
    DS1302_RST_LOW();
    //DS1302_CLK_HIGH();

    return temp;
}

u8 bcd_dec(u8 bcd)//BCD碼轉10進制函數
{
    return ((bcd/16)*10+(bcd%16));	
}

u8 dec_bcd(u8 dec)//10進制轉BCD碼
{
    return ((dec/10)*16+(dec%10));
}

void ds1302_write_time(void)//寫入時間日期
{
    ds1302_write(0x8E,0x00);		//允許寫
    //t_time.wday = week_conversion(t_time.year,t_time.month,t_time.day);
    ds1302_write(0x80,dec_bcd(t_time.second));	//秒
    ds1302_write(0x82,dec_bcd(t_time.minute));	//分
    ds1302_write(0x84,dec_bcd(t_time.hour));    //時
    ds1302_write(0x86,dec_bcd(t_time.day));		//日
    ds1302_write(0x88,dec_bcd(t_time.month));   //月
    //ds1302_write(0x8A,dec_bcd(t_time.wday));    //星期
    ds1302_write(0x8C,dec_bcd(t_time.year));    //年
    ds1302_write(0x8E,0x80);    	//禁止寫
}

void ds1302_read_time(void) //讀取時間數據
{
    t_time.second = bcd_dec(ds1302_read(0x81)&0x7F);	//秒
    t_time.minute = bcd_dec(ds1302_read(0x83));	//分
    t_time.hour = bcd_dec(ds1302_read(0x85)&0x1F);	  	//時
    t_time.day = bcd_dec(ds1302_read(0x87));	  	//日
    t_time.month = bcd_dec(ds1302_read(0x89));		//月	
    //t_time.wday = bcd_dec(ds1302_read(0x8B));		//星期	
    t_time.year = bcd_dec(ds1302_read(0x8D));	  	//年

    t_time.wday = week_conversion(t_time.year,t_time.month,t_time.day);
    //printf("%d : %d : %d\n",t_time.hour,t_time.minute,t_time.second);

    //printf("日期 : 20%d年%d月%d日  星期%d\n",t_time.year,t_time.month,t_time.day,t_time.wday);
    //printf("時間 : %02d : %02d : %02d\n\n",t_time.hour,t_time.minute,t_time.second);
}

void ds1302_conversion_hourly(u8 hourly,u8 ampm) //轉換12/24小時制,AM/PM<此函數未驗證>
{
    ds1302_write(0x8E,0x00);	//允許寫
    if(hourly == HOURLY_12) 	//12小時制
    {
        t_time.hour |= BIT(7);
        if(ampm == HOURLY_PM) 	//PM
            t_time.hour |= BIT(5);
        else if(ampm == HOURLY_AM)
            t_time.hour &= ~BIT(5);
    }
    else if(hourly == HOURLY_24)	//24小時制
    {
        t_time.hour &= ~BIT(7);
    }
    ds1302_write(0x84,dec_bcd(t_time.hour));
    ds1302_write(0x8E,0x80);    	//禁止寫
}

void ds1302_write_ram(void)//寫入RAM的記憶信息
{
    ds1302_write(0x8E,0x00);		//允許寫

/*
    此處記憶鬧鐘數據,地址範圍0xc0,0xc2...~0xe4
    ds1302_write(0xc0,0x08);//鬧鐘一小時位
    ds1302_write(0xc2,0x00);//鬧鐘一分鐘位
    ds1302_write(0xc4,0x08);//鬧鐘二小時位
    ds1302_write(0xc5,0x00);//鬧鐘二分鐘位
*/
    ds1302_write(0x8E,0x80);    	//禁止寫
}
void ds1302_reset(void)//復位---寫入寄存器時間日期和記憶信息
{
    //默認時間日期初始化
    t_time.second = 0;
    t_time.minute = 0;
    t_time.hour = 8;
    t_time.day = 1;
    t_time.month = 10;
    t_time.year = 17;
    t_time.wday = week_conversion(t_time.year,t_time.month,t_time.day);	
    //寫入時間日期
    //ds1302_write_time();
/*********************************************************************
    //寫入RAM的記憶信息
    ds1302_write_ram();
*********************************************************************/
    ds1302_write_time();

    ds1302_write(0x8E,0x00);		//允許寫
    ds1302_write(0xFC,0x99);   		//用於判斷是否曾經初始化過時間
    ds1302_write(0x8E,0x80);    	//禁止寫
}

void ds1302_init(void) //1302芯片初始化
{
    u8 temp = 0;

    DS1302_IO_INIT();

    DS1302_RST_LOW();
    DS1302_CLK_LOW();	

    temp = ds1302_read(0xFD);	//判斷振盪器是否爲開
    if(temp != 0x99) //如果特定寄存器的數據不是默認寫入的值---重寫默認時間	
    {	
        ds1302_reset(); //重新寫入時間
        printf("DS1302 reinit ......\n");	
    }	

/********************************************************************************/
    ds1302_write(0x8E,0x00);	//允許寫
    ds1302_write(0xFA,0x89);   	//寫0x89
    ds1302_write(0x8E,0x80);    //禁止寫
    //delay_ms(10);
    temp = ds1302_read(0xFB);	
    if(temp == 0x89)            //讀取寫進去的值
    {
        printf("DS1302 init successful !\n");	
    }
    else
    {
        printf("DS1302 init error !\n");	
    }	
/********************************************************************************/	
	
    ds1302_read_time();			//讀取時間
    t_time.second &= 0x7F; 		//啓動DS1302時鐘振盪器(0x80寄存器的bit7置0)
    ds1302_write(0x8E,0x00);	//允許寫
/********************************************************/	
    ds1302_write(0x80,dec_bcd(t_time.second));
    ds1302_write(0x90,TCS_OFF|DS_OFF);		//充電被禁止

    //ds1302_conversion_hourly(HOURLY_12,HOURLY_PM);//設置小時制
/********************************************************/	
    //ds1302_write(0x90,TCS_ON|DS_DIODE_TWO|CS_RES_8K);	//啓動充電---2個二極管,8K電阻涓流充電	
    ds1302_write(0x8E,0x80);    //禁止寫
/*
    if(t_time.second > 59)
        t_time.second = 0;
    if(t_time.minute > 59)
        t_time.minute = 0;
    if(t_time.hour > 23)
        t_time.hour = 0;	
    if(t_time.day > 31)
        t_time.day = 1;		
    if(t_time.month > 12)
        t_time.month = 1;
    if(t_time.year > 99)
        t_time.year = 0;	
*/
}

/****************************************************************************
算法:日期+年份+所過閏年數+月較正數之和除7 的餘數就是星期,但如果是在閏年又不到
3月份,上述之和要減一天再除7,星期數爲0

century=0 爲21世紀,century=1 爲20世紀
輸入輸出數據均爲BCD數據
年月日爲16進制數
*****************************************************************************/
u8 week_conversion(u8 year,u8 month,u8 day) //星期轉換
{	
    u16 y = year + 2000;
    //一月和二月被當作前一年的
    if((month==1)||(month==2))
    {
        month+=12;
        y--;
    }
    //u8 week=(day+2*month+3*(month+1)/5+y+y/4-y/100+y/400)%7;
    //printf("new:%d.%d.%d\n",y,month,day);
    return (day+2*month+3*(month+1)/5+y+y/4-y/100+y/400)%7+1;
}

/*****************************************************************************
FileName : ds1302.h
Function : DS1302驅動
Author   : mike
Email    : [email protected]
Version  : V1.0
Date     : 2019-10-21
Note     :

注意:DS1302寫寄存器是地址是偶數,讀的時候地址+1
比如:往0x80地址寫入0x01,讀取時需要從0x81讀取
*****************************************************************************/
#ifndef DS1302_H
#define DS1302_H

#define BIT(n)                          (1 << n)

#define DS1302_IO_INIT()                P2DIR &= ~BIT(0);P3DIR &= ~BIT(7);P0DIR &= ~BIT(6)	//IO初始化
#define DS1302_CLK_HIGH()               P2 |= BIT(0)
#define DS1302_CLK_LOW()                P2 &= ~BIT(0)
#define DS1302_IO_HIGH()                P3 |= BIT(7)
#define DS1302_IO_LOW()                 P3 &= ~BIT(7)
#define DS1302_RST_HIGH()               P0 |= BIT(6)
#define DS1302_RST_LOW()                P0 &= ~BIT(6)

#define DS1302_IO_IN()                  P3DIR |= BIT(7);P3PU0 |= BIT(7)
#define DS1302_IO_OUT()                 P3DIR &= ~BIT(7);P3PU0 &= ~BIT(7)
#define DS1302_IO_IS_HIGH()             (P3 & BIT(7))

#define SEC_ADR                         0x80
#define MIN_ADR                         0x82
#define HOU_ADR                         0x84
#define DAY_ADR                         0x86
#define MON_ADR                         0x88
#define YEA_ADR                         0x8C

#define WRITE_SW_ADR                    0x8E //寫保護地址

#define CHARGE_ADR                      0x90 //充電寫地址<讀爲0x91>
#define TCS_ON                          0xA0
#define TCS_OFF                         0x00
#define DS_DIODE_ONE                    0x04 //VCC2和VCC1之間1個二極管充電
#define DS_DIODE_TWO                    0x08 //VCC2和VCC1之間2個二極管充電
#define DS_OFF                          0x00 //充電被禁止
#define CS_RES_NO                       0x01 //無電阻
#define CS_RES_2K                       0x01 //2K電阻
#define CS_RES_4K                       0x02 //4K電阻
#define CS_RES_8K                       0x03 //8K電阻


#define HOURLY_24                       0x00
#define HOURLY_12                       0x01

#define HOURLY_PM                       0x00
#define HOURLY_AM                       0x01

typedef struct {
    u8 year;     //取值00~99
    u8 month;
    u8 day;
    u8 hour;
    u8 minute;
    u8 second;
    u8 wday;
} type_time;
extern type_time t_time;

u8 bcd_dec(u8 bcd);
u8 dec_bcd(u8 dec);
void ds1302_write(u8 adr,u8 dat);
u8 ds1302_read(u8 adr);
void ds1302_init(void);
void ds1302_write_time(void);
void ds1302_read_time(void);
u8 week_conversion(u8 year,u8 month,u8 day);

#endif







 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章