diff --git a/main.c b/main.c index caf7510..a0ec917 100644 --- a/main.c +++ b/main.c @@ -45,11 +45,18 @@ #include "rtc_ds1307.h" // Real Time Clock DS1307 utilities #include "rtc_dcf77.h" // DCF77 time receiver utilities +/** use external RTC, else use internal RTC */ +#define EXTERNAL_RTC false + /** @defgroup main_flags flag set in interrupts to be processed in main task * @{ */ volatile bool button_flag = false; /**< flag set when board user button has been pressed/released */ volatile bool photoresistor_flag = false; /**< flag set when ambient luminosity is measured */ +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC +#else +volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ticked */ +#endif /** @} */ /** @defgroup main_ticks ticks per time units @@ -58,7 +65,11 @@ volatile bool photoresistor_flag = false; /**< flag set when ambient luminosity * @{ */ /** the number of ticks in one second (32768 divisor greater than 256*LED_WS2812B_LEDS/60) */ +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC #define TICKS_PER_SECOND (RTC_DS1307_SQUARE_WAVE_FREQUENCY/RTC_DS1307_SQUARE_WAVE_TICKS) +#else +#define TICKS_PER_SECOND 256 +#endif /** number of ticks in one second */ const uint32_t ticks_second = TICKS_PER_SECOND; /** number of ticks in one minute */ @@ -325,16 +336,56 @@ static void process_command(char* str) if (0==strcmp(word,"help")) { printf("available commands:\n"); printf("time [HH:MM:SS]\n"); +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + printf("date [YYYY-MM-DD]\n"); +#endif } else if (0==strcmp(word,"time")) { word = strtok(NULL,delimiter); if (!word) { - printf("%02lu:%02lu:%02lu\n", rtc_get_counter_val()/ticks_hour, (rtc_get_counter_val()%ticks_hour)/ticks_minute, (rtc_get_counter_val()%ticks_minute)/ticks_second); - } else if (strlen(word)!=8 || word[0]<'0' || word[0]>'2' || word[1]<'0' || word[1]>'9' || word[3]<'0' || word[3]>'5' || word[4]<'0' || word[4]>'9' || word[6]<'0' || word[6]>'5' || word[7]<'0' || word[7]>'9') { +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + printf("current time: %02u:%02u:%02u\n", rtc_ds1307_read_hours(), rtc_ds1307_read_minutes(), rtc_ds1307_read_seconds()); // get and print time from external RTC +#else + printf("current time: %02lu:%02lu:%02lu\n", rtc_get_counter_val()/ticks_hour, (rtc_get_counter_val()%ticks_hour)/ticks_minute, (rtc_get_counter_val()%ticks_minute)/ticks_second); // get and print time from internal RTC +#endif + } else if (strlen(word)!=8 || word[0]<'0' || word[0]>'2' || word[1]<'0' || word[1]>'9' || word[3]<'0' || word[3]>'5' || word[4]<'0' || word[4]>'9' || word[6]<'0' || word[6]>'5' || word[7]<'0' || word[7]>'9') { // time format is incorrect goto error; } else { - rtc_set_counter_val(((word[0]-'0')*10+(word[1]-'0')*1)*ticks_hour+((word[3]-'0')*10+(word[4]-'0')*1)*ticks_minute+((word[6]-'0')*10+(word[7]-'0')*1)*ticks_second); // set time in RTC counter +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + if (!rtc_ds1307_write_hours((word[0]-'0')*10+(word[1]-'0')*1)) { + printf("setting hours failed\n"); + } else if (!rtc_ds1307_write_minutes((word[3]-'0')*10+(word[4]-'0')*1)) { + printf("setting minutes failed\n"); + } else if (!rtc_ds1307_write_seconds((word[6]-'0')*10+(word[7]-'0')*1)) { + printf("setting seconds failed\n"); + } else { + rtc_ds1307_ticks = rtc_ds1307_read_hours()*ticks_hour+rtc_ds1307_read_minutes()*ticks_minute+rtc_ds1307_read_seconds()*ticks_second; // set also internal time + rtc_ds1307_oscillator_enable(); // be sure the oscillation is enabled + printf("time set\n"); + } +#else + rtc_set_counter_val(((word[0]-'0')*10+(word[1]-'0')*1)*ticks_hour+((word[3]-'0')*10+(word[4]-'0')*1)*ticks_minute+((word[6]-'0')*10+(word[7]-'0')*1)*ticks_second); // set time in internal RTC counter printf("time set\n"); - } +#endif + } +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + } else if (0==strcmp(word,"date")) { + word = strtok(NULL,delimiter); + if (!word) { + printf("current date: 20%02u-%02u-%02u\n", rtc_ds1307_read_year(), rtc_ds1307_read_month(), rtc_ds1307_read_date()); + } else if (strlen(word)!=10 || word[0]!='2' || word[1]!='0' || word[2]<'0' || word[2]>'9' || word[3]<'0' || word[3]>'9' || word[5]<'0' || word[5]>'1' || word[6]<'0' || word[6]>'9' || word[8]<'0' || word[8]>'3' || word[9]<'0' || word[9]>'9') { + goto error; + } else { + if (!rtc_ds1307_write_year((word[2]-'0')*10+(word[3]-'0')*1)) { + printf("setting year failed\n"); + } else if (!rtc_ds1307_write_month((word[5]-'0')*10+(word[6]-'0')*1)) { + printf("setting month failed\n"); + } else if (!rtc_ds1307_write_date((word[8]-'0')*10+(word[9]-'0')*1)) { + printf("setting day failed\n"); + } else { + printf("date set\n"); + } + } +#endif } else { goto error; } @@ -378,9 +429,15 @@ int main(void) #endif // setup RTC - printf("setup RTC: "); - rtc_auto_awake(RCC_LSE, 32768/ticks_second-1); // ensure RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect) +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + printf("setup external RTC: "); rtc_ds1307_setup(); // setup external RTC module +#else + printf("setup internal RTC: "); + rtc_auto_awake(RCC_LSE, 32768/ticks_second-1); // ensure internal RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect) + rtc_interrupt_enable(RTC_SEC); // enable RTC interrupt on "seconds" + nvic_enable_irq(NVIC_RTC_IRQ); // allow the RTC to interrupt +#endif rtc_dcf77_setup(); // setup DCF77 module rtc_dcf77_on(); // switch on DCF77 module printf("OK\n"); @@ -428,18 +485,27 @@ int main(void) printf("OK\n"); // verify is external RTC is running +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC if (rtc_ds1307_oscillator_disabled()) { printf("/!\\ RTC oscillator is disabled: the battery may be empty\n"); } - - // use DCF77 time to measure drift - uint32_t time_dcf77 = 0; +#endif // get date and time - printf("current time: %02lu:%02lu:%02lu\n", rtc_get_counter_val()/ticks_hour, (rtc_get_counter_val()%ticks_hour)/ticks_minute, (rtc_get_counter_val()%ticks_minute)/ticks_second); // display time - clock_animate_time(rtc_get_counter_val()); // set time with animation + uint32_t ticks_time = 0; +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + uint8_t* rtc_ds1307_time = rtc_ds1307_read_time(); // get time/date from external RTC + rtc_ds1307_ticks = rtc_ds1307_time[2]*ticks_hour+rtc_ds1307_time[1]*ticks_minute+rtc_ds1307_time[0]*ticks_second; // initialize time for external RTC counter + ticks_time = rtc_ds1307_ticks; // save time + printf("current date: 20%02u-%02u-%02u\n", rtc_ds1307_time[6], rtc_ds1307_time[5], rtc_ds1307_time[4]); +#else + ticks_time = rtc_get_counter_val(); // get time/date from internal RTC +#endif + printf("current time: %02lu:%02lu:%02lu\n", ticks_time/ticks_hour, (ticks_time%ticks_hour)/ticks_minute, (ticks_time%ticks_minute)/ticks_second); // display time + clock_animate_time(ticks_time); // set time with animation - printf("input commands\n"); + // main loop + printf("command input: ready\n"); bool action = false; // if an action has been performed don't go to sleep button_flag = false; // reset button flag char c = ' '; // to store received character @@ -484,44 +550,55 @@ int main(void) } button_flag = false; // reset flag } - while (rtc_ds1307_tick_flag) { // the RTC tick four our counter passed - rtc_ds1307_tick_flag = false; // reset flag - action = true; // action has been performed - if ((rtc_ds1307_ticks%(ticks_second/10))==0) { // one tenth of a second passed - adc_start_conversion_regular(ADC1); // start measuring ambient luminosity - } - if ((rtc_ds1307_ticks%ticks_second)==0) { // one second passed - led_toggle(); // LED toggling confuses the 32.768 kHz oscillator on the blue pill - } - if ((rtc_ds1307_ticks%ticks_minute)==0) { // one minute passed - //printf("%02lu:%02lu:%02lu\n", rtc_get_counter_val()/ticks_hour, (rtc_get_counter_val()%ticks_hour)/ticks_minute, (rtc_get_counter_val()%ticks_minute)/ticks_second); // display internal time - printf("%02lu:%02lu:%02lu\n", rtc_ds1307_ticks/ticks_hour, (rtc_ds1307_ticks%ticks_hour)/ticks_minute, (rtc_ds1307_ticks%ticks_minute)/ticks_second); // display external time - } - if ((rtc_ds1307_ticks%ticks_hour)==0) { // one hours passed - clock_hours(); // show hour markers - } - if (rtc_ds1307_ticks>=ticks_midday*2) { // one day passed - rtc_set_counter_val(rtc_get_counter_val()%ticks_midday); // reset time counter - } - clock_set_time(rtc_ds1307_ticks); // set time - } while (rtc_dcf77_time_flag) { // the DCF77 module received a new time rtc_dcf77_time_flag = false; // reset flag action = true; // action has been performed uint8_t* dcf77_time = rtc_dcf77_time(); // get time if (dcf77_time) { // ensure it's valid + ticks_time = dcf77_time[1]*ticks_hour+dcf77_time[0]*ticks_minute; // calculate new time +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + rtc_ds1307_ticks = ticks_time; // set new time + rtc_ds1307_write_time(0, dcf77_time[0], dcf77_time[1], ((dcf77_time[3]+1)%8)+1, dcf77_time[2], dcf77_time[4], dcf77_time[5]); // set date and time + rtc_ds1307_oscillator_enable(); // be sure the oscillation is enabled +#else + rtc_set_counter_val(ticks_time); // set new time to internal RTC +#endif printf("DCF77 time: 20%02u-%02u-%02u %02u:%02u:00\n", dcf77_time[5], dcf77_time[4], dcf77_time[2], dcf77_time[1], dcf77_time[0]); // display time - uint32_t time_dcf77_new = dcf77_time[1]*ticks_hour+dcf77_time[0]*ticks_minute; // calculate new time - if (time_dcf77!=0) { // we got a previous time to measure drift - printf("internal/external RTC count drifts: %lu %lld %lld\n", time_dcf77_new-time_dcf77, (int64_t)rtc_get_counter_val()-time_dcf77_new, (int64_t)rtc_ds1307_ticks-time_dcf77_new); - } - time_dcf77 = time_dcf77_new; // set new time - rtc_set_counter_val(time_dcf77); // set internal RTC time - rtc_ds1307_ticks = time_dcf77; // set external RTC time } else { printf("DCF77 time: error\n"); } } +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + while (rtc_ds1307_tick_flag) { // the RTC tick for our counter passed + rtc_ds1307_tick_flag = false; // reset flag + ticks_time = rtc_ds1307_ticks; // copy time incremented by external RTC for processing +#else + while (rtc_internal_tick_flag) { // the internal RTC ticked + rtc_internal_tick_flag = false; // reset flag + ticks_time = rtc_get_counter_val(); // copy time from internal RTC for processing +#endif + action = true; // action has been performed + if ((ticks_time%(ticks_second/10))==0) { // one tenth of a second passed + adc_start_conversion_regular(ADC1); // start measuring ambient luminosity + } + if ((ticks_time%ticks_second)==0) { // one second passed + led_toggle(); // LED toggling confuses the 32.768 kHz oscillator on the blue pill + } + if ((ticks_time%ticks_minute)==0) { // one minute passed + printf("%02lu:%02lu:%02lu\n", ticks_time/ticks_hour, (ticks_time%ticks_hour)/ticks_minute, (ticks_time%ticks_minute)/ticks_second); // display external time + } + if ((ticks_time%ticks_hour)==0) { // one hours passed + clock_hours(); // show hour markers + } + if (ticks_time>=ticks_midday*2) { // one day passed +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC + rtc_ds1307_ticks = rtc_ds1307_ticks%ticks_midday; // reset time counter +#else + rtc_set_counter_val(rtc_get_counter_val()%ticks_midday); // reset time counter +#endif + } + clock_set_time(ticks_time); // set time + } while (photoresistor_flag) { // new photo-resistor value has been measured photoresistor_flag = false; // reset flag action = true; // action has been performed @@ -562,3 +639,14 @@ void adc1_2_isr(void) photoresistor_value = adc_read_regular(ADC1); // read measured photo-resistor value (clears interrupt flag) photoresistor_flag = true; // notify new ambient luminosity has been measured } + +#if defined(EXTERNAL_RTC) && EXTERNAL_RTC +#else +/** @brief interrupt service routine called when tick passed on RTC */ +void rtc_isr(void) +{ + rtc_clear_flag(RTC_SEC); // clear flag + rtc_internal_tick_flag = true; // notify to show new time +} +#endif +