作者:黃小棟
這次自造學堂的教學文主題是「用Arduino x RTC完成LCD時間顯示」。在這一章節裡除了介紹RTC模組外,也會教大家如何將RTC模組與上一章節中提到的I2C_LCD模組和Arduino做系統上的整合,讓大家不再只會使用一塊Arduino控制一個模組,或者看到Arduino IDE內資料庫一堆的範例程式,卻一頭霧水,不知該如何整合使用。
學習目標:
大家研讀完這篇文章並且實際操作之後,將會了解下列兩點:
- 對 DS3231_RTC模組有初步的認識,並且能夠將時間顯示在Arduino IDE的序列埠監控視窗上。
- 學會使用I2C匯流排,讓Arduino、RTC模組和LCD模組做結合,並且整合Arduino的範例程式來完成此專案的控制。
學習背景:
在研讀實作之前,必須知道下面幾點:
- 會安裝第三方資料庫libraries。(依然很重要)
- 了解麵包板的特性,並且知道如何使用。
- 知道I2C匯流排的特性。(可參考【自造學堂】Arduino如何透過I2C控制LCD模組的介紹)
好~話不多說,立刻進入我們的主題吧!
基礎認識:什麼是RTC?
我們可以在Google搜尋到,RTC是Real-time clock的縮寫,指的是負責記錄時間的積體電路元件。它可以跟時鐘一樣輸出實際時間,通常會出現在個人電腦、伺服器或嵌入式系統,因此大家的桌機和筆電內就有這個元件。RTC具有以下特性:
- 消耗功率低。
- 讓主系統處理更需時效性的工作。
- 有時會比其他方式的輸出要更準確。
以上資料皆來自於網路資源,若有興趣深入研究的也可再自行查找。
模組規格及腳位介紹
首先,我們這次所使用的模組為DS3231高精密RTC模組(iCShop貨號:368030500595)。筆者這次所使用的模組,依然要感謝iCShop的贊助提供。這次我們所使用的模組是下圖這顆:

RTC模組正面與電池組裝

RTC模組背面
接著來看官方所給的相關介紹資料分析:
“DS3231是低成本、高精度I2C即時時鐘(RTC),具有嵌入式的溫補晶振(TCXO)和晶體。該器件包含電池輸入端,斷開主電源時仍可保持精確的計時。嵌入晶振提高了器件的長期精確度,並減少了生產線的元件數量。DS3231提供商用級和工業級溫度範圍,採用16引腳300mil的SO封裝。”
我們可以自文中得知此模組是用I2C傳輸控制的,所以它裡面也會有SDA和SCL與我們Arduino UNO內的A4和A5的接腳做連接,並且會引用<Wire.h>的函式庫。關於RTC的時間格式及設置說明如下:
“RTC保存秒、分、時、星期、日期、月和年資訊。少於31天的月份,將自動調整月末的日期,包括閏年的修正。時鐘的工作格式可以是24小時或帶/AM/PM指示的12小時格式。它提供兩個可設置的日曆鬧鐘和一個可設置的方波輸出。位址與資料通過I2C雙向匯流排序列傳輸。”
也因此,它可以做電子時鐘相關的專案。想更進一步了解這顆RTC模組的話,請見iCShop本頁說明。
總而言之,這塊模組內部還包含一溫度感測,除了有主電源輸入外,還有備用電源(電池)輸入,但根據筆者測試的結果,它的備用電源僅供內部晶片繼續計時,不會提供訊號的輸出。最後是模組參數與接線說明介紹:
- 尺寸:38mm(長)*22mm(寬)*14mm(高)
- 工作電壓:3.3–5.5V
- 時鐘晶片: DS3231
- 存儲晶片:AT24C32(存儲容量32K)
- 可聯結其它IIC設備,24C32位址可通過短路A0/A1/A2修改,默認地址為0x57。
- 帶可充電電池LIR2032,保證系統斷電後,時鐘任然正常走動。
- 接線說明(以Arduino Uno為例):SCL→A5、SDA→A4、Vcc→5V、GND→GND。
模組硬體接線圖
進行模組接線之前,我們先來了解這次所要準備的材料:
- Arduino開發板 1塊(iCShop商品編號:368030500683)
- 麵包板 1塊(iCShop商品編號:368090200061)
- DS3231_RTC模組 1塊(iCShop商品編號:368030500595)
- I2C_LCD模組 1塊(iCShop商品編號:368030100095)
- 杜邦線(公-公、公-母) 數條(iCShop商品編號:3681101000389、368110100159)
再來是模組的接線方式,只需將「DS3231_RTC」模組和「I2C_LCD模組」Vcc接腳接至Arduino的5V接腳,模組們GND接腳接至Arduino的GND接腳,緊接著將模組們SDA接腳接至Arduino的A4接腳,最後是模組們SCL接腳接至Arduino的A5接腳即可完成接線。是不是非常容易呢?

本專案模組接線(DS3231_RTC模組和I2C_LCD 模組接法一樣)
模組程式範例
步驟1:
在講解程式之前,大家除了要先去網路上下載I2C_LCD的第三方資料庫以外(可參考【自造學堂】Arduino如何透過I2C控制LCD模組),還要下載「DS3231_TEST」這個第三方資料庫,雖然網路有眾多相關資料庫,然而經筆者測試,還是這個最簡單好用。
步驟2:
安裝好第三方資料庫後,請先開啟Arduino IDE,並且點選「檔案」→「範例」→「DS3231_TEST」→「Examples」→「DS3231_TEST」範例程式。

開啟DS3231_TEST範例程式
步驟3:
#include <DS3231.h>
#include <Wire.h>DS3231 Clock;
bool Century=false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;byte year, month, date, DoW, hour, minute, second;
在程式範例介紹的部分,我們可以了解在程式宣告的區域裡,它一開始同樣引用了<DS3231.h>和<Wire.h>這兩個函式庫,並且做了相關函式的定義。所謂的函式定義,好比我們國高中數學所學,會先假設「蓮霧的數量為X,芭樂的數量為Y……」是一樣的意思,引用函式庫即相當於「這個算式要引用二元一次方程式」之意。
void setup() {
// Start the I2C interface
Wire.begin();
Clock.setSecond(50);//Set the second
Clock.setMinute(59);//Set the minute
Clock.setHour(11); //Set the hour
Clock.setDoW(5); //Set the day of the week
Clock.setDate(31); //Set the date of the month
Clock.setMonth(5); //Set the month of the year
Clock.setYear(13); //Set the year (Last two digits of the year)
// Start the serial interface
Serial.begin(115200);
}
在初始化設定裡,此處做了秒、分、時、週、日、月、年的設定,大家可以任意改括弧裡面的數值測試看看。接著設定Baud Rate為115200。
(註:綠色文字部分為「函式定義的設定」;橘色文字部分為「序列埠監控視窗訊息的輸出」。)
void ReadDS3231()
{
int second,minute,hour,date,month,year,temperature;
second=Clock.getSecond();
minute=Clock.getMinute();
hour=Clock.getHour(h12, PM);
date=Clock.getDate();
month=Clock.getMonth(Century);
year=Clock.getYear();temperature=Clock.getTemperature();
Serial.print(“20”);
Serial.print(year,DEC);
Serial.print(‘-‘);
Serial.print(month,DEC);
Serial.print(‘-‘);
Serial.print(date,DEC);
Serial.print(‘ ‘);
Serial.print(hour,DEC);
Serial.print(‘:’);
Serial.print(minute,DEC);
Serial.print(‘:’);
Serial.print(second,DEC);
Serial.print(‘\n’);
Serial.print(“Temperature=”);
Serial.print(temperature);
Serial.print(‘\n’);
}
這個範例程式比較特別的地方,是在主程式迴圈之前,先設定好一個「ReadDS3231()」這個副程式。副程式的好處是:當程式很多很雜,可藉由副程式的設定,使主程式迴圈乾淨簡潔好閱讀。這個副程式會先設定函式定義,如同X=1,Y=2一樣,再來即可進行序列埠監控視窗訊息的輸出。
void loop()
{
ReadDS3231();
delay(1000);
}
最後就是主程式迴圈,一直執行「ReadDS3231()」這個副程式,並且中間延遲1秒。當然我們也可以把副程式跟主程式迴圈做結合,也是一樣的意思,以下為結合後的全部程式。
#include <DS3231.h>
#include <Wire.h>DS3231 Clock;
bool Century=false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;
byte year, month, date, DoW, hour, minute, second;void setup() {
// Start the I2C interface
Wire.begin();
Clock.setSecond(50);//Set the second
Clock.setMinute(59);//Set the minute
Clock.setHour(11); //Set the hour
Clock.setDoW(5); //Set the day of the week
Clock.setDate(31); //Set the date of the month
Clock.setMonth(5); //Set the month of the year
Clock.setYear(13); //Set the year (Last two digits of the year)
// Start the serial interface
Serial.begin(115200);
}
void loop()
{
int second,minute,hour,date,month,year,temperature;
second=Clock.getSecond();
minute=Clock.getMinute();
hour=Clock.getHour(h12, PM);
date=Clock.getDate();
month=Clock.getMonth(Century);
year=Clock.getYear();
temperature=Clock.getTemperature();Serial.print(“20”);
Serial.print(year,DEC);
Serial.print(‘-‘);
Serial.print(month,DEC);
Serial.print(‘-‘);
Serial.print(date,DEC);
Serial.print(‘ ‘);
Serial.print(hour,DEC);
Serial.print(‘:’);
Serial.print(minute,DEC);
Serial.print(‘:’);
Serial.print(second,DEC);
Serial.print(‘\n’);
Serial.print(“Temperature=”);
Serial.print(temperature);
Serial.print(‘\n’);
delay(1000);
}
步驟4:
最後我們要與LCD程式做整合,讓LCD顯示時間。其實很簡單,我們先開啟【自造學堂】Arduino如何透過I2C控制LCD模組最後的程式,並且在宣告區域引用<LiquidCrystal_I2C.h>這個函數式。再來將於初始化設定該設定的,以及想在主程式迴圈顯示的,通通複製貼上並修改即可。程式如下:
#include <DS3231.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>DS3231 Clock;
bool Century=false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;
byte year, month, date, DoW, hour, minute, second;LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
void setup() {
// Start the I2C interface
Wire.begin();
Clock.setSecond(59);//Set the second
Clock.setMinute(10);//Set the minute
Clock.setHour(12); //Set the hour
Clock.setDoW(5); //Set the day of the week
Clock.setDate(17); //Set the date of the month
Clock.setMonth(3); //Set the month of the year
Clock.setYear(17); //Set the year (Last two digits of the year)
// Start the serial interface
Serial.begin(115200);// 初始化 LCD,一行 16 的字元,共 2 行,預設開啟背光
lcd.begin(16, 2);// 閃爍三次
for(int i = 0; i < 3; i++) {
lcd.backlight(); // 開啟背光
delay(250);
lcd.noBacklight(); // 關閉背光
delay(250);
}
lcd.backlight();// 輸出初始化文字
lcd.setCursor(0, 0); // 設定游標位置在第一行行首
lcd.print(“ICshop&MakerPRO”);
delay(1000);
lcd.setCursor(0, 1); // 設定游標位置在第二行行首
lcd.print(“Hello, Maker!”);
delay(8000);
lcd.clear();
}void loop() {
int second,minute,hour,date,month,year,temperature;
second=Clock.getSecond();
minute=Clock.getMinute();
hour=Clock.getHour(h12, PM);
date=Clock.getDate();
month=Clock.getMonth(Century);
year=Clock.getYear();temperature=Clock.getTemperature();
Serial.print(“20”);
Serial.print(year,DEC);
Serial.print(‘-‘);
Serial.print(month,DEC);
Serial.print(‘-‘);
Serial.print(date,DEC);
Serial.print(‘ ‘);
Serial.print(hour,DEC);
Serial.print(‘:’);
Serial.print(minute,DEC);
Serial.print(‘:’);
Serial.print(second,DEC);
Serial.print(‘\n’);
Serial.print(“Temperature=”);
Serial.print(temperature);
Serial.print(‘\n’);lcd.setCursor(0, 0); // 設定游標位置在第一行行首
lcd.print(“ICshop&MakerPRO”);
lcd.setCursor(0, 1);
lcd.print(“Time=”);
lcd.setCursor(5, 1); // 設定游標位置在第二行行首
lcd.print(hour,DEC);
lcd.setCursor(7, 1);
lcd.print(‘:’);
lcd.setCursor(8, 1);
lcd.print(minute,DEC);
lcd.setCursor(10, 1);
lcd.print(‘:’);
lcd.setCursor(11, 1);
lcd.print(second,DEC);delay(1000);
}
最後這個程式的流程,一樣是啟動Arduino時,會先引用Wire、DS3231與LiquidCrystal_I2C函式庫。之後於初始化設定,則會先控制LCD模組閃爍背光三次,並在第一行顯示「ICshop&MakerPRO」,延遲一秒後在第二行顯示「Hello, Maker!」,並且延遲八秒,再清除所有顯示。
最後進入主程式迴圈裡面,在第一行顯示「ICshop&MakerPRO」等字,而後在第二行開頭先顯示「Time=」等字,在第6位元顯示「時」並且十進位(DEC)輸出,在第8位元顯示「:」,後面以此列推,最後延遲1秒,再進入下一個迴圈。
結語
相信做到這裡,大家都已經完成LCD模組的時間顯示了吧!如果沒有的話,還是要檢查一下,是否接錯哪條線路了,或者程式有打錯(比如有分號未打之類的)。最後,不用太介意自己沒有相關背景與技術,只需要了解其原理原則,就能夠享受當Maker的樂趣,這也是Arduino的魅力所在!
(責任編輯:林佳盈)
- 【Project】用D2000完成環境監控系統及基座 - 2017/07/20
- 【Tutorial】如何使用LinkIt 7697在MCS上監控溫溼度變化 - 2017/06/21
- 【實測心得】Intel Quark D2000有何優勢? - 2017/05/30
訂閱MakerPRO知識充電報
與40000位開發者一同掌握科技創新的技術資訊!
2021/03/12
不好意思DS3231_TEST這個網址不見了
2021/03/17
不好意思,本文時間已久,建議用Google Search看看,有查到這個給你參考:https://gist.github.com/dvsseed/649717d92b8a2d8e7d6dfcc2d3fed145#file-ds3231_test-ino
2021/03/09
不好意思那個副檔名的網址不見了,可以再給一次嗎?
2021/03/09
請問是哪個副檔名呢?
2021/03/11
DS3231_TEST這個第三方資料庫的網址不見了
2020/05/29
有成功了,搞了一天,這個版本是對的。
感謝教學
2018/09/13
請問小時要調整成24HR制該如何設定?
month=Clock.getMonth(Century);其中Century預設為flase用意何在?謝謝!
2018/09/20
有關於操作上或技術上的一些小問題,歡迎您在MakerPRO社群論壇-交流、分享、協作
進行留言與提問喔!社團裡有許多厲害的Maker們願意分享他們的經驗
謝謝您的提問
MakerPRO 編輯部
2018/07/28
程式碼複製過去顯示字串的引號會變全形.所以會出錯無法正常顯示
例如(lcd.print(‘:’);)裡面的單引號會變全形.雙引號也是.
2018/05/13
請問筆者使用arduino版本為何 因為螢幕沒有顯示但有上傳成功
2018/05/08
請問筆者使用arduino版本為何??
2018/05/08
求大神們指點指點小弟都按照步驟來可是LCD跑不出東西來請問筆者ARDUINO版本是??還跑出exit status 1
stray ‘\241’ in progra的這串字,專題有點趕求大神們幫幫忙阿
2019/04/15
因为有中文符号,尝试更换为英文的” 或’
2017/11/22
rtc ds1307 跟i2c lcd 如何混合在一起我有兩個單獨的程式我要讓ds1307所收到的\時間在lcd上面顯示出來
2017/11/23
您好,這裡是MakerPRO編輯部,謝謝您的詢問,關於技術問題,需要詢問一下作者再回覆您噢~若急需解答,建議可上MakerPRO社群發問,相信社群中的高手們能很快為您解惑!請上:https://www.facebook.com/groups/makerpro.cc/
2017/11/20
請問 我時間顯示當只有一個位數時我希望他能夠補零輸出例如:原本是1,2,3…
我希望它是 01,02,03
請問程式要怎麼改呢??
2017/11/21
您好,這裡是MakerPRO編輯部,謝謝您的詢問,我們詢問一下作者再回覆您噢~~
2017/11/20
請問我計數到了59秒之後 他會從09開始計數請問要怎麼調整??才能夠從00開始計數??
請大大幫我解惑感謝
2017/11/21
您好,這裡是MakerPRO編輯部,謝謝您的詢問,我們詢問一下作者再回覆您噢~~
2017/10/01
想請問一下這個副程式「DS3231_TEST」為什麼不能使用?因為我們也有使用這個程式可是我們下載完後也有把副程式加進去I2C_LCD模組也是去上面建議的地方購買的,可是到後來也找不出什麼錯誤但是I2C_LCD模組上就是沒顯示時間
2017/10/19
您好,我們是MakerPRO編輯部,感謝您的提問,這是技術問題的部分,我們再請作者來回答噢:)
2018/03/01
I2C_LCD上看一下上面的晶片,如果轉接的晶片是PCF8574T位址是0X27,如果是PCF8574AT位址是0X3F