|
| 1 | +/* |
| 2 | + RTCReset |
| 3 | +
|
| 4 | + This sketch allows to test STM32RTC after a software reset or power off |
| 5 | + with VBat. Including Alarm A and B management. |
| 6 | +
|
| 7 | + Creation 17 jan 2023 |
| 8 | + by Frederic Pillon for STMicroelectronics |
| 9 | +
|
| 10 | + This example code is in the public domain. |
| 11 | +
|
| 12 | + https://github.com/stm32duino/STM32RTC |
| 13 | +
|
| 14 | +*/ |
| 15 | +#include <STM32RTC.h> |
| 16 | + |
| 17 | +/* Get the rtc object */ |
| 18 | +STM32RTC& rtc = STM32RTC::getInstance(); |
| 19 | + |
| 20 | +/* Change these values to set the current initial time |
| 21 | +
|
| 22 | + format: date: "Dec 31 2022" and time: "23:59:56" |
| 23 | + by default use built date and time |
| 24 | +*/ |
| 25 | +static const char* mydate = __DATE__; |
| 26 | +static const char* mytime = __TIME__; |
| 27 | +//static const char* mydate = "Dec 31 2022"; |
| 28 | +//static const char* mytime = "23:59:56"; |
| 29 | + |
| 30 | +/* Declare it volatile since it's incremented inside an interrupt */ |
| 31 | +volatile int alarmMatch_counter = 0; |
| 32 | +volatile int alarmMatchB_counter = 0; |
| 33 | + |
| 34 | +typedef struct { |
| 35 | + uint32_t next; |
| 36 | + bool alarm_a; |
| 37 | +} cb_data_t; |
| 38 | + |
| 39 | +static cb_data_t atime = { 2222, true}; |
| 40 | +#ifdef RTC_ALARM_B |
| 41 | +static cb_data_t btime = { 3333, false}; |
| 42 | +#endif |
| 43 | +static byte seconds = 0; |
| 44 | +static byte minutes = 0; |
| 45 | +static byte hours = 0; |
| 46 | +static uint32_t subSeconds = 0; |
| 47 | + |
| 48 | +static byte weekDay = 1; |
| 49 | +static byte day = 0; |
| 50 | +static byte month = 0; |
| 51 | +static byte year = 0; |
| 52 | +static STM32RTC::Hour_Format hourFormat = STM32RTC::HOUR_24; |
| 53 | +static STM32RTC::AM_PM period = STM32RTC::AM; |
| 54 | + |
| 55 | +#ifndef USER_BTN |
| 56 | +#define USER_BTN PA0 |
| 57 | +#endif |
| 58 | + |
| 59 | +static uint8_t conv2d(const char* p) { |
| 60 | + uint8_t v = 0; |
| 61 | + if ('0' <= *p && *p <= '9') |
| 62 | + v = *p - '0'; |
| 63 | + return 10 * v + *++p - '0'; |
| 64 | +} |
| 65 | + |
| 66 | +// sample input: date = "Dec 26 2009", time = "12:34:56" |
| 67 | +void initDateTime (void) { |
| 68 | + Serial.printf("Build date & time %s, %s\n", mydate, mytime); |
| 69 | + |
| 70 | + year = conv2d(mydate + 9); |
| 71 | + // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec |
| 72 | + switch (mydate[0]) { |
| 73 | + case 'J': month = (mydate[1] == 'a') ? 1 : ((mydate[2] == 'n') ? 6 : 7); break; |
| 74 | + case 'F': month = 2; break; |
| 75 | + case 'A': month = mydate[2] == 'r' ? 4 : 8; break; |
| 76 | + case 'M': month = mydate[2] == 'r' ? 3 : 5; break; |
| 77 | + case 'S': month = 9; break; |
| 78 | + case 'O': month = 10; break; |
| 79 | + case 'N': month = 11; break; |
| 80 | + case 'D': month = 12; break; |
| 81 | + } |
| 82 | + day = conv2d(mydate + 4); |
| 83 | + hours = conv2d(mytime); |
| 84 | + if (hourFormat == rtc.HOUR_12) { |
| 85 | + period = hours >= 12 ? rtc.PM : rtc.AM; |
| 86 | + hours = hours >= 13 ? hours - 12 : (hours < 1 ? hours + 12 : hours); |
| 87 | + } |
| 88 | + minutes = conv2d(mytime + 3); |
| 89 | + seconds = conv2d(mytime + 6); |
| 90 | +} |
| 91 | + |
| 92 | +void setup() |
| 93 | +{ |
| 94 | + pinMode(USER_BTN, INPUT_PULLUP); |
| 95 | + int32_t default_state = digitalRead(USER_BTN); |
| 96 | + |
| 97 | + Serial.begin(9600); |
| 98 | + while (!Serial); |
| 99 | + // Wait user input to start |
| 100 | + while (digitalRead(USER_BTN) == default_state); |
| 101 | + // Convenient function to init date and time variables |
| 102 | + initDateTime(); |
| 103 | + |
| 104 | + // Select RTC clock source: LSI_CLOCK, LSE_CLOCK or HSE_CLOCK. |
| 105 | + // By default the LSI is selected as source. |
| 106 | + // rtc.setClockSource(STM32RTC::LSE_CLOCK); |
| 107 | + |
| 108 | + // In any case attach a callback to the RTC alarm interrupt. |
| 109 | + rtc.attachInterrupt(alarmMatch, &atime); |
| 110 | +#ifdef RTC_ALARM_B |
| 111 | + rtc.attachInterrupt(alarmMatch, &btime, STM32RTC::ALARM_B); |
| 112 | +#endif |
| 113 | + rtc.begin(); // Initialize RTC 24H format |
| 114 | + if (!rtc.isTimeSet()) { |
| 115 | + Serial.printf("RTC time not set\n Set it.\n"); |
| 116 | + // Set the time |
| 117 | + rtc.setTime(hours, minutes, seconds); |
| 118 | + rtc.setDate(weekDay, day, month, year); |
| 119 | + // ALARM_A (default argument) |
| 120 | + rtc.setAlarmDay(day); |
| 121 | + rtc.setAlarmTime(hours, minutes, seconds + 5, 567); |
| 122 | + rtc.enableAlarm(rtc.MATCH_DHHMMSS); |
| 123 | +#ifdef RTC_ALARM_B |
| 124 | + // ALARM_B |
| 125 | + rtc.setAlarmDay(day, STM32RTC::ALARM_B); |
| 126 | + rtc.setAlarmTime(hours, minutes, seconds + 5, 567, STM32RTC::ALARM_B); |
| 127 | + rtc.enableAlarm(rtc.MATCH_DHHMMSS, STM32RTC::ALARM_B); |
| 128 | +#endif |
| 129 | + } else { |
| 130 | + // RTC already initialized |
| 131 | + time_t epoc, alarm_epoc; |
| 132 | + if (rtc.isAlarmEnabled()) { |
| 133 | + rtc.enableAlarm(rtc.MATCH_DHHMMSS); |
| 134 | + alarm_epoc = rtc.getAlarmEpoch(); |
| 135 | + epoc = rtc.getEpoch(); |
| 136 | + if (difftime(alarm_epoc, epoc) <= 0) { |
| 137 | + Serial.printf("Alarm A was enabled and expired, force callback call\n"); |
| 138 | + alarmMatch(&atime); |
| 139 | + } else { |
| 140 | + Serial.printf("Alarm A was enabled and restored\n"); |
| 141 | + } |
| 142 | + } |
| 143 | +#ifdef RTC_ALARM_B |
| 144 | + // ALARM_B |
| 145 | + if (rtc.isAlarmEnabled(STM32RTC::ALARM_B)) { |
| 146 | + rtc.enableAlarm(rtc.MATCH_DHHMMSS, STM32RTC::ALARM_B); |
| 147 | + alarm_epoc = rtc.getAlarmEpoch(STM32RTC::ALARM_B); |
| 148 | + epoc = rtc.getEpoch(); |
| 149 | + if (difftime(alarm_epoc, epoc) <= 0) { |
| 150 | + Serial.printf("Alarm B was enabled and expired, force callback call\n"); |
| 151 | + alarmMatch(&btime); |
| 152 | + } else { |
| 153 | + Serial.printf("Alarm B was enabled and restored\n"); |
| 154 | + } |
| 155 | + } |
| 156 | +#endif |
| 157 | + Serial.printf("RTC time already set\n"); |
| 158 | + } |
| 159 | + Serial.printf("Alarm A enable status: %s\n", (rtc.isAlarmEnabled(STM32RTC::ALARM_A)) ? "True" : "False"); |
| 160 | +#ifdef RTC_ALARM_B |
| 161 | + Serial.printf("Alarm B enable status: %s\n", (rtc.isAlarmEnabled(STM32RTC::ALARM_B)) ? "True" : "False"); |
| 162 | +#else |
| 163 | + Serial.println("Alarm B not available."); |
| 164 | +#endif |
| 165 | +} |
| 166 | + |
| 167 | +void loop() |
| 168 | +{ |
| 169 | + rtc.getTime(&hours, &minutes, &seconds, &subSeconds, &period); |
| 170 | + // Print current date & time |
| 171 | + Serial.printf("\n%02d/%02d/%02d %02d:%02d:%02d.%03d\n", rtc.getDay(), rtc.getMonth(), rtc.getYear(), hours, minutes, seconds, subSeconds); |
| 172 | + // Print current alarm configuration |
| 173 | + Serial.printf("Alarm A: %02d %02d:%02d:%02d.%03d\n", rtc.getAlarmDay(), rtc.getAlarmHours(), rtc.getAlarmMinutes(), rtc.getAlarmSeconds(), rtc.getAlarmSubSeconds()); |
| 174 | +#ifdef RTC_ALARM_B |
| 175 | + Serial.printf("Alarm B: %02d %02d:%02d:%02d.%03d\n", rtc.getAlarmDay(STM32RTC::ALARM_B), rtc.getAlarmHours(STM32RTC::ALARM_B), rtc.getAlarmMinutes(STM32RTC::ALARM_B), rtc.getAlarmSeconds(STM32RTC::ALARM_B), rtc.getAlarmSubSeconds(STM32RTC::ALARM_B)); |
| 176 | +#endif |
| 177 | + delay(1000); |
| 178 | +} |
| 179 | + |
| 180 | +void alarmMatch(void *data) |
| 181 | +{ |
| 182 | + time_t epoc; |
| 183 | + uint32_t epoc_ms; |
| 184 | + uint32_t sec = 0; |
| 185 | + uint32_t _millis = 1000; |
| 186 | + cb_data_t cbdata = {.next = 1000, .alarm_a = true}; |
| 187 | + if (data != NULL) { |
| 188 | + cbdata.next = ((cb_data_t*)data)->next; |
| 189 | + cbdata.alarm_a = ((cb_data_t*)data)->alarm_a; |
| 190 | + _millis = cbdata.next; |
| 191 | + } |
| 192 | + |
| 193 | + sec = _millis / 1000; |
| 194 | +#if !defined(RTC_SSR_SS) |
| 195 | + // Minimum is 1 second |
| 196 | + if (sec == 0) { |
| 197 | + sec = 1; |
| 198 | + } |
| 199 | + epoc = rtc.getEpoch(&epoc_ms); |
| 200 | +#else |
| 201 | + _millis = _millis % 1000; |
| 202 | + epoc = rtc.getEpoch(&epoc_ms); |
| 203 | + |
| 204 | + // Update epoch_ms - might need to add a second to epoch |
| 205 | + epoc_ms += _millis; |
| 206 | + if (epoc_ms >= 1000) { |
| 207 | + sec ++; |
| 208 | + epoc_ms -= 1000; |
| 209 | + } |
| 210 | +#endif |
| 211 | + if (cbdata.alarm_a) { |
| 212 | + Serial.printf("\t\t\tAlarm A Match %i\n", ++alarmMatch_counter); |
| 213 | + rtc.setAlarmEpoch(epoc + sec, STM32RTC::MATCH_SS, epoc_ms); |
| 214 | + } |
| 215 | +#ifdef RTC_ALARM_B |
| 216 | + else { |
| 217 | + Serial.printf("\t\t\tAlarm B Match %i\n", ++alarmMatchB_counter); |
| 218 | + rtc.setAlarmEpoch(epoc + sec, STM32RTC::MATCH_SS, epoc_ms, STM32RTC::ALARM_B); |
| 219 | + } |
| 220 | +#endif |
| 221 | +} |
0 commit comments