如何使用實時時鐘 IC DS1307 制作準(zhǔn)確的時鐘。時間將顯示在液晶顯示屏上。
要求
運行 Arduino 1.6.5 的計算機(jī)
阿杜諾
跳線
面包板
零件清單中的零件
您可以用 ATMEL 的另一個 IC 替換 Arduino,但要確保它具有足夠數(shù)量的輸入和輸出引腳以及 I 2 C 功能。我正在使用 ATMega168A-PU。如果你這樣做,你將需要一個程序員。我有 AVR MKII ISP 編程器。
建議讀者熟悉面包板,在Arduino環(huán)境下編程,對C編程語言有一定的了解。下面的兩個程序不需要額外的解釋。
介紹
微控制器如何跟蹤時間和日期?普通的微控制器有一個定時器功能,上電時從0(零)開始,然后開始計數(shù)。在 Arduino 世界中,我們可以使用 millis() 函數(shù)來重置自上電以來經(jīng)過的毫秒數(shù)。當(dāng)您斷開并重新連接電源時,它會重新開始。這在時鐘和日期方面不太方便。
這就是實時時鐘或 RTC 芯片派上用場的地方。該 IC 帶有 3v 紐扣電池或另一個 3v 電源,可跟蹤時間和日期。時鐘/日歷提供秒、分鐘、小時、星期、日期、月份和年份信息。IC 以 30/31 天和閏年校正月份。通過 I 2 C 總線進(jìn)行通信。I 2 C 總線將不在這里討論。
如果主電路的 Vcc 低于 Vbat,RTC 會自動切換到低功耗電池備份模式。備用電池通常是連接到 PIN 3 和 GND 的 3v 紐扣電池。通過這種方式,IC 仍會跟蹤時間和日期,當(dāng)主電路通電時,微控制器會獲取當(dāng)前時間和日期。
在這個項目中,我們使用的是DS1307。在該 IC 上,引腳 7 是 SQW/OUT 引腳。您可以使用此引腳來閃爍 LED,或為微控制器計時。我們將兩者都做。數(shù)據(jù)表中的下圖有助于我們了解 SQW/OUT。
此表可幫助您了解頻率:
頻率BIT7 & BIT6 & BIT5BIT4第 3 位和第 2 位BIT1位0
1赫茲 01 0 0 0
4.096Hz 01 0 0 1
8.192Hz 01 0 1 0
32.768Hz 01 0 1 1
如果將 LED 和電阻連接到 PIN 7,并希望它以 1Hz 頻率閃爍,則將 0b00010000 寫入控制寄存器內(nèi)存地址。如果你想要 4.096 Hz,你會寫 0b000100001?,F(xiàn)在您需要一臺示波器來查看脈沖,因為 LED 閃爍得如此之快,以至于看起來它一直亮著。我們使用的是 1Hz。
硬件
這是我們想要的框圖。
我們想要:
ISP(在系統(tǒng)編程中)對微控制器進(jìn)行編程
按鈕設(shè)置時間和日期
微控制器通過 I 2 C與 RTC 通信
在 LCD 上顯示時間和日期
示意圖:
點擊圖片為全尺寸。
零件清單
這是 Eagle 的截圖:
軟件
我們將在本指南中使用兩種不同的草圖:一種將時間和日期寫入 RTC,另一種從 RTC 讀取時間和日期。我已經(jīng)這樣做了,因此您將對正在發(fā)生的事情有更好的了解。我們將為這兩個程序使用與上述相同的電路。
首先,我們將時間和日期寫入 RTC,這就像在手表上設(shè)置時間一樣。
我們使用兩個開關(guān)。一種是增加小時、分鐘、日期、月、年和星期幾,另一種是在它們之間進(jìn)行選擇。該應(yīng)用程序不會從任何關(guān)鍵傳感器讀取值,因此我們使用中斷來檢查是否按下了開關(guān)并處理開關(guān)彈跳。有關(guān)開關(guān)彈跳的更多信息, 請閱讀此。
以下代碼將設(shè)置值并將它們寫入 RTC:
// Include header files #include #include // LCD pin definitions #define RS 9 #define E 10 #define D4 8 #define D5 7 #define D6 6 #define D7 5 LiquidCrystal lcd(RS, E, D4, D5, D6, D7); // Interrupt 0 is hardware pin 4 (digital pin 2) int btnSet = 0; // Interrupt 1 is hardware pin 5 (digital pin 3) int btnSel = 1; // Interrupt state int togBtnSet = false; int togBtnSel = false; // Time and date variables int tmpHour = 0; int tmpMinute = 0; int tmpDate = 0; int tmpMonth = 0; int tmpYear = 0; int tmpDay = 0; int tmpSecond = 0; int counterVal = 0; // Variable to keep track of where we are in the "menu" int myMenu[6]; // 0=Hour, 1=Minutes, 2=date, 3=MOnth, 4=Year, 5=DOW int menuCounter = 0; // A array of the weekday char* days[] = { "NA", "Mon", "Tue", "Wed", "Thu", "Fre", "Sat", "Sun" }; void setup() { // Interrupt declaration, execute increaseValue/nextItem function // when btnXXX is RISING attachInterrupt(btnSet, increaseValue, RISING); attachInterrupt(btnSel, nextItem, RISING); Wire.begin(); lcd.begin(16,2); showWelcome(); } // Interrupt function void increaseValue() { // Variables static unsigned long lastInterruptTime = 0; // Making a timestamp unsigned long interruptTime = millis(); // If timestamp - lastInterruptTime is greater than 200 if (interruptTime - lastInterruptTime > 200) { // Toggle the variable togBtnSet = !togBtnSet; // Increase the counterVal by 1 counterVal++; } // Setting lastInterruptTime equal to the timestamp // so we know we moved on lastInterruptTime = interruptTime; } // Next menuItem Interrupt function void nextItem() { static unsigned long lastInterruptTime = 0; unsigned long interruptTime = millis(); if (interruptTime - lastInterruptTime > 200) { togBtnSel = !togBtnSel; // Increase the menu counter so we move to next item menuCounter++; // Placing the counterVal in the menucounters array position myMenu[menuCounter] = counterVal; // Reset counterVal, now we start at 0 on the next menuItem counterVal = 0; } lastInterruptTime = interruptTime; } // Function that convert decimal numbers to binary byte decToBCD(byte val) { return ((val/10*16) + (val)); } // Short welcome message, now we know everything is OK void showWelcome() { lcd.setCursor(2,0); lcd.print("Hello world."); lcd.setCursor(3,1); lcd.print("I'm alive."); delay(500); lcd.clear(); } // Funcion to set the hour void setHour() { lcd.setCursor(0,0); lcd.print("Set hour. "); // Checks if interrupt has occured = button pressed if (togBtnSet) { // Update array value with counterVal myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); // Print the new value lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { // Update array value with counterVal myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); // Print the new value lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set minutes void setMinute() { lcd.setCursor(0,0); lcd.print("Set minute. "); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set date void setDate() { lcd.setCursor(0,0); lcd.print("Set date. "); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set month void setMonth() { lcd.setCursor(0,0); lcd.print("Set month. "); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set year void setYear() { lcd.setCursor(0,0); lcd.print("Set year. "); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set the day of week void setDOW() { lcd.setCursor(0,0); lcd.print("Set day (1=mon)."); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Write the data to the RTC void writeRTC() { Wire.beginTransmission(0x68); Wire.write(0); // Start address Wire.write(0x00); // seconds Wire.write(decToBCD(myMenu[1])); // convert tmpMinutes to BCD and write them Wire.write(decToBCD(myMenu[0])); // convert tmpHour to BCD and write them Wire.write(decToBCD(myMenu[5])); // convert tmpDay to BCD and write them Wire.write(decToBCD(myMenu[2])); // convert tmpDate to BCD and write them Wire.write(decToBCD(myMenu[3])); // convert tmpMonth to BCD and write them Wire.write(decToBCD(myMenu[4])); // convert tmpYear to BCD and write them Wire.write(0b00010000); // enable 1Hz Square wave on PIN7 Wire.endTransmission(); // close the transmission } // Show the time // You need to use the other program to see the RTC is working void showTime() { lcd.setCursor(0,0); lcd.print(" "); lcd.print(myMenu[0]); lcd.print(":"); // hour lcd.print(myMenu[1]); lcd.print(":"); lcd.print("00 "); // minute lcd.setCursor(3,1); lcd.print(days[myMenu[5]]); lcd.print(" "); // DOW lcd.print(myMenu[2]); lcd.print("."); // date lcd.print(myMenu[3]); lcd.print("."); // month lcd.print(myMenu[4]); lcd.print(" "); // year // Call the writeRTC function writeRTC(); } void loop() { if (menuCounter == 0) { setHour(); } if (menuCounter == 1) { setMinute(); } if (menuCounter == 2) { setDate(); } if (menuCounter == 3) { setMonth(); } if (menuCounter == 4) { setYear(); } if (menuCounter == 5) { setDOW(); } if (menuCounter == 6) { showTime(); } }
該程序以簡短的歡迎信息開始。此消息告訴您已接通電源,LCD 正在工作,并且程序已開始運行。
要從 RTC 讀取并顯示時間和日期,您必須使用以下程序?qū)ξ⒖刂破鬟M(jìn)行編程。程序從 RTC 讀取時間和日期值并將它們顯示在 LCD 上。
// Include header files
#include #include // LCD pin definitions #define RS 9 #define E 10 #define D4 8 #define D5 7 #define D6 6 #define D7 5 LiquidCrystal lcd(RS, E, D4, D5, D6, D7); // Pin that will receive clock pulse from RTC int clockPin = 0; // Time and date vaiables byte second; byte minute; byte hour; byte day; byte date; byte month; byte year; // A array of the weekday char* days[] = { "NA", "Mon", "Tue", "Wed", "Thu", "Fre", "Sat", "Sun" }; // Function run once void setup() { pinMode(clockPin, INPUT); pinMode(clockPin, LOW); Wire.begin(); lcd.begin(16,2); showWelcome(); } // Nice welcome message, then we know LCD is OK void showWelcome() { lcd.setCursor(2,0); lcd.print("Hello world."); lcd.setCursor(3,1); lcd.print("I'm alive."); delay(500); lcd.clear(); } // Doing this forever void loop() { // While clockPin is high while (digitalRead(clockPin)) { // start the I2C transmission, at address 0x68 Wire.beginTransmission(0x68); // Start at address 0 Wire.write(0); // Close transmission Wire.endTransmission(); // Start to read the 7 binary data from 0x68 Wire.requestFrom(0x68, 7); second = Wire.read(); minute = Wire.read(); hour = Wire.read(); day = Wire.read(); date = Wire.read(); month = Wire.read(); year = Wire.read(); // Formatting and displaying time lcd.setCursor(4,0); if (hour < 10) lcd.print("0"); lcd.print(hour, HEX); lcd.print(":"); if (minute < 10) lcd.print("0"); lcd.print(minute, HEX); lcd.print(":"); if (second < 10) lcd.print("0"); lcd.print(second, HEX); lcd.setCursor(2,1); // Formatting and displaying date lcd.print(days[day]); lcd.print(" "); if (date < 10) lcd.print("0"); lcd.print(date, HEX); lcd.print("."); if (month < 10) lcd.print("0"); lcd.print(month, HEX); lcd.print("."); lcd.print(year, HEX); } // end while }
結(jié)論
在本文中,我們研究了 Maxim Integrated 的小型 DS1307 RTC IC。我們制作了一個程序來設(shè)置時間和日期,我們制作了另一個程序來讀取時間和日期。為了檢查是否按下了開關(guān),我們使用了中斷。中斷還負(fù)責(zé)開關(guān)彈跳。
圖片
點擊圖片為全尺寸。
-
實時時鐘
+關(guān)注
關(guān)注
4文章
246瀏覽量
65859 -
DS1307
+關(guān)注
關(guān)注
1文章
34瀏覽量
14151
發(fā)布評論請先 登錄
相關(guān)推薦
評論