Arduino實例1——基於DS3231多功能(手動校時/鬧鐘/溫顯)RTC(實時時鐘)製作-IIC1602顯示

最近拿到實時時鐘模塊DS3231,可能很多人不知道這個芯片,這個芯片號稱(數據手冊)年誤差可以做到小於兩分鐘的高精度時鐘芯片;不過玩過DS1302的同學都知道確實精度很差,有時一天誤差好幾秒!
簡單總結下DS3231:DS3231是低成本、高精度I2C實時時鐘(RTC),具有集成的溫補晶振(TCXO)和晶體,具有以下特性:
* 實時時鐘產生秒、分、時、星期、日期、月和年計時,並提供有效期到2100年的閏年補償
* 兩個日曆鬧鐘
* 可編程方波輸出
* IIC總線接口
* 備份電池輸入
* 溫度輸出(注意:溫度64秒更新一次 --- 在VCC初次上電或Vbat供電下首次進行IIC通信時,開始讀取溫度值,之後每64秒讀取一次)

......-
更多詳細可以參考數據手冊:
http://wiki.yfrobot.com/datasheet/DS3231.pdf
http://wiki.yfrobot.com/datasheet/DS3231_cn.pdf

下面是我使用RTC3231時鐘模塊做的小項目:桌面時鐘
首先需要用到的器件:
1、主板arduino
2、RTC3231模塊
3、IIC1602液晶
4、3按鍵
電路連接:

提示:使用鬧鐘功能時,需要連接中斷引腳(UNO爲例)D2 到DS3231模塊 INT/SQW引腳 ;不使用時不連接也可以

D4,D5,D6 連接按鍵。。。

示例程序:
需要用到庫文件:RtcDS3231庫 -- 庫介紹
本站下載地址:
程序下載:

/* arduino sketch --
    arduino display date and time with IIC 1602 LCD and get them with ds3231 RTC breakout
   SETUP:
    arduino (UNO R3)     ds3231/iic_1602
      A4/SDA          →    SDA
      A5/SCL          →    SCL
      GND             →    GND
 
   Read More DS3231: [url=http://www.yfrobot.com/wiki/index.php?title=RTC_3231]http://www.yfrobot.com/wiki/index.php?title=RTC_3231[/url]
   BY YFROBOT
*/
 
#include <Wire.h>  // must be incuded here so that Arduino library object file references work
#include <RtcDS3231.h>                    // RTC DS3231
#include <LiquidCrystal_I2C.h>           // for IIC lcd
 
#define YEAR 0
#define MONTH 1
#define DAY 2
#define HOUR 3
#define MINUTE 4
#define SECOND 5
#define ALARM_ONE 1
#define ALARM_TWO 2
 
RtcDS3231 Rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2); // set address 0X27 & 16 chars / 2 lines
 
// make some custom characters :
#define DU 0
#define SMILEY 1
#define BELL 2
byte du[8] = { 0x18, 0x18, 0x6, 0x9, 0x8, 0x9, 0x6, 0x0 };
byte smiley[8] = { 0x0, 0x0, 0xa, 0x0, 0x0, 0x11, 0xe, 0x0 };
byte bell[8] = { 0x4, 0xe, 0xe, 0xe, 0x1f, 0x0, 0x4};
 
String daysOfWeek[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
 
const int Pin_Sel = 4;         // 選擇按鈕
const int Pin_Adj_down = 5;    // 調整按鈕 下調
const int Pin_Adj_up = 6;      // 調整按鈕 上調
// Board           int.0    int.1   int.2   int.3   int.4   int.5
// ---------------------------------------------------------------
// Uno, Ethernet    [2]     3
// Mega2560         2       3       21      20      19      18
// Leonardo         3       2       0       1       7
const int Pin_Alarm = 2;       // 鬧鐘引腳 -- 中斷引腳
#define RtcSquareWaveInterrupt 0        // UNO
 
// 時鐘參數
RtcDateTime c_dateTime;
uint16_t c_year;
uint8_t c_month, c_day, c_dayOfWeek, c_hour, c_minute, c_second;
uint8_t LCD_Col_Row_DT[6][2] = {
  {6, 0}, {0, 0}, {3, 0}, {0, 1}, {3, 1}, {6, 1}
};
 
// 鬧鐘1參數
boolean Enable_Alarm_one = false;
int8_t a1_mode, a1_dayOf, a1_hour, a1_minute, a1_second;
int8_t a1_m;
const uint8_t A1Mode[6] = { 0x00, 0x08, 0x10, 0x14, 0x16, 0x17};
 
// 鬧鐘2參數
boolean Enable_Alarm_two = false;
int8_t a2_mode, a2_dayOf, a2_hour, a2_minute;
int8_t a2_m;
const uint8_t A2Mode[5] = { 0x00, 0x04, 0x08, 0x0a, 0x0b};
 
unsigned long previousMillis = 0; // 計時 -- 程序每隔一秒刷新顯示一次
 
int8_t f_out = 0;               // 退回主界面標誌
int8_t f_tempRead = 0;          // 讀取溫度標誌
int8_t f_AlarmOne = 0;     // 鬧鐘1 已觸發標誌
int8_t f_AlarmTwo = 0;     // 鬧鐘2 已觸發標誌
boolean interuptFlag = false;   // 鬧鐘中斷觸發標誌
 
 
// 中斷觸發
void InterruptServiceRoutine() {
  interuptFlag = true;
}
 
void setup ()
{
  Serial.begin(115200);
 
  pinMode(Pin_Sel, INPUT);
  pinMode(Pin_Adj_up, INPUT);
  pinMode(Pin_Adj_down, INPUT);
 
  Serial.print("compiled: ");
  Serial.print(__DATE__);      // 編譯文檔的日期
  Serial.println(__TIME__);    // 編譯文檔的時間
 
  //--------RTC SETUP ------------
  Rtc.Begin();
 
  // if you are using ESP-01 then uncomment the line below to reset the pins to
  // the available pins for SDA, SCL
  // Wire.begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL
 
  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__); // 存儲當前編譯的時間及日期並打印
  printDateTime(compiled);
  Serial.println();
 
  if (!Rtc.IsDateTimeValid())   // 判斷時間日期是否有效(詳見數據手冊狀態寄存器第7位描述)
  {
    // Common Cuases:
    //    1) first time you ran and the device wasn't running yet
    //    2) the battery on the device is low or even missing
 
    Serial.println("RTC lost confidence in the DateTime!");
 
    // following line sets the RTC to the date & time this sketch was compiled
    // it will also reset the valid flag internally unless the Rtc device is
    // having an issue
 
    Rtc.SetDateTime(compiled);
  }
 
  if (!Rtc.GetIsRunning())
  {
    Serial.println("RTC was not actively running, starting now");
    Rtc.SetIsRunning(true);
  }
 
  RtcDateTime now = Rtc.GetDateTime();  // 獲取當前DS3231時間及日期
  if (now < compiled)
  {
    Serial.println("RTC is older than compile time!  (Updating DateTime)");
    Rtc.SetDateTime(compiled);
  }
  else if (now > compiled)
  {
    Serial.println("RTC is newer than compile time. (this is expected)");
  }
  else if (now == compiled)
  {
    Serial.println("RTC is the same as compile time! (not expected but all is fine)");
  }
 
  // never assume the Rtc was last configured by you, so
  // just clear them to your needed state
  Rtc.Enable32kHzPin(false);
  Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
 
  // setup external interupt
 
  attachInterrupt(RtcSquareWaveInterrupt, InterruptServiceRoutine, FALLING);
 
  lcd.init();                           // initialize the lcd
 
  // create a new character
  lcd.createChar(DU, du);
  lcd.createChar(SMILEY, smiley);
  lcd.createChar(BELL, bell);
 
  lcd.backlight();                      // Print a message to the LCD.
  lcd.home();
  lcd.print("YFROBOT CLOCK");
  lcd.setCursor(0, 1);
  lcd.print("WWW.YFROBOT.COM");
  delay(3000);
 
  lcd.clear();
}
 
#define countof(a) (sizeof(a) / sizeof(a[0]))
 
// 串口打印日期時間
void printDateTime(const RtcDateTime& dt)
{
  char datestring[20];
 
  snprintf_P(datestring, countof(datestring), PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
             dt.Month(), dt.Day(), dt.Year(),
             dt.Hour(), dt.Minute(), dt.Second() );
  Serial.print(datestring);
}
 
void printEmpty(int8_t cou) {
  String empty = "";
  for (int i = 0; i < cou; i++) {
    empty += ' ';
  }
  lcd.print(empty);
}
 
// LCD 輸出日期時間
void displayDateTime(const RtcDateTime& dt) {
  lcd.home();
 
  if (dt.Month() < 10)
    lcd.print("0");
 
  lcd.print(dt.Month(), DEC);
 
  lcd.print('/');
 
  if (dt.Day() < 10)
    lcd.print("0");
 
  lcd.print(dt.Day(), DEC);
 
  lcd.print('/');
  lcd.print(dt.Year(), DEC);
 
  lcd.setCursor(15, 0);
  lcd.write(SMILEY);
 
  lcd.setCursor(0, 1);
 
  if (dt.Hour() < 10)
    lcd.print("0");
 
  lcd.print(dt.Hour(), DEC);
  lcd.print(':');
 
  if (dt.Minute() < 10)
    lcd.print("0");
 
  lcd.print(dt.Minute(), DEC);
  lcd.print(':');
 
  if (dt.Second() < 10)
    lcd.print("0");
 
  lcd.print(dt.Second(), DEC);
 
}
// LCD 輸出星期
void displayDayWeek(const RtcDateTime& dt) {
  lcd.setCursor(11, 0);
  lcd.print(daysOfWeek[dt.DayOfWeek()]);
}
// LCD 輸出溫度
void displayTemp(const RtcTemperature& te) {
  lcd.setCursor(12, 1);
  printEmpty(4);
  lcd.setCursor(12, 1);
  if (int(te.AsFloat()) < 100 && int(te.AsFloat()) >= 0)
    printEmpty(1);
  lcd.print(int(te.AsFloat()));
  lcd.setCursor(15, 1);
  lcd.write(DU);  // 寫單位
}
 
// 讀取按鍵
unsigned long LastTime;
boolean BtnPress(int btn) {
  if (digitalRead(btn) == HIGH) {               // check button press
    if (millis() - LastTime >= 500) {
      LastTime = millis();
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
}
 
// 顯示數字
void AdjustDisplay(uint8_t c_item , uint8_t col, uint8_t row) {
  lcd.setCursor(col, row);
  if (c_item < 10)
    lcd.print("0");
  lcd.print(c_item);
}
 
// 調整-閃爍
void AdjustDisplayBlink(uint8_t c_item , uint8_t col, uint8_t row) {
  unsigned long WT = millis() % 1000;
  lcd.setCursor(col, row);
  if (WT < 500) {
    printEmpty(2);
  } else {
    if (c_item < 10)
      lcd.print("0");
    lcd.print(c_item);
  }
}
 
// 上調下調按鍵調節
int8_t AdjustData(int8_t c_item, int8_t cmin, int8_t cmax) {
  if (BtnPress(Pin_Adj_up)) {
    c_item += 1;
    if (c_item > cmax)
      c_item = cmin;
  }
  if (BtnPress(Pin_Adj_down)) {
    c_item -= 1;
    if (c_item < cmin)
      c_item = cmax;
  }
  return c_item;
}
 
// 界面-閃爍
void S_DisplayBlink(String c_item, uint8_t col, uint8_t row) {
  unsigned long WT = millis() % 1000;
  lcd.setCursor(col, row);
  if (WT < 500) {
    printEmpty(c_item.length());
    //    Serial.print(c_item.length());
  } else {
    lcd.print(c_item);
  }
}
 
// 鬧鐘標誌
void displayBell(boolean bellOn) {
  if (bellOn) {
    lcd.setCursor(9, 1);
    lcd.write(BELL);  // 寫單位
  }
}
 
// 鬧鐘執行
void displayBellAlarm() {
  if (interuptFlag) {
    interuptFlag = false; // reset the flag
 
    // this gives us which alarms triggered and then allows for others to trigger again
    DS3231AlarmFlag flag = Rtc.LatchAlarmsTriggeredFlags();
    if ((flag & DS3231AlarmFlag_Alarm1) && Rtc.IsEnableAlarmOne()) {
      f_AlarmOne = 1;
      lcd.setCursor(10, 1);
      printEmpty(1);
      lcd.setCursor(10, 1);
      lcd.print(1);  // 輸出鬧鐘標誌
      Serial.println("111111");
    }
    if ((flag & DS3231AlarmFlag_Alarm2) && Rtc.IsEnableAlarmTwo()) {
      f_AlarmTwo = 1;
      //      lcd.setCursor(11, 1);
      //      printEmpty(1);
      lcd.setCursor(11, 1);
      lcd.print(2);  // 輸出鬧鐘標誌
      Serial.println("222222");
    }
  }
}
 
// 清除鬧鐘
void clearBellAlarm(int8_t Bell) {
  if (Bell == ALARM_ONE) {
    lcd.setCursor(10, 1);
    printEmpty(1);
  } else if (Bell == ALARM_TWO) {
    lcd.setCursor(11, 1);
    printEmpty(1);
  }
}
 
// lcd Print
void D_lcdPrint(uint8_t c_item, uint8_t col, uint8_t row) {
  lcd.setCursor(col, row);
  lcd.print(c_item);
}
 
// lcd Print
void D_lcdPrint(String c_item, uint8_t col, uint8_t row) {
  lcd.setCursor(col, row);
  lcd.print(c_item);
}
 
 
// 初始化調整時鐘參數
void InitAdjPer(const RtcDateTime& dt) {
  c_year = dt.Year();
  c_month = dt.Month();
  c_day = dt.Day();
  c_hour = dt.Hour();
  c_minute = dt.Minute();
  c_second = dt.Second();
}
 
// 進入設置時鐘界面
void SetTime() {
  /************ set year *************/
  lcd.clear();
  c_dateTime = Rtc.GetDateTime();
  InitAdjPer(c_dateTime);
  boolean F_Year = true;
  displayDateTime(c_dateTime);
  while (true) {
    unsigned long WT = millis() % 1000;
    if (WT < 500) {
      lcd.setCursor(6, 0);
      printEmpty(4);
    } else {
      lcd.setCursor(6, 0);
      lcd.print(c_year);
    }
    if (BtnPress(Pin_Adj_up)) {
      c_year += 1;
    }
    if (BtnPress(Pin_Adj_down)) {
      c_year -= 1;
    }
    /************ set month *************/
    if (BtnPress(Pin_Sel)) {
      lcd.setCursor(LCD_Col_Row_DT[YEAR][0], LCD_Col_Row_DT[YEAR][1]);
      lcd.print(c_year);
      while (true) {
        AdjustDisplayBlink(c_month, LCD_Col_Row_DT[MONTH][0], LCD_Col_Row_DT[MONTH][1]);
        c_month = AdjustData(c_month, 1, 12);
        /************ set day *************/
        if (BtnPress(Pin_Sel)) {
          AdjustDisplay(c_month, LCD_Col_Row_DT[MONTH][0], LCD_Col_Row_DT[MONTH][1]);
          while (true) {
            AdjustDisplayBlink(c_day, LCD_Col_Row_DT[DAY][0], LCD_Col_Row_DT[DAY][1]);
            uint8_t c_daysInMon = pgm_read_byte_near(c_daysInMonth + c_month - 1);
            //  [url=https://www.arduino.cc/en/Reference/PROGMEM]https://www.arduino.cc/en/Reference/PROGMEM[/url]
            //  [url=http://www.yfrobot.com/wiki/index.php?title=PROGMEM]http://www.yfrobot.com/wiki/index.php?title=PROGMEM[/url]
            //  [url=http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html]http://www.nongnu.org/avr-libc/u ... _avr__pgmspace.html[/url]
            c_day = AdjustData(c_day, 1, c_daysInMon);
            //            Serial.print("\t");
            //            Serial.println(  c_daysInMon);
            /************ set hour *************/
            if (BtnPress(Pin_Sel)) {
              AdjustDisplay(c_day, LCD_Col_Row_DT[DAY][0], LCD_Col_Row_DT[DAY][1]);
              while (true) {
                AdjustDisplayBlink(c_hour, LCD_Col_Row_DT[HOUR][0], LCD_Col_Row_DT[HOUR][1]);
                c_hour = AdjustData(c_hour, 0, 23);
                /************ set minute *************/
                if (BtnPress(Pin_Sel)) {
                  AdjustDisplay(c_hour, LCD_Col_Row_DT[HOUR][0], LCD_Col_Row_DT[HOUR][1]);
                  while (true) {
                    AdjustDisplayBlink(c_minute, LCD_Col_Row_DT[MINUTE][0], LCD_Col_Row_DT[MINUTE][1]);
                    c_minute = AdjustData(c_minute, 0, 59);
                    /************ set second *************/
                    if (BtnPress(Pin_Sel)) {
                      AdjustDisplay(c_minute, LCD_Col_Row_DT[MINUTE][0], LCD_Col_Row_DT[MINUTE][1]);
                      while (true) {
                        AdjustDisplayBlink(c_second, LCD_Col_Row_DT[SECOND][0], LCD_Col_Row_DT[SECOND][1]);
                        c_second = AdjustData(c_second, 0, 59);
                        /************ Sure set *************/
                        if (BtnPress(Pin_Sel)) {  // sure set
                          f_out = 1;       // 確認進入設置時鐘界面標誌
                          lcd.clear();
                          D_lcdPrint("Sure to Change!", 0, 0);
                          //                          S_DisplayBlink("YES", 3, 1);
                          //                          D_lcdPrint("NO", 8, 1);
                          boolean YesorNo = true;
                          while (true) {
                            if (BtnPress(Pin_Adj_up) || BtnPress(Pin_Adj_down)) {
                              YesorNo = !YesorNo;
                            }
                            if (YesorNo) {
                              D_lcdPrint("NO", 8, 1);
                              S_DisplayBlink("YES", 3, 1);
                            } else {
                              D_lcdPrint("YES", 3, 1);
                              S_DisplayBlink("NO", 8, 1);
                            }
                            if (YesorNo && BtnPress(Pin_Sel)) {  // out set -- ok or cancel
                              lcd.clear();
                              RtcDateTime now_dataTime(c_year, c_month, c_day, c_hour, c_minute, c_second);
                              c_dateTime = now_dataTime;
                              Rtc.SetDateTime(c_dateTime);
                              return;
                            } else if (!YesorNo && BtnPress(Pin_Sel)) {
                              lcd.clear();
                              return;
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
 
// 進入設置鬧鐘界面
void SelAlarms() {
  /************ select alarms *************/
  lcd.clear();
  int8_t alarms_list = 0;
  int8_t alarms_display = 0;
 
  while (true) {
    if (BtnPress(Pin_Adj_up)) {
      alarms_list++;
      if (alarms_list >= 3) {
        alarms_list = 0;
      }
      alarms_display = alarms_list;
    } else if (BtnPress(Pin_Adj_down)) {
      alarms_list--;
      if (alarms_list < 0) {
        alarms_list = 2;
      }
      alarms_display = alarms_list;
    }
    if (alarms_list == 0 ) {
      if (alarms_display == 0) {
        D_lcdPrint("Set Alarms!", 0, 0);
        D_lcdPrint("A_2", 6, 1);
        D_lcdPrint("EXIT", 11, 1);
        alarms_display = -1;
      }
      S_DisplayBlink("A_1", 1, 1);
    } else if (alarms_list == 1) {
      if (alarms_display == 1 ) {
        D_lcdPrint("Set Alarms!", 0, 0);
        D_lcdPrint("A_1", 1, 1);
        D_lcdPrint("EXIT", 11, 1);
        alarms_display = -1;
      }
      S_DisplayBlink("A_2", 6, 1);
    } else if (alarms_list == 2) {
      if (alarms_display == 2) {
        D_lcdPrint("Set Alarms!", 0, 0);
        D_lcdPrint("A_1", 1, 1);
        D_lcdPrint("A_2", 6, 1);
        alarms_display = -1;
      }
      S_DisplayBlink("EXIT", 11, 1);
    }
    if (alarms_list == 0 && BtnPress(Pin_Sel)) {  // out set -- ok or cancel
      SetAlarms_One();
      alarms_display = 0;
    } else if (alarms_list == 1 && BtnPress(Pin_Sel)) {
      SetAlarms_Two();
      alarms_display = 1;
    } else if (alarms_list == 2 && BtnPress(Pin_Sel)) {
      lcd.clear();
      f_out = 1;          //退回主界面
      return;
    }
  }
}
 
// 進入鬧鐘一設置界面
void SetAlarms_One() {
  lcd.clear();
  lcd.print("A one");
  lcd.setCursor(12, 0);
  if (Enable_Alarm_one) {
    lcd.print("ON ");
  } else {
    lcd.print("OFF");
  }
  DS3231AlarmOne c_alarmOne = Rtc.GetAlarmOne();
  a1_mode = c_alarmOne.ControlFlags();
  for (int i = 0; i < sizeof(A1Mode); i++) {
    if (a1_mode == A1Mode[i]) {
      a1_m = i;
      break;
    }
  }
  /* a1 mode
     0x00  DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch
     0x08  DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch
     0x10  DS3231AlarmOneControl_HoursMinutesSecondsMatch
     0x14  DS3231AlarmOneControl_MinutesSecondsMatch
     0x16  DS3231AlarmOneControl_SecondsMatch
     0x17  DS3231AlarmOneControl_OncePerSecond
  */
  a1_dayOf = c_alarmOne.DayOf();
  a1_hour = c_alarmOne.Hour();
  a1_minute = c_alarmOne.Minute();
  a1_second = c_alarmOne.Second();
  Serial.println(a1_mode);
  Serial.println(a1_dayOf);
  Serial.println(a1_hour);
  Serial.println(a1_minute);
  Serial.println(a1_second);
  lcd.setCursor(1, 1);
  if (a1_mode < 10)
    lcd.print("0");
  lcd.print(a1_mode);
  lcd.setCursor(4, 1);
  if (a1_dayOf < 10)
    lcd.print("0");
  lcd.print(a1_dayOf);
  lcd.setCursor(7, 1);
  if (a1_hour < 10)
    lcd.print("0");
  lcd.print(a1_hour);
  lcd.setCursor(10, 1);
  if (a1_minute < 10)
    lcd.print("0");
  lcd.print(a1_minute);
  lcd.setCursor(13, 1);
  if (a1_second < 10)
    lcd.print("0");
  lcd.print(a1_second);
 
  int8_t c_a1 = 0;
  while (true) {
    c_a1 = AdjustData(c_a1, 0, 1);
    if (c_a1 == 0) {
      S_DisplayBlink("A one", 0, 0);
    } else if (c_a1 == 1) {
      D_lcdPrint("A one", 0, 0);
      if (Enable_Alarm_one) {
        S_DisplayBlink("ON ", 12, 0);
      } else {
        S_DisplayBlink("OFF", 12, 0);
      }
      if (BtnPress(Pin_Adj_up) || BtnPress(Pin_Adj_down)) {
        Enable_Alarm_one = !Enable_Alarm_one;
      }
      if (BtnPress(Pin_Sel)) {  // out set
        if (Enable_Alarm_one) {
          Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmOne);
          DS3231AlarmOne alarm1(a1_dayOf, a1_hour, a1_minute, a1_second, a1_mode);
          Rtc.SetAlarmOne(alarm1);
          // throw away any old alarm state before we ran
          Rtc.LatchAlarmsTriggeredFlags();
        } else {
          Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmOne_Off);
        }
        lcd.clear();
        return;
      }
    }
    if (BtnPress(Pin_Sel)) {
      D_lcdPrint("A one", 0, 0);
      while (true) {
        AdjustDisplayBlink(a1_mode, 1, 1);
        a1_m = AdjustData(a1_m, 0, 5);
        a1_mode = A1Mode[a1_m];
        if (BtnPress(Pin_Sel)) {  // set day of month of week
          AdjustDisplay(a1_mode, 1, 1);
          while (true) {
            AdjustDisplayBlink(a1_dayOf, 4, 1);
            if (a1_mode == 0) {
              uint8_t c_daysInMon = pgm_read_byte_near(c_daysInMonth + a1_mode - 1);
              //  [url=https://www.arduino.cc/en/Reference/PROGMEM]https://www.arduino.cc/en/Reference/PROGMEM[/url]
              //  [url=http://www.yfrobot.com/wiki/index.php?title=PROGMEM]http://www.yfrobot.com/wiki/index.php?title=PROGMEM[/url]
              //  [url=http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html]http://www.nongnu.org/avr-libc/u ... _avr__pgmspace.html[/url]
              a1_dayOf = AdjustData(a1_dayOf, 1, c_daysInMon);
            } else if (a1_mode == 1) {
              a1_dayOf = AdjustData(a1_dayOf, 0, 6);
            }
            if (BtnPress(Pin_Sel)) {  // set hour
              AdjustDisplay(a1_dayOf, 4, 1);
              while (true) {
                AdjustDisplayBlink(a1_hour, 7, 1);
                a1_hour = AdjustData(a1_hour, 0, 23);
                if (BtnPress(Pin_Sel)) {  // set minute
                  AdjustDisplay(a1_hour, 7, 1);
                  while (true) {
                    AdjustDisplayBlink(a1_minute, 10, 1);
                    a1_minute = AdjustData(a1_minute, 0, 59);
                    if (BtnPress(Pin_Sel)) {  // set second
                      AdjustDisplay(a1_minute, 10, 1);
                      while (true) {
                        AdjustDisplayBlink(a1_second, 13, 1);
                        a1_second = AdjustData(a1_second, 0, 59);
                        if (BtnPress(Pin_Sel)) {  // turn on or off
                          AdjustDisplay(a1_second, 13, 1);
                          while (true) {
                            if (Enable_Alarm_one) {
                              S_DisplayBlink("ON ", 12, 0);
                            } else {
                              S_DisplayBlink("OFF", 12, 0);
                            }
                            if (BtnPress(Pin_Adj_up) || BtnPress(Pin_Adj_down)) {
                              Enable_Alarm_one = !Enable_Alarm_one;
                            }
                            if (BtnPress(Pin_Sel)) {  // out set
                              if (Enable_Alarm_one) {
                                Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmOne);
                                DS3231AlarmOne alarm1(a1_dayOf, a1_hour, a1_minute, a1_second, a1_mode);
                                Rtc.SetAlarmOne(alarm1);
                                // throw away any old alarm state before we ran
                                Rtc.LatchAlarmsTriggeredFlags();
                              } else {
                                Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmOne_Off);
                              }
                              lcd.clear();
                              return;
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
 
// 進入鬧鐘二設置界面
void SetAlarms_Two() {
  lcd.clear();
  lcd.print("A two");
  lcd.setCursor(12, 0);
  if (Enable_Alarm_two) {
    lcd.print("ON ");
  } else {
    lcd.print("OFF");
  }
  DS3231AlarmTwo c_alarmTwo = Rtc.GetAlarmTwo();
  a2_mode = c_alarmTwo.ControlFlags();
  for (int i = 0; i < sizeof(A2Mode); i++) {
    if (a2_mode == A2Mode[i]) {
      a2_m = i;
      break;
    }
  }
  /* a2 mode
     0x00  DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch
     0x04  DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch
     0x08  DS3231AlarmTwoControl_HoursMinutesMatch
     0x0a  DS3231AlarmTwoControl_MinutesMatch
     0x0b  DS3231AlarmTwoControl_OncePerMinute
  */
  a2_dayOf = c_alarmTwo.DayOf();
  a2_hour = c_alarmTwo.Hour();
  a2_minute = c_alarmTwo.Minute();
  Serial.println(a2_mode);
  Serial.println(a2_dayOf);
  Serial.println(a2_hour);
  Serial.println(a2_minute);
  lcd.setCursor(1, 1);
  if (a2_mode < 10)
    lcd.print("0");
  lcd.print(a2_mode);
  lcd.setCursor(4, 1);
  if (a2_dayOf < 10)
    lcd.print("0");
  lcd.print(a2_dayOf);
  lcd.setCursor(7, 1);
  if (a2_hour < 10)
    lcd.print("0");
  lcd.print(a2_hour);
  lcd.setCursor(10, 1);
  if (a2_minute < 10)
    lcd.print("0");
  lcd.print(a2_minute);
  int8_t c_a2 = 0;
  while (true) {
    c_a2 = AdjustData(c_a2, 0, 1);
    if (c_a2 == 0) {
      S_DisplayBlink("A two", 0, 0);
    } else if (c_a2 == 1) {
      D_lcdPrint("A two", 0, 0);
      if (Enable_Alarm_two) {
        S_DisplayBlink("ON ", 12, 0);
      } else {
        S_DisplayBlink("OFF", 12, 0);
      }
      if (BtnPress(Pin_Adj_up) || BtnPress(Pin_Adj_down)) {
        Enable_Alarm_two = !Enable_Alarm_two;
      }
      if (BtnPress(Pin_Sel)) {  // out set
        if (Enable_Alarm_two) {
          Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmTwo);
          DS3231AlarmTwo alarm2(a2_dayOf, a2_hour, a2_minute, a2_mode);
          Rtc.SetAlarmTwo(alarm2);
          // throw away any old alarm state before we ran
          Rtc.LatchAlarmsTriggeredFlags();
        } else {
          Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmTwo_Off);
        }
        lcd.clear();
        return;
      }
    }
    if (BtnPress(Pin_Sel)) {
      D_lcdPrint("A two", 0, 0);
      while (true) {
        AdjustDisplayBlink(a2_mode, 1, 1);
        a2_m = AdjustData(a2_m, 0, 4);
        a2_mode = A2Mode[a2_m];
        if (BtnPress(Pin_Sel)) {  // set day
          AdjustDisplay(a2_mode, 1, 1);
          while (true) {
            AdjustDisplayBlink(a2_dayOf, 4, 1);
            if (a2_m == 0) {
              uint8_t c_daysInMon = pgm_read_byte_near(c_daysInMonth + a2_mode - 1);
              //  [url=https://www.arduino.cc/en/Reference/PROGMEM]https://www.arduino.cc/en/Reference/PROGMEM[/url]
              //  [url=http://www.yfrobot.com/wiki/index.php?title=PROGMEM]http://www.yfrobot.com/wiki/index.php?title=PROGMEM[/url]
              //  [url=http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html]http://www.nongnu.org/avr-libc/u ... _avr__pgmspace.html[/url]
              a2_dayOf = AdjustData(a2_dayOf, 1, c_daysInMon);
            } else if (a2_m == 1) {
              a2_dayOf = AdjustData(a2_dayOf, 0, 6);
            }
            if (BtnPress(Pin_Sel)) {  // set hour
              AdjustDisplay(a2_dayOf, 4, 1);
              while (true) {
                AdjustDisplayBlink(a2_hour, 7, 1);
                a2_hour = AdjustData(a2_hour, 0, 23);
                if (BtnPress(Pin_Sel)) {  // set minute
                  AdjustDisplay(a2_hour, 7, 1);
                  while (true) {
                    AdjustDisplayBlink(a2_minute, 10, 1);
                    a2_minute = AdjustData(a2_minute, 0, 59);
                    if (BtnPress(Pin_Sel)) {  // turn on or off
                      AdjustDisplay(a2_minute, 10, 1);
                      while (true) {
                        if (Enable_Alarm_two) {
                          S_DisplayBlink("ON ", 12, 0);
                        } else {
                          S_DisplayBlink("OFF", 12, 0);
                        }
                        if (BtnPress(Pin_Adj_up) || BtnPress(Pin_Adj_down)) {
                          Enable_Alarm_two = !Enable_Alarm_two;
                        }
                        if (BtnPress(Pin_Sel)) {  // out set
                          if (Enable_Alarm_two) {
                            Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmTwo);
                            DS3231AlarmTwo alarm2(a2_dayOf, a2_hour, a2_minute, a2_mode);
                            Rtc.SetAlarmTwo(alarm2);
                            // throw away any old alarm state before we ran
                            Rtc.LatchAlarmsTriggeredFlags();
                          } else {
                            Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmTwo_Off);
                          }
                          Serial.println(Enable_Alarm_two);
                          lcd.clear();
                          return;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
 
// 進入設置選擇界面
void Settings() {
  if (BtnPress(Pin_Sel)) {
    f_tempRead = 0;  // 溫度顯示標誌 -- 進入Set系統後,返回主界面依然顯示溫度
    lcd.clear();
    int8_t c_setting = 0;
    int8_t c_display = 0;
    while (true) {
      //上下調節按鍵
      if (BtnPress(Pin_Adj_up)) {
        c_setting ++;
        if (c_setting >= 3) {
          c_setting = 0;
        }
        c_display = c_setting;
      } else if (BtnPress(Pin_Adj_down)) {
        c_setting --;
        if (c_setting < 0) {
          c_setting = 2;
        }
        c_display = c_setting;
      }
      if (c_setting == 0) {
        if (c_display == 0) {
          D_lcdPrint("Select One!", 0, 0);
          D_lcdPrint("ALARM", 6, 1);
          D_lcdPrint("EXIT", 12, 1);
          Serial.println("test");
          c_display = -1;
        }
        S_DisplayBlink("TIME", 0, 1);
      } else if (c_setting == 1) {
        if (c_display == 1) {
          D_lcdPrint("Select One!", 0, 0);
          D_lcdPrint("TIME", 0, 1);
          D_lcdPrint("EXIT", 12, 1);
          c_display = -1;
        }
        S_DisplayBlink("ALARM", 6, 1);
      } else if (c_setting == 2) {
        if (c_display == 2) {
          D_lcdPrint("Select One!", 0, 0);
          D_lcdPrint("TIME", 0, 1);
          D_lcdPrint("ALARM", 6, 1);
          c_display = -1;
        }
        S_DisplayBlink("EXIT", 12, 1);
      }
      if (c_setting == 0 && BtnPress(Pin_Sel)) {
        SetTime();
        c_display = 0;
      } else if (c_setting == 1 && BtnPress(Pin_Sel)) {
        SelAlarms();
        c_display = 1;
      } else if ((c_setting == 2 && BtnPress(Pin_Sel)) || f_out != 0) { // out set -- ok or cancel
        f_out = 0;   // 恢復標誌
        lcd.clear();
        return;
      }
    }
  }
}
 
 
void loop () {
  if (!Rtc.IsDateTimeValid())
  {
    // Common Cuases:
    //    1) the battery on the device is low or even missing and the power line was disconnected
    Serial.println("RTC lost confidence in the DateTime!");
  }
 
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 1000) {  // 每1000ms執行一次
    RtcDateTime now = Rtc.GetDateTime();
    printDateTime(now);
    Serial.println();
    displayDateTime(now);
    displayDayWeek(now);
    displayBell((Enable_Alarm_one || Enable_Alarm_two));  // 鬧鐘標誌
    displayBellAlarm(); // 鬧鐘響鈴
 
    // 每64秒讀取溫度一次
    if (f_tempRead == 0) {
      //輸出溫度 -- 溫度每64秒更新一次 / 精度±3°C
      RtcTemperature temp = Rtc.GetTemperature();
      Serial.print("Temp:");
      Serial.print(temp.AsFloat());
      Serial.println("C");
      displayTemp(temp);
    }
    f_tempRead ++;
    if (f_tempRead == 63) {
      f_tempRead = 0;
    }
 
    // 鬧鐘響鈴後30s,清除屏幕標誌
    if (f_AlarmOne) {
      f_AlarmOne ++;
      if (f_AlarmOne >= 30) {
        clearBellAlarm(ALARM_ONE);
        f_AlarmOne = 0;
      }
    }
    // 鬧鐘響鈴後30s,清除屏幕標誌
    if (f_AlarmTwo) {
      f_AlarmTwo++;
      if (f_AlarmTwo >= 30) {
        clearBellAlarm(ALARM_TWO);
        f_AlarmTwo = 0;
      }
    }
 
    previousMillis = currentMillis;
  }
  Settings();
}

功能實現:
實時顯示日期時間、星期、溫度、鬧鐘!

視頻:http://v.youku.com/v_show/id_XMTg3NTQwMTM4MA==.html

arduino RTC DS3231 實時時鐘

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章