1、DS1337介紹編程
DS1337串行實時時鐘芯片是一種低功耗、所有采用BCD碼的時鐘日曆芯片,它帶有兩個可編程的定時鬧鐘和一個可編程的方波輸出。其地址和數據可經過I2C總線串行傳輸,能提供秒、分、時、日、星期、月和年等信息。eclipse
1.1 DS1337的引腳說明ide
DS1337的引腳排列示意圖如圖1所示。各引腳的功能以下:函數
圖1 DS1337引腳示意圖spa
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。其中:接口
DS1337的狀態寄存器地址爲0FH, 各位的做用以下:
圖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發生改變則是表明以下的開始和中止信號:
圖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 讀操做
對 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);
第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 }
第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 }
第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 }
SMBus中斷,須要手動清除中斷標誌。
3.3 實物