SPI接口DS1302時鍾芯片操作


  今天,又花了差不多一天時間,從手冊看起,到寫完代碼,最后仿真。期間出現了一個細小的差錯,折騰了約1個鍾頭才解決掉(所以,最怕底層細小之處出現錯誤)。

DS1302是達拉斯公司出品的一款實時時鍾芯片。具體且詳細的資料介紹在其芯片手冊上面都有寫着。說起來自己讀DS1302芯片手冊,也花了不少精力,主要是對一個問題一直沒理解。

下圖是DS1302時鍾寄存器的結構。(注意左邊READ與WRITE兩列)

                       

下圖是DS1302的命令字節(就是跟它通信的格式)

 

  其中A4到A0可以代表寄存器的地址。我想,5bit表示的地址,翻遍了手冊,在上面也沒有說明5bit的地址是怎么表示的(手冊上只有讀寫地址,8bit)。就這樣,我納悶了,就去問問搜索引擎。網上掛出來最多的盡是些代碼(說實話,驅動代碼不難寫,難的是對芯片的理解),最終還是找到了一篇博文(寫了對DS1302的理解),而且我才煥然大悟,原來READ與WRITE兩列是什么的。

  舉個例子:寫秒寄存器的地址是0x80,展開成8bit的就是1000,0000(結合命令字節看看),你會發現其實就是命令字節。

  現在來說說DS1302的SPI接口(其實比標准的SPI接口少了一根線),它包含RST線、SCLK線、IO線(雙向傳送數據用,標准的SPI則將其分成兩根MISO與MOSI)3條接線。

 

  上面這張圖片就是其時序圖,單字節讀取和單字節寫。相比1條線的單總線、2條線的IIC,這個SPI貌似是最簡單的。每次傳送時,需要先發送8bit命令字節,再發送/接收8bit數據。

  再細小的看,CE(也就是RST)先拉至高電平,在IO線上事先要准備好數據,然后將SCLK拉高,一個上升沿,發完了1bit。如此往復,發完接下來的幾位。如果是發送數據的話,注意每次都是上升沿發送1bit。如果是接收數據的話,注意,在傳完最后命令字節的1(高電平)之后的第一個下降沿后DS1302發送數據。當然DS1302能夠每次傳送多個字節。

  說完了通信機制,通信內容,基本上差不多了。值得提醒的是,DS1302內部有31字節RAM,可以用來保存數據。

 

  今天寫的有點少。下面貼上調好的代碼:

 

頭文件部分:

#ifndef __hal_ds1302_h__
#define __hal_ds1302_h__

#include<reg52.h>
#include"datatype.h"
#include"delay.h"
#include"hal.h"

sbit rst=P3^2;
sbit sclk=P3^3;
sbit sda_ds1302=P1^7;

#define RST rst
#define SCLK sclk
#define SIO sda_ds1302

#define WRITE_SECONDS    0x80//
#define READ_SECONDS    0x81
#define WRITE_MINUTES    0x82//
#define READ_MINUTES    0x83
#define WRITE_HOUR        0x84//
#define READ_HOUR        0x85
#define WRITE_DATE        0x86//
#define READ_DATE        0x87
#define WRITE_MONTH        0x88//
#define READ_MONTH        0x89
#define WRITE_DAY        0x8a//星期
#define READ_DAY        0x8b
#define WRITE_YEAR        0x8c//
#define READ_YEAR        0x8d
#define WRITE_WP        0x8e//寫保護bit7為高時,不允許寫
#define READ_WP            0x8f//所以寫之前需將其設為0


//ds1302時間結構體類型
struct ds1302_time
{
    //秒0-59
    uchar seconds;
    //分0-59
    uchar minutes;
    //時0-23(24小時模式)
    //如果需要12小時模式,跟寄存器格式需要一致
    uchar hour;
    //星期1-7
    enum{Sunday=1,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday} day;
    //日1-31
    uchar date;
    //月1-12
    uchar month;
    //年0-99
    uchar year;
};

//參數1:寫保護;參數0:取消寫保護
#define HAL_DS1302_WRITE_PROTECT(wp) hal_ds1302_single_byte_write(WRITE_WP,wp?0x80:0x00)

void hal_ds1302_init();
void hal_ds1302_single_byte_write(uchar comm,uchar val);
uchar hal_ds1302_single_byte_read(uchar comm);

void hal_ds1302_init_time(struct ds1302_time time);
void hal_ds1302_get_time(struct ds1302_time * time);

#endif

 

C文件部分:

 

  1 #include"hal_ds1302.h"
  2 
  3 void hal_ds1302_init()
  4 {
  5     RST=0;
  6     SCLK=0;
  7     SIO=1;
  8 }
  9 
 10 //實質上傳送了16bit
 11 void hal_ds1302_single_byte_write(uchar comm,uchar val)
 12 {
 13     //RST低電平    SCLK低電平
 14     uchar i;
 15     RST=1;
 16     for(i=0;i<8;i++)//從低位開始傳送
 17     {
 18         if(comm&(0x01<<i))
 19             SIO=1;
 20         else
 21             SIO=0;
 22         SCLK=1;//SCLK一個上升沿,讀取了SDA上的電平
 23         //單片機時鍾周期1us情況下,幾乎不用考慮延時
 24         SCLK=0;
 25     }
 26     for(i=0;i<8;i++)
 27     {
 28         if(val&(0x01<<i))
 29             SIO=1;
 30         else
 31             SIO=0;
 32         SCLK=1;//上升沿讀取
 33         SCLK=0;
 34     }
 35     RST=0;
 36     //RST低電平    SCLK低電平    SDA電平未知
 37 }
 38 
 39 //實質上傳送了16bit
 40 uchar hal_ds1302_single_byte_read(uchar comm)
 41 {
 42      //RST低電平  SCLK低電平
 43      uchar i,tmp=0;  
 44      RST=1;
 45      for(i=0;i<8;i++)
 46      {
 47          SCLK=0;//放在這兒是為了第8次SCLK依舊是高電平
 48          if(comm&(0x01<<i))
 49             SIO=1;
 50         else
 51             SIO=0;
 52         SCLK=1;//上升沿,DS1302讀取值    
 53      }
 54      //現在SCLK依舊是高電平
 55      //而且達拉斯考慮到了總線釋放問題,所以傳送的最后一位都為1
 56      for(i=0;i<8;i++)
 57      {
 58          SCLK=1;//放在此處是為了i=7時候,SCLK仍為低電平
 59          SCLK=0;//下降沿,DS1302輸出數據
 60         if(SIO)
 61             tmp=tmp|(0x01<<i);    
 62      }    
 63      RST=0;
 64      return tmp;
 65      //RST低電平  SCLK低電平  SDA電平狀態未知
 66 }
 67 
 68 //參數char類型16進制
 69 //傳出2個4位BCD碼組成的8bit數據
 70 uchar hal_ds1302_uchar2BCD(uchar val)
 71 {
 72     uchar shi=0,ge=0;
 73     shi=val/10%10;
 74     ge=val%10;
 75     return (shi<<4)|ge;
 76 }
 77 
 78 uchar hal_ds1302_BCD2uchar(uchar val)
 79 {
 80     uchar shi=0,ge=0;
 81     shi=val>>4;
 82     ge=val&0x0f;//小心,就是這兒0x0f寫錯了,不是0xf0
 83     return shi*10+ge;
 84 }
 85 
 86 //1.設置寫保護位為0
 87 //2.設置秒字節,同時將bit7置1(暫停計時)
 88 //3.設置年、月、日、星期、時、分
 89 //4設置秒字節,晶振起震
 90 //5.設置寫保護字節bit7為1
 91 //6.之后可以讀取時間了
 92 void hal_ds1302_init_time(struct ds1302_time time)
 93 {
 94     HAL_DS1302_WRITE_PROTECT(0);
 95     delay_ms(1);
 96     hal_ds1302_single_byte_write(WRITE_SECONDS,0x80);
 97     delay_ms(1);
 98     hal_ds1302_single_byte_write(WRITE_YEAR,hal_ds1302_uchar2BCD(time.year));
 99     delay_ms(1);
100     hal_ds1302_single_byte_write(WRITE_MONTH,hal_ds1302_uchar2BCD(time.month));
101     delay_ms(1);
102     hal_ds1302_single_byte_write(WRITE_DATE,hal_ds1302_uchar2BCD(time.date));
103     delay_ms(1);
104     hal_ds1302_single_byte_write(WRITE_DAY,hal_ds1302_uchar2BCD(time.day));
105     delay_ms(1);
106     hal_ds1302_single_byte_write(WRITE_HOUR,hal_ds1302_uchar2BCD(time.hour));
107     delay_ms(1);
108     hal_ds1302_single_byte_write(WRITE_MINUTES,hal_ds1302_uchar2BCD(time.minutes));
109     delay_ms(1);
110       hal_ds1302_single_byte_write(WRITE_SECONDS,hal_ds1302_uchar2BCD(time.seconds));
111     delay_ms(1);
112     HAL_DS1302_WRITE_PROTECT(1);
113 }
114 
115 //注意對12小時模式沒有進行編寫,如有需要,需要額外修改
116 void hal_ds1302_get_time(struct ds1302_time * time)
117 {
118     time->year=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_YEAR));
119     delay_ms(1);
120     time->month=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_MONTH));
121     delay_ms(1);
122     time->date=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_DATE));
123     delay_ms(1);
124     time->day=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_DAY));
125     delay_ms(1);
126     time->hour=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_HOUR));
127     delay_ms(1);
128     time->minutes=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_MINUTES));
129     delay_ms(1);
130     time->seconds= hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_SECONDS));    
131 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM