clock can now work with internal xor external RTC

This commit is contained in:
King Kévin 2016-06-12 15:24:11 +02:00
parent 1167eb7dd8
commit c2cd9a238e
1 changed files with 128 additions and 40 deletions

168
main.c
View File

@ -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