201406081553Time 時鐘與RTC 即時時鐘

關於時鐘,arduino板子裡是使用石英振盪器來計時,但沒電池,所以無法保存時間

很麻煩的是,每次程式重新執行時,時間就是reset

況且內部計時的資料型別,即使用到長整數(unsigned long),50天後也會溢位

當然如果有網路板的話,就可以連上網路,做NTP校時服務,一樣可以抓取到時間

同樣也會面臨到溢位的問題

arduino.cc 中有提供Time.h和TimeAlarm.h的函式

在這裡僅分享最簡單的部份,讓大家感受一下Time函式裡追蹤時間和日期的功能

Arduino Time Library ← arduino.cc的連接

RTC_Test ← 本篇文章的程式碼下載

#include "time.h"
void setup()
{
  Serial.begin(9600);
  setTime(16,0,0,8,6,14);  //2014-06-08 16:00:00
  Serial.println("Format is \"yyyy-dd-mm hh:mm:ss\"");
}

void loop()
{
  PrintTime();
  delay(1000);
}

void PrintTime()
{
  Serial.print(year(), DEC);  // Year need not to be changed
  Serial.print("-");
  if (month() < 10)   // correct month if necessary
  {
    Serial.print("0");
    Serial.print(month(), DEC);
  }
  else
  {
    Serial.print(month(), DEC);
  }
  Serial.print("-");
  if (day() < 10)  // correct date if necessary
  {
    Serial.print("0");
    Serial.print(day(), DEC);
  }
  else
  {
    Serial.print(day(), DEC);
  }
  Serial.print(" ");
  if (hour() < 10)  // correct hour if necessary
  {
    Serial.print("0");
    Serial.print(hour(), DEC);
  } 
  else
  {
    Serial.print(hour(), DEC);
  }
  Serial.print(":");
  if (minute() < 10)  // correct minute if necessary
  {
    Serial.print("0");
    Serial.print(minute(), DEC);
  }
  else
  {
    Serial.print(minute(), DEC);
  }
  Serial.print(":");
  if (second() < 10)  // correct second if necessary
  {
    Serial.print("0");
    Serial.print(second(), DEC);
  }
  else
  {
    Serial.print(second(), DEC);
  }
  Serial.println();
}

 

一般來說,為了讓計時模組獨立運作,都會有另外獨立的電池

RTC (Real Time Clock) 即時時鐘當設定完成後,獨立電池,會持續運作,不受外部電源影響

像桌上型電腦主機板裡、電子手錶、HMI(人機介面)等裡都有RTC

RTC晶片最常見的即是DS1307,上述arduino.cc連結中也有DS1307RTC.h函式庫可供使用

市面上有許多種RTC小板,在這邊分享的是DFRobot出的

下面是電路連接圖:

大部份RTC板子都是使用 I2C (Inter-Integrated Circuit)和arduino做溝通

以Uno為例,就是將RTC上SCL (Serial clock line)接腳連到類比接腳5、SDA (Serial data line)接腳連到類比接腳4

RTC板子還有有一個DS訊號接到數位接腳2,那是DS1307的SQW/OUT

可以輸出1Hz, 4kHz, 8kHz, 32kHz的方波,基本上在這裡並不會使用到

這個RTC板子的函式和設定可以在這個網站中觀看到 Real Time Clock Module

 

範例程式中setup()裡需要輸入時間,會先去RAM中檢查時間是否被設定過,沒有才允許寫入

如果想要重新設定,需要將下列二行unmark掉後重燒錄

 

//  TimeIsSet = 0xffff;
//  RTC.setRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t)); 

 

做完後記得再mark回來,然後重新燒錄,否則arduino板子只要重新被設定

時間又會跳回原先設定的

 

範例程式中,關於顯示星期幾的地方是錯誤的

從DS1307抓出來的資料 Sun=1, Mon=2, ....., Sat=7

但DS1307new.h函式庫中,又做 dow-- 的動作,所以請將範例程式#180的地方改成

  case 0:
    Serial.print("SUN");

    break;

我所提供的範例程式RTC_Test.ino中,為了之後綜合專案,做了簡單小應用

時間在秒數為hh:mm:00和hh:mm:30時,會做一個七彩LED燈開/關的動作

至於定時器的設定上,只有做一組ON/OFF,往後會寫成library,做多組定時器

使用者可以選擇三種格式:(1) hh:mm:ss (2) mm:ss (3) ss

但一般來說會用到的應該是 DayOfWeek + hh:mm:ss 的組合才對

這個在之後的綜合專案會提出來

 


#include "Wire.h"
#include "DS1307new.h"

int LED_PIN = 7;
uint16_t startAddr = 0x0000;            // Start address to store in the NV-RAM

uint8_t ON_HOUR = 0xFF;
uint8_t ON_MINUTE = 0xFF;
uint8_t ON_SECOND = 0xFF;
uint8_t OFF_HOUR = 0xFF;
uint8_t OFF_MINUTE = 0xFF;
uint8_t OFF_SECOND = 0xFF;

void setup()
{
  Serial.begin(9600);
  
  RTC.setRAM(0, (uint8_t *)&startAddr, sizeof(uint16_t));// Store startAddr in NV-RAM address 0x08
  RTC.getTime();
  RTC.ctrl = 0x00;                      // 0x00=disable SQW pin, 0x10=1Hz,
                                        // 0x11=4096Hz, 0x12=8192Hz, 0x13=32768Hz
  RTC.setCTRL();
  Serial.println("Format is \"yyyy-dd-mm hh:mm:ss (dow)\"");
  
  pinMode(LED_PIN, OUTPUT);
  ON_SECOND = 0;
  OFF_SECOND = 30;
}

void loop()
{
  if (IsTimerTrigger(ON_HOUR, ON_MINUTE, ON_SECOND))
  {
    Serial.println("7 color LED on!");
    digitalWrite(LED_PIN, HIGH);
  }
  
  if (IsTimerTrigger(OFF_HOUR, OFF_MINUTE, OFF_SECOND))
  {
    Serial.println("7 color LED off...");
    digitalWrite(LED_PIN, LOW);
  }
    
  PrintTime();
  delay(1000);
}

boolean IsTimerTrigger(uint8_t _hour, uint8_t _minute, uint8_t _second)
{
  int compare_case = -1;

  // Check timer cases, 0) hh:mm:ss   2) mm:ss   3) ss
  if (_hour != 0xFF && _minute != 0xFF && _second != 0xFF)
    compare_case = 0;
  else if (_hour == 0xFF && _minute != 0xFF && _second != 0xFF)
    compare_case = 1;
  else if (_hour == 0xFF && _minute == 0xFF && _second != 0xFF)
    compare_case = 2;
  else
    return false;
  
  // Compare timer time with now time from RTC  
  RTC.getTime();
  if ((compare_case == 0) && (RTC.hour == _hour && RTC.minute == _minute && RTC.second == _second))
    return true;
  if ((compare_case == 1) && (RTC.minute == _minute && RTC.second == _second))
    return true;
  if (compare_case == 2 && RTC.second == _second)
    return true;

  return false;  
}

void PrintTime()
{
  RTC.getTime();
  Serial.print(RTC.year, DEC);  // Year need not to be changed
  Serial.print("-");
  if (RTC.month < 10)   // correct month if necessary
  {
    Serial.print("0");
    Serial.print(RTC.month, DEC);
  }
  else
  {
    Serial.print(RTC.month, DEC);
  }
  Serial.print("-");
  if (RTC.day < 10)  // correct date if necessary
  {
    Serial.print("0");
    Serial.print(RTC.day, DEC);
  }
  else
  {
    Serial.print(RTC.day, DEC);
  }
  Serial.print(" ");
  if (RTC.hour < 10)  // correct hour if necessary
  {
    Serial.print("0");
    Serial.print(RTC.hour, DEC);
  } 
  else
  {
    Serial.print(RTC.hour, DEC);
  }
  Serial.print(":");
  if (RTC.minute < 10)  // correct minute if necessary
  {
    Serial.print("0");
    Serial.print(RTC.minute, DEC);
  }
  else
  {
    Serial.print(RTC.minute, DEC);
  }
  Serial.print(":");
  if (RTC.second < 10)  // correct second if necessary
  {
    Serial.print("0");
    Serial.print(RTC.second, DEC);
  }
  else
  {
    Serial.print(RTC.second, DEC);
  }
  Serial.print(" ");
  switch (RTC.dow)  // Friendly printout the weekday
  {
    case 1:
      Serial.print("(MON)");
      break;
    case 2:
      Serial.print("(TUE)");
      break;
    case 3:
      Serial.print("(WED)");
      break;
    case 4:
      Serial.print("(THU)");
      break;
    case 5:
      Serial.print("(FRI)");
      break;
    case 6:
      Serial.print("(SAT)");
      break;
    case 0:
      Serial.print("(SUN)");
      break;
    default:
      Serial.print("RTC.dow failed!");
      break;
  }
  //skip seconds since 1.1.2000 and daylight saving time
  /*Serial.print(" seconds since 1.1.2000:");
  Serial.print(RTC.time2000, DEC);
  uint8_t MESZ = RTC.isMEZSummerTime();
  Serial.print(" MEZ=0, MESZ=1 : ");
  Serial.print(MESZ, DEC);  */
  Serial.println();
}

 

沒有上一則|日誌首頁|沒有下一則
回應
關鍵字
    沒有新回應!