YFROBOT创客社区

标题: arduino-基于DS3231多功能(手动校时/闹钟/温显)RTC(实时时钟)制作-IIC1602显示 [打印本页]

作者: AllBlue    时间: 2016-12-21 10:43
标题: arduino-基于DS3231多功能(手动校时/闹钟/温显)RTC(实时时钟)制作-IIC1602显示
最近拿到实时时钟模块DS3231,可能很多人不知道这个芯片,这个芯片号称(数据手册)年误差可以做到小于两分钟的高精度时钟芯片;不过玩过DS1302的同学都知道确实精度很差,有时一天误差好几秒
简单总结下DS3231:
DS3231是低成本、高精度I2C实时时钟(RTC),具有集成的温补晶振(TCXO)和晶体,具有以下特性:
* 实时时钟产生秒、分、时、星期、日期、月和年计时,并提供有效期到2100年的闰年补偿
* 两个日历闹钟
* 可编程方波输出
* IIC总线接口
* 备份电池输入
* 温度输出(注意:温度64秒更新一次 --- 在VCC初次上电或Vbat供电下首次进行IIC通信时,开始读取温度值,之后每64秒读取一次)
......-
更多详细可以参考数据手册:
http://yfrobot.gitee.io/wiki/doc/DS3231.pdf
http://yfrobot.gitee.io/wiki/doc/DS3231_cn.pdf

下面是我使用RTC3231时钟模块做的小项目:桌面时钟
首先需要用到的器件:
1、主板arduino
2、RTC3231模块
3、IIC1602液晶
4、3按键
电路连接:
提示:使用闹钟功能时,需要连接中断引脚(UNO为例)D2 到DS3231模块 INT/SQW引脚 ;不使用时不连接也可以
Arduino(UNO R3) DS3231 IIC1602
VCC VCC VCC
GND GND GND
A4/SDA SDA SDA
A5/SCL SCL SCL
D2(中断) INT/SQW X
D4,D5,D6 连接按键。。。

示例程序:
需要用到库文件:RtcDS3231库 -- 库介绍
本站下载地址:[attach]1691[/attach]
程序下载:[attach]2460[/attach]
[C] 纯文本查看 复制代码
/* 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: http://www.yfrobot.com.cn/wiki/index.php?title=RTC_3231
   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);
            //  https://www.arduino.cc/en/Reference/PROGMEM
            //  http://www.yfrobot.com.cn/wiki/index.php?title=PROGMEM
            //  http://www.nongnu.org/avr-libc/u ... _avr__pgmspace.html
            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) {
      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);
              //  https://www.arduino.cc/en/Reference/PROGMEM
              //  http://www.yfrobot.com.cn/wiki/index.php?title=PROGMEM
              //  http://www.nongnu.org/avr-libc/u ... _avr__pgmspace.html
              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) {
      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);
              //  https://www.arduino.cc/en/Reference/PROGMEM
              //  http://www.yfrobot.com.cn/wiki/index.php?title=PROGMEM
              //  http://www.nongnu.org/avr-libc/u ... _avr__pgmspace.html
              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();
}


功能实现:
实时显示日期时间、星期、温度、闹钟!
[attach]1696[/attach]
视频:http://v.youku.com/v_show/id_XMTg3NTQwMTM4MA==.html
[vedio=375,500]https://player.youku.com/embed/XMTg3NTQwMTM4MA==[/vedio]


菜单详情:
PDF下载:[attach]1695[/attach]


[attach]1694[/attach]

流程图在线制作:点击查看


作者: 0storm0    时间: 2017-5-10 13:01
编译的时候显示错误
作者: 0storm0    时间: 2017-5-10 18:25
0storm0 发表于 2017-5-10 13:01
编译的时候显示错误

是我编译器有问题,换个电脑就好了,估计是库装的太多乱了
作者: AllBlue    时间: 2017-5-11 19:09
0storm0 发表于 2017-5-10 18:25
是我编译器有问题,换个电脑就好了,估计是库装的太多乱了

恩,库安装好就可以了
作者: 困了睡    时间: 2017-5-29 16:09
我连接好代码上传成功了,为什么lcd1602上面没有显示呢
作者: 困了睡    时间: 2017-5-29 16:12
电路这个样子的

作者: AllBlue    时间: 2017-5-31 08:03
困了睡 发表于 2017-5-29 16:12
电路这个样子的

你单独测试IIC液晶,液晶是否可以显示正常,如果不正常看下面的贴子:
http://www.yfrobot.com/thread-11812-1-1.html
作者: 困了睡    时间: 2017-5-31 18:21
AllBlue 发表于 2017-5-31 08:03
你单独测试IIC液晶,液晶是否可以显示正常,如果不正常看下面的贴子:
http://www.yfrobot.com/thread-1 ...

已经把0x27改为0x3f,可是显示的很乱,如图片,也一直在闪烁

作者: AllBlue    时间: 2017-6-2 08:42
困了睡 发表于 2017-5-31 18:21
已经把0x27改为0x3f,可是显示的很乱,如图片,也一直在闪烁

不应该啊,这个程序都是测试过的。
现在你只有单独测试下 IIC的液晶库是否能正常用于你的液晶模块,单独测试下即可;
还有将其他按键先拆除,试试看
作者: 困了睡    时间: 2017-6-6 23:31
AllBlue 发表于 2017-6-2 08:42
不应该啊,这个程序都是测试过的。
现在你只有单独测试下 IIC的液晶库是否能正常用于你的液晶模块,单独 ...

请问怎么添加蜂鸣器

作者: AllBlue    时间: 2017-6-7 08:04
困了睡 发表于 2017-6-6 23:31
请问怎么添加蜂鸣器

在闹钟程序部分加入蜂鸣器输出就可以
作者: wumeidaozhang    时间: 2018-11-18 20:02
编译错误,是我的库有问题吗,请问楼主的Rtc DS3231用的哪个版本
作者: wumeidaozhang    时间: 2018-11-18 20:06
请问这是什么原因呢

作者: AllBlue    时间: 2018-11-19 13:15
wumeidaozhang 发表于 2018-11-18 20:02
编译错误,是我的库有问题吗,请问楼主的Rtc DS3231用的哪个版本

库文件 贴中有链接
作者: AllBlue    时间: 2018-11-19 13:16
wumeidaozhang 发表于 2018-11-18 20:06
请问这是什么原因呢

这看起来是函数哪里有问题,你看看你函数应用时参数类型有没有正确,还有参数数量

作者: aris63    时间: 2019-5-2 10:00
Hello
新版函式庫中RtcTemperature.h有更動,函式庫連結https://github.com/Makuna/Rtc,
詳見 https://github.com/Makuna/Rtc/wiki/RtcTemperature-object
把AsFloat() 改為 AsFloatDegC() 就可以了

作者: rainbowdzc    时间: 2019-5-20 15:16
如果不使用I2C 的话可不可以使用lcd1602实现功能
作者: rainbowdzc    时间: 2019-5-21 14:23
本帖最后由 AllBlue 于 2019-5-21 17:16 编辑

[attach]2247[/attach]
请问这个错误是错在哪了? 谢谢
作者: AllBlue    时间: 2019-5-21 17:16
本帖最后由 AllBlue 于 2019-5-21 17:24 编辑
rainbowdzc 发表于 2019-5-21 14:23
请问这个错误是错在哪了? 谢谢

* DS3231 库有没有下载并放置到位 ?
* displayTemp 未定义,你看看这个函数有没有?
* 看#17楼 ,库有变动 ,AsFloat()改 AsFloatDegC() ;(未测试)

https://github.com/Makuna/Rtc/wiki/RtcTemperature-object



作者: rainbowdzc    时间: 2019-5-22 14:04
AllBlue 发表于 2019-5-21 17:16
* DS3231 库有没有下载并放置到位 ?
* displayTemp 未定义,你看看这个函数有没有?
* 看#17楼 ,库有 ...

谢谢!!!!!!!!!!!!!!!
作者: rainbowdzc    时间: 2019-5-22 14:41
[attach]2248[/attach]放进库里就可以了吗?

作者: tiantianyouyou    时间: 2019-5-23 08:01
这个好,比d1302好得多
作者: rainbowdzc    时间: 2019-5-24 14:26
[attach]2249[/attach][attach]2250[/attach]为什么装了库文件还是找不到这个Wire.h的文件


作者: rainbowdzc    时间: 2019-5-24 15:04
rainbowdzc 发表于 2019-5-24 14:26
为什么装了库文件还是找不到这个Wire.h的文件

换了台电脑就好了....为什么
作者: rainbowdzc    时间: 2019-5-28 14:52
如果用lcd1602替换i2C该怎么改程序
作者: rainbowdzc    时间: 2019-5-29 15:02
为什么按键不能按照程序控制
作者: rainbowdzc    时间: 2019-5-30 11:37
rainbowdzc 发表于 2019-5-28 14:52
如果用lcd1602替换i2C该怎么改程序

但是 我的按钮却失灵了,完全不受控制,自己乱跳
作者: rainbowdzc    时间: 2019-5-30 11:41
rainbowdzc 发表于 2019-5-29 15:02
为什么按键不能按照程序控制

不 情况 比较严重 我没有接按键 但是屏幕上还是在自己切换选择
作者: rainbowdzc    时间: 2019-5-30 15:42
本帖最后由 rainbowdzc 于 2019-5-30 17:41 编辑
rainbowdzc 发表于 2019-5-30 11:37
但是 我的按钮却失灵了,完全不受控制,自己乱跳
就像这样

https://v.qq.com/x/page/v0877wccpbi.html

作者: shinlee    时间: 2019-12-26 20:12
金币哪里来的啊。。。很珍贵啊
作者: 1000din    时间: 2019-12-27 15:10
每天签到会有金币的。
作者: wang5825    时间: 2020-2-20 14:47
谢谢分享   学习一下




欢迎光临 YFROBOT创客社区 (http://yfrobot.com.cn/) Powered by Discuz! X3.1