DS1337 時鐘芯片在 C8051F 上的實現

 1、DS1337介紹編程

  DS1337串行實時時鐘芯片是一種低功耗、所有采用BCD碼的時鐘日曆芯片,它帶有兩個可編程的定時鬧鐘和一個可編程的方波輸出。其地址和數據可經過I2C總線串行傳輸,能提供秒、分、時、日、星期、月和年等信息。eclipse

 1.1 DS1337的引腳說明ide

  DS1337的引腳排列示意圖如圖1所示。各引腳的功能以下:函數

        

        圖1 DS1337引腳示意圖spa

  • VCC,GND:直流電源和接地端,VCC的輸入範圍在1.8~5.5V之間。X1,X2:標準的32.768kHz的石英晶振接入端,內部晶振電路設計要求晶振特定電容負載爲6pF。另外,這兩個引腳還能夠有其它接法,即:X1腳鏈接外部振盪信號源,而將X2腳懸空。
  • SCL:串行時鐘輸入,用來在總線上同步數據傳輸。
  • SDA:串行數據輸入輸出,SDA是I2C總線接口的數據輸入輸出引腳,開漏輸出,使用時要求接一個上拉電阻。
  • SQW/INTB:方波/中斷輸出,可經過對DS1337的內部控制寄存器進行編程來控制這個引腳是輸出方波仍是輸出中斷信號。該引腳是開漏輸出,使用時要接一個外部的上拉電阻。
  • INTA:中斷輸出端,使能時,若是鬧鐘寄存器的設定值與當前時間匹配,該腳會輸出一個低電平。該引腳也是開漏輸出,要接上拉電阻。

1.2 時間寄存器設計

  經常使用的時間寄存器地址爲00H~06H。設置和初始化時間和日曆可經過寫相應的寄存器字段來實現,寄存器的數據格式以BCD碼錶示。DS1337既能夠工做在12小時模式下,也能夠工做在24小時模式下。小時寄存器的位6被定義爲12小時模式或24小時模式選擇位,該位爲1時,選擇12小時模式。在12小時模式時,位5是AM/PM標誌位,該位爲1時表示PM。當在24小時模式時,位5是第二個十位(表示20到23小時)。月寄存器的第7位是世紀位,當年寄存器從0到99溢出時,該位發生變化。3d

1.3 控制寄存器和狀態寄存器code

  DS1337中有一個控制寄存器和一個狀態寄存器,可用於控制實時時鐘、鬧鐘和方波的輸出。blog

  控制寄存器地址爲0EH。其中:接口

  • EOSC:振盪器使能位。該位爲0,振盪器起振;爲1,振盪器停振。剛上電時,該位爲0;RS1,RS2:方波輸出頻率選擇位。RS1和RS2共有四種組合,分別對應的方波輸出頻率爲1Hz,4.096kHz,8.192kHz,32.768kHz。在剛加電時,方波輸出頻率設置是32.768kHz。
  • INTCN:中斷控制位。用於控制兩個鬧鐘與中斷輸出腳之間的關係。爲1時,兩個鬧鐘在知足定時條件時,各自有獨立的中斷輸出。爲0時,兩個鬧鐘共用一箇中斷輸出腳INTA,而腳SQW/INTB爲方波輸出端。開始上電時,該位爲0
  • A1IE:鬧鐘1中斷使能位。爲1時,容許狀態寄存器的A1F位輸出到腳INTA。上電時該位爲0,此時不能用A1F位初始化INTA信號。
  • A2IE:鬧鐘2中斷使能位,該位的做用與A1IE位相同。

  DS1337的狀態寄存器地址爲0FH, 各位的做用以下:

  • OSF:振盪器中止標誌。該位爲1,表示振盪器已中止。有四種狀況能產生這樣的結果:一是芯片剛上電,二是Vcc引腳電壓不足,三是EOSC位爲1,四是晶振受到外部影響(如噪聲等)。
  • A1F、A2F:鬧鐘標誌位。爲1時,表示鬧鐘設定時間與當前時間匹配,併產生中斷輸出。

 

圖2 DS1337寄存器

 1.4 對DS1337的讀與寫

圖3 DS1337 寫寄存器

  從上圖中,能夠看出,主器件發起開始條件,發送從器件的地址和寫命令(0xD0|0x00),等待從器件的應答,而後再發送要寫的寄存器地址,等待從器件的應答,而後再發送要寫的數據,等待從器件的應答,若是寫操做完成,主器件發送結束。完成一次寫數據過程。

圖4 DS1337 讀寄存器

  從上圖中,能夠看出,主器件發起開始條件,發送從器件的地址和寫命令(0xD0|0x00),等待從器件的應答,而後再發送要讀的寄存器地址,等待從器件的應答,而後主器件再從新發送開始條件,發送從器件的地址和讀命令(0xD0|0x01),等待從器件的應答,接收從器件發來的數據,主器件應答。當收到最後一個數據後,主器件發送非應答和結束。完成一次讀數據過程。


 2、SMBus總線介紹

  SMBus串行I/O接口是一個雙線的雙向串行總線,與I2C串行總線兼容。圖 5給出了一個典型的SMBus 配置。SMBus 接口的工做電壓能夠在3.0V和5.0V 之間,總線上不一樣器件的工做電壓能夠不一樣。SCL(串行時鐘)和 SDA(串行數據)線是雙向的。 必須經過上拉電阻或相似電路將它們連到電源電壓。當總線空閒時,這兩條線都被拉到高電平。鏈接在總線上的每一個器件的 SCL 和 SDA 都必須是漏極開路或集電極開路的。

圖5 SMBus 配置

  2.1握手

  SMBus採用多種線路條件做爲器件間的握手信號。在一次數據傳輸中,SDA只能在SCL爲低時改變電平。在SCL爲高電平時SDA發生改變則是表明以下的開始和中止信號:

 

  • 開始:該條件啓動一次傳輸過程。當SCL爲高電平時SDA上出現一個降低沿。
  • 結束:該條件結束一次傳輸過程。當SCL爲高電平時SDA上出現一個上升沿。
  • 應答:也稱爲ACK,接收器件發送該信號表示確認。例如,在器件X收到一個字節後,它將發送一個ACK確認傳輸成功。ACK條件是在SCL爲高時採樣到SDA爲低電平。
  • 非應答:也稱爲NACK,這是在SCL爲高電平時採樣到SDA爲高電平。當接收器件不能產生ACK時,發送器件看到的是NACK。在典型的數據傳輸中,收到NACK信號表示所尋址的從器件沒有準備好或不在總線上。一個處於接收狀態的主器件發送NACK表示這是傳輸的最後一個字節。圖2給出了握手信號時序。

圖6 SMBus 時序

  2.2 傳輸方式

  有兩種可能的傳輸方式:寫(從主器件到從器件)和讀(從從器件到主器件)。在一次傳輸中,任何一個器件均可以是四種角色之一。這四種角色將在下面說明。注意,從地址+R/W’是指一個8位傳輸(7位地址,1位R/W)。

  1)主發送器:在該方式下,器件在SDA上發送串行數據,在SCL上輸出時鐘。器件用一個起始條件啓動傳輸過程,發送從地址+W,而後等待從器件的ACK。收到ACK後,器件發送一個或多個字節數據,每一個字節都要由從器件確認。在發送完最後一個字節後,器件發送一箇中止條件。

  2)主接收器:在該方式下,器件在SDA上接收串行數據,在SCL上輸出時鐘。器件用一個起始條件啓動傳輸過程,以後發送從地址+R。在收到從器件對地址的ACK後,在SCL上輸出時鐘並在SDA上接收數據。在接收完最後一個字節後,器件將發送一個NACK和一箇中止條件。

  3)從發送器:在該方式下,器件在SDA上輸出串行數據,在SCL上接受時鐘。器件接收一個起始條件和它本身的從地址+R,而後發出ACK並進入從發送方式。器件在SDA上發送數據,在發送完每一個字節後都要收到一個ACK。在傳輸完最後一個字節後,主器件發送一個NACK和一箇中止條件。

  4)從接收器:在該方式下,器件收到來自主器件的起始條件和和它本身的從地址+W。而後發出ACK並進入從接收方式。如今器件在SDA上接收串行數據,在SCL上接收時鐘。在接收完每一個字節後都要發送一個ACK,在接收到主器件的中止條件後退出從接收方式。

  圖7爲典型的寫操做狀況。圖8爲典型的讀操做狀況。

圖7 寫操做

  (1)爲一個成功的傳送過程。在(3)中,主器件在收到一個ACK後從新發出起始條件。這一過程容許主器件在不放棄總線的狀況下啓動一個新的傳輸過程(例如,從寫操做切換到讀操做)。重複起始條件一般在訪問EEPROM時使用,由於一個讀操做前面必須有一個寫存儲器地址的操做。

圖8 讀操做

  2.3  SMBus特殊功能寄存器

  對 SMBus 串行接口的訪問和控制是經過 5 個特殊功能寄存器來實現的:控制寄存器 SMB0CN、時鐘速率寄存器 SMB0CR、地址寄存器 SMB0ADR、數據寄存器 SMB0DAT 和狀態寄存器 SMB0STA。系統器件能夠有一個或多個 SMBus 串行接口。

  2.3.1 控制寄存器SMB0CN

  SMBus 控制寄存器 SMB0CN 用於配置和控制 SMBus 接口。該寄存器中的全部位均可以 用軟件讀寫。有兩個控制位還受 SMBus 硬件的影響。當發生一個有效的串行中斷條件時,串 行中斷標誌(SI,SMB0CN.3)被硬件設置爲邏輯 1,該標誌只能用軟件清 0。當總線上出現 一箇中止條件時,中止標誌(STO,SMB0CN.4)被硬件清 0。

 

  2.3.2 時鐘速率寄存器SMB0CR

  在器件工做於主方式時SMBus時鐘寄存器用於控制SCL時鐘速率。SMB0CR中的8位數決定了時鐘速率,公式以下:

                  

  其中,SMB0CR是一個負數的補碼。所以,對於100kHz的SCL頻率和16MHz的SYSCLK,應向SMB0CL裝入-80,即0xB0。

  2.3.3 地址寄存器 SMB0ADR

  SMBus地址寄存器保存器件在從方式時將要應答的從地址。位(7:1)保存從地址;位0是通用呼叫容許。若是位0被置位,器件將應答通用呼叫地址(0x00)。

  2.3.4 數據寄存器 SMB0DAT

  SMBus數據寄存器用於保存將要發送或剛剛接收的數據。只有在SI=1時,從該寄存器讀出的數據纔是有效的。當SI不爲1時,SMBus可能處在向SMB0DAT移入數據或從SMB0DAT移出數據的過程當中。注意:在傳輸過程當中,從SMB0DAT移出的最高位又移回到最低位,所以在一次傳輸完成後SMB0DAT中仍然保存着原始數據。

  1.3.5 狀態寄存器 SMB0STA

  共有28個可能的SMBus狀態,每一個狀態對應一個惟一的狀態碼。狀態碼的高5位是可變的,而一個有效狀態碼的低3位固定爲0(當SI=1時)。所以全部有效的狀態碼都是8的整數倍。


 3、在C8051F 上的實現

3.1 硬件

3.2 軟件

 1 typedef struct
 2 { 
 3     u8 second;        // 0 to 59 
 4     u8 minute;        // 0 to 59 
 5   u8 hour;          // 0 to 23  (24-hour time) 
 6   u8 day;            // 0 = Sunday, 1 = Monday, etc. 
 7     u8 date;           // 1 to 31 
 8   u8 month;          // 1 to 12 
 9   u8 year;           // 00 to 99 
10 } DS1337_time; 
11 
12 xdata DS1337_time Time; 
13  
14 bit SMB_BUSY;
15 u8 COMMAND;
16 u8 Mode;
17 u8 wr_data[2];  
18 u8 wrnumber;   
19 u8 get_data;
20  
21 
22 void DS1337_Set_time(DS1337_time dt);
23 
24 
25 char bcd2bin(char bcd_value)
26 { 
27   char temp; 
28   temp = bcd_value; 
29   temp >>= 1; 
30   temp &= 0x78; 
31   return(temp + (temp >> 2) + (bcd_value & 0x0f)); 
32 } 
33 
34 
35 unsigned char bin2bcd(unsigned char value) 
36 { 
37   char retval; 
38   retval = 0; 
39 
40   while(1) 
41     { 
42         if(value >= 10) 
43         { 
44          value -= 10; 
45          retval += 0x10; 
46         } 
47         else 
48         { 
49          retval += value; 
50          break; 
51         } 
52     } 
53   return(retval); 
View Code

  第25行的函數是將BCD碼轉化爲二進制數。第35行的函數是將二進制數轉化爲BCD碼。

 1 void init_iic(void) 
 2 {
 3     SMB0CN = 0x44;            // Enable SMBus with acknowledge low (AA = 1)
 4     SMB0CR = 146;             // SMBus clock rate = 100 kHz   146
 5     EIE1 |= 2;                // SMBus interrupt enable
 6     SI = 0;                           
 7     SMB_BUSY = 1;
 8 }
 9 
10 
11 void Write_DS1337(u8 adrress, u8 data1) 
12 { 
13     Mode = 1;
14   wrnumber = 2 ;
15     wr_data[0] = adrress;
16     wr_data[1] = data1;
17     SMB0CN = 0x44;
18     COMMAND = DS1337_ADDR;
19     STO = 0;
20     STA = 1;
21     SMB_BUSY = 1;
22     while(SMB_BUSY);
23 }
24 
25 
26 int Read_DS1337(u8 adrress) 
27 {
28   Mode=0;    
29     SMB0CN = 0x44;
30     COMMAND = (DS1337_ADDR | 0x01);
31     wr_data[0] = adrress;
32     STO = 0;
33     STA = 1;
34     SMB_BUSY = 1;
35     while(SMB_BUSY);
36     return get_data;
37 }
View Code

   第1行的函數初始化SMBus總線。第11行的函數爲DS1337寫操做。第26行的函數爲DS1337讀操做。

 1 void DS1337_init()
 2 {
 3     u8 status;
 4     DS1337_time DT;
 5     
 6     DT.second = 30;
 7      DT.minute = 50;
 8     DT.hour =     21;
 9     DT.day =     2;
10     DT.date =     12;
11     DT.month =     8;
12     DT.year =     14;
13     
14     status = Read_DS1337(DS1337_STATUS_REG);
15     if((status & 0x80) != 0)
16     {
17         DS1337_Set_time(DT);
18         Write_DS1337(DS1337_CONTROL_REG,DS1337_CTRL_REG_INIT_VAL);
19         Write_DS1337(DS1337_STATUS_REG,DS1337_CLEAR_STATUS_VAL);
20     }
21 }
22 
23 void DS1337_Set_time(DS1337_time dt)
24 {
25     u8 bcd_sec,bcd_min,bcd_hrs,bcd_day,bcd_date,bcd_mon,bcd_year; 
26 
27     bcd_sec  = bin2bcd(dt.second); 
28   bcd_min  = bin2bcd(dt.minute); 
29   bcd_hrs  = bin2bcd(dt.hour);   
30   bcd_day  = bin2bcd(dt.day); 
31   bcd_date = bin2bcd(dt.date); 
32   bcd_mon  = bin2bcd(dt.month);    
33   bcd_year = bin2bcd(dt.year); 
34         
35     Write_DS1337(DS1337_SECONDS_REG,bcd_sec);
36     Write_DS1337(DS1337_MINUTES_REG,bcd_min);
37     Write_DS1337(DS1337_HOURS_REG,bcd_hrs);
38     Write_DS1337(DS1337_DAY_OF_WEEK_REG,bcd_day);
39     Write_DS1337(DS1337_DATE_REG,bcd_date);
40     Write_DS1337(DS1337_MONTH_REG,bcd_mon);
41     Write_DS1337(DS1337_YEAR_REG,bcd_year);
42 }
43 
44 void DS1337_Get_time() 
45 {
46     u8 bcd_sec,bcd_min,bcd_hrs,bcd_day,bcd_date,bcd_mon,bcd_year; 
47     
48     bcd_sec = Read_DS1337(DS1337_SECONDS_REG);
49     bcd_min = Read_DS1337(DS1337_MINUTES_REG);
50     bcd_hrs = Read_DS1337(DS1337_HOURS_REG);
51     bcd_day = Read_DS1337(DS1337_DAY_OF_WEEK_REG);
52     bcd_date = Read_DS1337(DS1337_DATE_REG);
53     bcd_mon = Read_DS1337(DS1337_MONTH_REG);
54     bcd_year = Read_DS1337(DS1337_YEAR_REG);
55     
56     Time.second = bcd2bin(bcd_sec);
57     Time.minute = bcd2bin(bcd_min);
58     Time.hour =     bcd2bin(bcd_hrs);
59     Time.day =         bcd2bin(bcd_day);
60     Time.date =     bcd2bin(bcd_date);
61     Time.month =     bcd2bin(bcd_mon);
62     Time.year =     bcd2bin(bcd_year);
63 }
View Code

   第1行的函數爲初始化DS1337,讀取狀態寄存器,若是最高位不爲0,則初始化時間。第23行的函數爲設置時間,包括年月日星期時分秒。第44行的函數爲讀取時間。

 1 #ifdef eclipse
 2 void SMBUS_ISR(void)
 3 #else
 4 void SMBUS_ISR (void) interrupt ESMB0_VECTOR
 5 #endif
 6 {
 7     switch (SMB0STA) 
 8     {
 9         case SMB_START:                        //起始條件已發送
10             SMB0DAT = (COMMAND & 0xFE);
11             STA = 0;
12             break;
13         case SMB_RP_START:                //重複起始條件已發送
14             SMB0DAT = COMMAND;
15             STA = 0;
16             break;
17         case SMB_MTADDACK:                //地址 + WRITE已發送,收到ACK
18             SMB0DAT = wr_data[0];        
19             break;
20         case SMB_MTADDNACK:                //地址 + WRITE已發送,收到NACK。
21             STO = 1;                                //發送STOP + START重試
22             STA = 1;
23             break;
24         case SMB_MTDBACK:                    //數據字節已發送,收到ACK。
25             switch(Mode)
26             {
27                 case 1:
28                     wrnumber--;
29                     if(wrnumber)
30                         SMB0DAT = wr_data[1];
31                     else
32                     {
33                         STO = 1;
34                         SMB_BUSY=0;            
35                     }
36                     break;
37                 case 0:
38                     STA = 1;
39                     break;
40                 default:     
41                     STO = 1;
42                     SMB_BUSY = 0;   
43                     break;   
44             }
45             break;
46         case SMB_MTDBNACK:                //數據字節已發送,收到NACK。
47             STO = 1;                    
48             STA = 1;
49             break;
50         case SMB_MTARBLOST:                //競爭失敗
51             STO = 1;                    
52             STA = 1;
53             break;
54         case SMB_MRADDACK:                //地址 + READ 已發送。收到ACK
55             AA = 0;                        
56             break;
57         case SMB_MRADDNACK:                //地址 + READ 已發送。收到NACK
58             STO = 0;                    
59             STA = 1;
60             break;
61         case SMB_MRDBACK:                    //收到數據字節。ACK已發送
62             get_data = SMB0DAT;
63             SMB_BUSY = 0;                        //完成
64             STO = 1;                    
65             break;
66         case SMB_MRDBNACK:                //收到數據字節。NACK已發送
67             get_data = SMB0DAT;
68             SMB_BUSY = 0;                
69             STO = 1;                    
70             break;
71         default:
72             STO = 1;
73             break;
74     }
75     SI = 0;
76 }
View Code

   SMBus中斷,須要手動清除中斷標誌。

3.3 實物

相關文章
相關標籤/搜索