☛ 功能说明
使用 Arduino 开发板读取 DS1307 时钟芯片应用电路的日期时间,并且以 Serial Monitor 视窗显示日期时间。
时钟芯片说明如下:
DS1307 时钟芯片是一款低功耗实时时钟芯片,可以提供秒、分、小时等信息,而且每个月的天数能够自动调整,并且有闰年补偿功能。DS1307 是 Maxim 的串行、I2C 实时时钟芯片。主要特性有:
⑴ 工作电压:主电源电压 4.5~5.5V,电池电压 2.0~3.5V。
⑵ 功耗:电池供电、备份模式时<500nA。
⑶ 接口:I2C,最大速率 100kbps。
⑷ 可编程方波输出。
⑸ 电源自动切换、失效检测。
⑹ 内置 56 字节大小、支持电池备份的 RAM。
⑺ 封装:8-Pin SO / PDIP。
DS1307 时钟芯片的典型应用电路如下:
☛ 使用材料
Arduino UNO R3 开发板 × 1、电阻 4.7KΩ × 3、DS 1307 芯片 × 1、32.768kHz 晶振 × 1 。
☛ 电路图及面包板接线图
☛ 程序码
范例程序码 ㈠
#include <Wire.h> #include <TimeLib.h> #include <DS1307RTC.h> const char *monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; tmElements_t tm; // tmElements_t 为保存日期和时间的结构体类型 void setup() { bool parse=false; bool config=false; if (getDate(__DATE__) && getTime(__TIME__)) // 获取编译时的日期和时间 { parse = true; if (RTC.write(tm)) // 将时间数据写入 DS1307 RTC 芯片 { config = true; } } Serial.begin(9600); while (!Serial) ; // 等待 Arduino Serial Monitor 视窗 delay(200); if (parse && config) { Serial.print("DS1307 configured Time="); Serial.print(__TIME__); Serial.print(", Date="); Serial.println(__DATE__); } else if (parse) { Serial.println("DS1307 Communication Error :-{"); Serial.println("Please check your circuitry"); } else { Serial.print("Could not parse info from the compiler, Time=\""); Serial.print(__TIME__); Serial.print("\", Date=\""); Serial.print(__DATE__); Serial.println("\""); } } void loop() { tmElements_t tm; if (RTC.read(tm)) //读出 DS1307 芯片中的时间数据 { Serial.print("Ok, Time = "); print2digits(tm.Hour); Serial.write(':'); print2digits(tm.Minute); Serial.write(':'); print2digits(tm.Second); Serial.print(", Date (D/M/Y) = "); Serial.print(tm.Day); Serial.write('/'); Serial.print(tm.Month); Serial.write('/'); Serial.print(tmYearToCalendar(tm.Year)); Serial.println(); } else { if (RTC.chipPresent()) { Serial.println("The DS1307 is stopped. Please run the SetTime"); Serial.println("example to initialize the time and begin running."); Serial.println(); } else { Serial.println("DS1307 read error! Please check the circuitry."); Serial.println(); } delay(9000); } delay(1000); } bool getTime(const char *str) //获取时间数据并存入 tm 变量 { int Hour, Min, Sec; if (sscanf(str, "%d:%d:%d", &Hour, &Min, &Sec) != 3) return false; tm.Hour = Hour; tm.Minute = Min; tm.Second = Sec; return true; } bool getDate(const char *str) //获取日期数据并存入 tm 变量 { char Month[12]; int Day, Year; uint8_t monthIndex; if (sscanf(str, "%s %d %d", Month, &Day, &Year) != 3) return false; for (monthIndex = 0; monthIndex < 12; monthIndex++) { if (strcmp(Month, monthName[monthIndex]) == 0) break; } if (monthIndex >= 12) return false; tm.Day = Day; tm.Month = monthIndex + 1; tm.Year = CalendarYrToTm(Year); return true; } void print2digits(int number) { if (number >= 0 && number < 10) { Serial.write('0'); } Serial.print(number); }
上述程序码中的 __DATE__ 和 __TIME__ 是系统常量,当编译程序时,它们会自动替换为当前的日期和时间,再通过 getTime() 和 getDate() 这两个函数将日期和时间数据存入 tm 中。
而 tm 是一个 tmElements_t 类型的结构体,其定义在 TimeLib.h 中,内容如下:
typedef struct { uint8_t Second; uint8_t Minute; uint8_t Hour; uint8_t Wday; // day of week, sunday is day 1 uint8_t Day; uint8_t Month; uint8_t Year; // offset from 1970; } tmElements_t, TimeElements, *tmElementsPtr_t;
当日期和时间数据存入 tm 后,就可以通过 tm.Month、tm.Year 等操作得到数据了。
想要将数据写入 DS1307 中储存,还需调用 RTC.write(tm) 语句,如果返回 true,则说明数据写入成功。
设置好 DS1307 的时间后,要想读出其中的数据,可以使用 RTC.read(tm) 语句,读出的时间数据会储存在参数 tm 中。当 read() 函数成功地读取数据后会返回 true,读取失败则会返回 false。
程序中的 RTC.chipPresent() 是一个错误检查语句,可以根据错误提示重新设置 DS1307 的数据,或是检测硬件的电路连结是否正确。
范例程序码 ㈡
/* real time clock using DS1307 function: set the time */ #include <Wire.h> #define ADDRESS_DS1307 0x68 byte timeDec[] = {15, 1, 15, 5, 19, 20, 0}; byte timeBcd[] = {0, 0, 0, 0, 0, 0, 0}; //time = {year, month, date, day, hours, minutes, seconds}; void setup() { Wire.begin(); Serial.begin(9600); //convert decimal to BCD code int i; for (i = 0; i < 7; i++) { timeBcd[i] = DecToBcd(timeDec[i]); } //set the time Wire.beginTransmission(ADDRESS_DS1307); Wire.write(0x00); for (i = 0; i < 7; i++) { Wire.write(timeBcd[6-i]); } Wire.endTransmission(); Serial.println("Time has been set."); } void loop() { //read the time Wire.beginTransmission(ADDRESS_DS1307); Wire.write(0x00); Wire.endTransmission(); Wire.requestFrom(ADDRESS_DS1307, 7); if (Wire.available() >= 7) { for (int i = 0; i < 7; i++) { timeBcd[6-i] = Wire.read(); } } //print Serial.print("20"); Serial.print(timeBcd[0], HEX); Serial.print("/"); Serial.print(timeBcd[1], HEX); Serial.print("/"); Serial.print(timeBcd[2], HEX); Serial.print(" "); Serial.print(BcdToDay(timeBcd[3])); Serial.print(" "); Serial.print(timeBcd[4], HEX); Serial.print(":"); Serial.print(timeBcd[5], HEX); Serial.print(":"); Serial.print(timeBcd[6], HEX); Serial.println(); delay(1000); } // Convert normal decimal numbers to binary coded decimal byte DecToBcd(byte val) { byte res; if ((val <= 99) && (val >= 0)) { res = ((val/10)<<4) | (val%10); } else { res = 0; Serial.println("Error"); } return res; } // Convert binary coded decimal to normal decimal numbers byte BcdToDec(byte val) { byte res; if (val <= 0x99) { res = (val >> 4)*10 + (val & 0x0F); } else { res = 0; Serial.println("Error"); } return res; } // Convert binary coded decimal to day String BcdToDay(byte val) { String res; switch(val) { case 1: res = "Sunday"; break; case 2: res = "Monday"; break; case 3: res = "Tuesday"; break; case 4: res = "Wednesday"; break; case 5: res = "Thursday"; break; case 6: res = "Friday"; break; case 7: res = "Saturday"; break; default: res = "Error!"; } return res; }