星期日, 3月 19, 2017

Arduino筆記(十七):即時時鐘 RTC 與 TM1637 四位數顯示器

[2017/03/19]
通常電腦關機之後重開機,能夠正確知道現在的時間,主要原因是主機板上有一個實時時鐘(RTC,real-time clock)晶片,搭配一顆電池;當電源關閉後,這個電池能持續提供時鐘運作。Arduino 為了成本考量,並沒有內建 RTC 晶片及電池,如果安裝 Arduino 網路擴展板,於開機時,可向網際網路的時間伺服器進行校時。如果沒有網路時,可以安裝 RTC 模組來校正時間,這也是我們今天要介紹的主題:RTC DS1302模組。

有一個額外的插曲:我兩三年前買的 RTC DS1302模組,換過新的電池後,依照線路圖接上,一點反應也沒有,在三確認了好幾次,還是不行,不知道是哪裡壞了,只好放棄。今天到光華商場再買一個新的,花了 50元,總算可以正常取得 RTC 的時間了。

[名詞]

實時時鐘(Real-time clock)是指可以像時鐘一樣輸出實際時間的電子裝置,一般會是積體電路,因此也稱為時鐘晶片。此名詞常用來表示在個人電腦、伺服器或嵌入式系統中有此機能的裝置,不過許多需要精確時的系統都會有此功能。
實時時鐘和定時器訊號(Clock signal)不同,後者只是數位電路中一個表示時間的方波訊號,而且不會以日常使用的時間單位表示。[維基百科]

網路時間協定(Network Time Protocol,簡稱NTP)是在資料網路潛伏時間可變的電腦系統之間通過封包交換進行時鐘同步的一個網路協定。自1985年以來,NTP是目前仍在使用的最古老的網際網路協定之一。[維基百科]

[材料]

• Arduino Uno  x 1
• DS1302 RTC 模組  x1
• TM1637 四位數七段顯示器模組 x1
• 連接線 x 11條

[接線圖]


• DS1302 與TM1637 模組連接線路
DS-1302模組
Arduino
 TM 1637四位數段顯示器
GND Ground
GND
 GND
VCC +5V
5V
 VCC
RST
Pin 2
 -
DAT
Pin 3
 -
CLK
Pin 4
 -
-
Pin 8
 DIO
-
Pin 9
 CLK

[程式]

#include <ds1302.h>
#include <tm1637display.h>

// DS1302 初始化設定
DS1302 rtc(2, 3, 4);

// 設定 TM1637 接腳
#define CLK 9
#define DIO 8

TM1637Display display(CLK, DIO);
boolean colon = true ;

String dw = "";
String hh = "";
String mm = "";
String ss = ""; 
float t = 0; 
  
void setup()
{
  // 設定時鐘執行模式,取消寫入保護
  rtc.halt(false);
  rtc.writeProtect(false);
  
  // Setup Serial connection
  Serial.begin(9600);
  display.setBrightness(0xA);
  
// 第一次設定寫入 DS1302 RTC時鐘,之後可以加上註解
//  rtc.setDOW(SUNDAY);         // 設定每週星期幾?
//  rtc.setTime(20, 16, 30);     // 設定24小時時間 20:16:30 
//  rtc.setDate(19, 3, 2017);   // 設定日期(日, 月, 年)
}

void loop()
{
  // 取得星期幾
  Serial.print(rtc.getDOWStr());
  Serial.print(" ");
  
  // 取得日期
  Serial.print(rtc.getDateStr());
  Serial.print(" -- ");

  // 取得時間
  dw = rtc.getTimeStr();
  Serial.println(dw);
  
  hh = dw.substring(0,2);          // 時數
  mm = dw.substring(3,5);          // 分鐘數
  ss = dw.substring(6,8);          // 秒數 

  // 顯示四位數中間的冒號
  uint8_t segto;
  int value = 1000;
  // 顯示 時:分
  int  t =  hh.toInt()*100  + mm.toInt();
  // 顯示 分:秒
  //  int t =  mm.toInt() *100 +ss.toInt();
  segto = 0x80 | display.encodeDigit((t / 100)%10);
  display.setSegments(&segto, 1, 1);
  delay(500);

  // 顯示時間
  display.showNumberDec(t, true);
  delay(500);
}

[參考資料]

•  Rinky Dink Electronics:DS1302 Library
•  Github:avishorp/Arduino library for TM1637 (LED Driver)
•  TMP1637 技術手冊


Share:

19 則留言:

  1. 請問 我想做一個時鐘 // 第一次設定寫入 DS1302 RTC時鐘,之後可以加上註解
    // rtc.setDOW(SUNDAY); // 設定每週星期幾?
    // rtc.setTime(20, 16, 30); // 設定24小時時間 13:05:00
    // rtc.setDate(19, 3, 2017); // 設定日期(日, 月, 年)
    }
    這部分是 //之後 不是都不會算進程式碼裡嗎? 那// rtc.setDOW(SUNDAY); 後面為甚麼還要分號
    然後// rtc.setTime(20, 16, 30); // 設定24小時時間 13:05:00
    的20 16 30 我看的不是很懂 為甚麼這個時間代表13:05:00
    我還只是新手 可以請問一下嗎?

    回覆刪除
    回覆
    1. 您好, 回覆如下:
      (1) //後面是註解,程式不會執行。我沒有另外寫設定時間程式,只好在程式中的第一次執行時,將當時時間寫入RTC,再將程式註解起來,沒有將;拿掉。
      (2) 程式每行後面要加;,這是C語言的特性,Arduino的IDE基礎也是C語言,除了include等特殊用法外,每行後面都要加;。
      (3) 註解後面的時間是我修改幾次第一次時間後,忘了修正,應該為 20:16:30才對,謝謝指正。

      刪除
    2. 請問有聯絡方式 可以方便指導一下嗎??因為我照打編譯一直錯誤

      刪除
    3. 可以的話,把錯誤訊息貼出來,比較能夠知道哪裡有錯誤。

      刪除
    4. 作者已經移除這則留言。

      刪除
    5. 因為我當時是 完全照 上面的程式碼// DS1302: RST pin -> Arduino Digital 2
      // DAT pin -> Arduino Digital 3
      // CLK pin -> Arduino Digital 4
      // TM1637 CLK pin -> Arduino Digital 9
      // DIO pin -> Arduino Digital 8

      #include
      #include

      // DS1302 初始化設定
      DS1302 rtc(2, 3, 4);

      // 設定 TM1637 接腳
      #define CLK 9
      #define DIO 8

      TM1637Display display(CLK, DIO);
      boolean colon = true ;

      String dw = "";
      String mm = "";
      String ss = "";
      float t = 0;

      void setup()
      {
      // 設定時鐘執行模式,取消寫入保護
      rtc.halt(false);
      rtc.writeProtect(false);

      // Setup Serial connection
      Serial.begin(9600);
      display.setBrightness(0xA);

      // 第一次設定寫入 DS1302 RTC時鐘,之後可以加上註解
      // rtc.setDOW(SUNDAY); // 設定每週星期幾?
      // rtc.setTime(20, 16, 30); // 設定24小時時間 20:16:30
      // rtc.setDate(19, 3, 2017); // 設定日期(日, 月, 年)
      }

      void loop()
      {
      // 取得星期幾
      Serial.print(rtc.getDOWStr());
      Serial.print(" ");

      // 取得日期
      Serial.print(rtc.getDateStr());
      Serial.print(" -- ");

      // 取得時間
      dw = rtc.getTimeStr();
      Serial.println(dw);

      mm = dw.substring(3,5); //分鐘數
      ss = dw.substring(6,8); //秒數

      // 顯示四位數中間的冒號
      uint8_t segto;
      int value = 1000;
      int t = mm.toInt() *100 +ss.toInt();
      segto = 0x80 | display.encodeDigit((t / 100)%10);
      display.setSegments(&segto, 1, 1);
      delay(500);

      // 顯示時間
      display.showNumberDec(t, true);
      delay(500);
      }

      刪除
    6. 後來我發現是 沒有加上附檔#include
      #include
      這兩個 所以 我再從參考資料裡下載 之後解壓縮 從資料夾裡取出 ds1302.h
      tm1637display.h
      這兩個檔案 將其跟主檔一起放在 library裡 再打開主檔編譯 發現依然編譯錯誤
      請問是我放置檔案的方式錯誤嗎? 我想問一下 正確的放置檔案方式 ?

      刪除
    7. D:\arduino-1.8.2\libraries\sketch_may25a\sketch_may25a.ino:7:20: fatal error: DS1302.h: No such file or directory

      #include

      ^

      compilation terminated.

      exit status 1
      開發板 Arduino/Genuino Uno 編譯錯誤。

      刪除
    8. 後來我將主檔 和兩個附檔的 .h /.cpp 從資料夾取出 之後全部放到主檔的資料夾
      編譯 後結果是D:\arduino-1.8.2\libraries\sketch_may25a\sketch_may25a.ino:7:20: fatal error: DS1302.h: No such file or directory

      #include

      ^

      compilation terminated.

      exit status 1
      開發板 Arduino/Genuino Uno 編譯錯誤。

      刪除
    9. 其中不知道為甚麼 用這個網頁去回覆的時候 < DS1302.h > 和 < tm1637display.h > 貌似在網頁上的回覆打不出來 基本上 有的地方空白 是 ds1302.h 跟 tm1637display.h 自己不見了 但在程式中沒這個問題

      刪除
    10. (1) 從網頁將程式複製至Arduino時,要注意大括號及小括號,常會被當成html語言,造成錯誤。
      (2) 下載DS1302 或其他Library,會是一個壓縮檔,解壓縮後會存放在一個目錄內,整個目錄Copy放在Arduino主程式下的libraries目錄內,例如,我安裝的 Arduino 主程式在 C:\Program Files (x86),解壓縮後的目錄整個複製到:C:\Program Files (x86)\Arduino\libraries就可以。不需要將 .h檔放在跟arduino 程式同一個目錄。記得複製完,要重新啟動 Arduino,就會在功能表的 草稿碼(Sketch) -> 匯入程式庫(Include Library) 中看到 DS1302 跟 TM1637Display這兩個Library。
      (3) 完成步驟二,在重新編譯程式,應該就會成功了,祝好運。

      刪除
  2. 請問為什麼我程式照你的打還是編譯不出來?

    回覆刪除
    回覆
    1. 你好, 編譯不出來有沒有錯誤訊息?是不是少了個 } 或是其他錯誤?可以的話,把錯誤訊息貼出來,比較方便知道哪裡有問題。

      刪除
  3. 你好,我照你程式碼全部複製貼上有問題
    sketch_may27a:11: error: 'DS1302' does not name a type
    sketch_may27a:17: error: 'TM1637Display' does not name a type
    sketch_may27a.ino: In function 'void setup()':
    sketch_may27a:28: error: 'rtc' was not declared in this scope
    sketch_may27a:33: error: 'display' was not declared in this scope
    sketch_may27a.ino: In function 'void loop()':
    sketch_may27a:44: error: 'rtc' was not declared in this scope
    sketch_may27a:62: error: 'display' was not declared in this scope

    回覆刪除
    回覆
    1. 可以了 我發現是字母大小寫問題

      刪除
    2. 我想請問一下 如果要改成時跟分要怎麼改?
      還有這可以加蜂鳴器弄成鬧鐘嗎?

      刪除
    3. 我已將程式更新,文章中的程式是顯示時:分,增加以下幾行:
      (1) String hh = "";
      (2) hh = dw.substring(0,2); // 時數
      (3) int t = hh.toInt()*100 + mm.toInt();

      您可以在文章中的程式找到這三行,如果要改成分:秒,就將 int t = ...哪一行註解互換即可。
      如果要做成鬧鐘也可以,只要比對設定鬧鐘的時間,跟hh,mm,ss比對,只要三個都值都一樣時,觸發蜂鳴器即可,有空可以做一下,應該蠻容易的,祝你成功。

      刪除
    4. 謝謝喔
      再問一下,雖然已經改成時跟分了,但要怎麼顯示現在正確時間?
      hh = dw.substring(0,2);這行為何是0,2

      刪除
    5. (1)要顯示正確時間,將上述程式「第一次設定寫入 DS1302...」,以下的三行註解拿掉,改成現在時間及日期,時間要稍為提前1-2分鐘,改好後,上傳到Arduino,此時時間已經寫入DS1302。將註解加上去,再上傳一次到Arduino,就可以了。沒寫設定介面,有點笨拙。
      (2)substring(0,2)的意思是從第0個位置開始,到2前的那個位元,指令可參考:
      https://www.arduino.cc/en/Reference/StringSubstring

      刪除