rtc_dcf77: better decoding using signal correlation
This commit is contained in:
parent
2f67cbe979
commit
e598b572c2
256
lib/rtc_dcf77.c
256
lib/rtc_dcf77.c
|
@ -25,12 +25,11 @@
|
|||
|
||||
/* STM32 (including CM3) libraries */
|
||||
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
||||
#include <libopencm3/cm3/nvic.h> // interrupt handler
|
||||
#include <libopencm3/stm32/rcc.h> // real-time control clock library
|
||||
#include <libopencm3/stm32/gpio.h> // general purpose input output library
|
||||
#include <libopencm3/stm32/spi.h> // SPI library
|
||||
#include <libopencm3/stm32/timer.h> // timer library
|
||||
#include <libopencm3/cm3/nvic.h> // interrupt handler
|
||||
#include <libopencm3/stm32/exti.h> // external interrupt utilities
|
||||
|
||||
#include "rtc_dcf77.h" // RTC DCF77 library API
|
||||
#include "global.h" // common methods
|
||||
|
@ -44,15 +43,29 @@
|
|||
#define RTC_DCF77_SIGNAL_PIN 3 /**< GPIO pin to capture the DCF signal */
|
||||
/** @} */
|
||||
|
||||
/** @defgroup rtc_dcf77_timer timer to measure signal puls
|
||||
/** @defgroup rtc_dcf77_timer timer to sample DCF77 signal
|
||||
* @{
|
||||
*/
|
||||
#define RTC_DCF77_TIMER 4 /**< timer peripheral */
|
||||
#define RTC_DCF77_TIMER_MAX_TIME 2200 /**< the maximum time in ms the timer can count. DCF77 have pulses < 2s */
|
||||
/** @} */
|
||||
|
||||
volatile bool rtc_dcf77_time_flag = false;
|
||||
static volatile uint64_t rtc_dcf77_frame = 0; /**< the received DCF77 frame bits */
|
||||
struct rtc_dcf77_time_t rtc_dcf77_time = {false, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
/**< the received DCF77 frame bits */
|
||||
static volatile uint64_t rtc_dcf77_frame = 0;
|
||||
/** values of the DCF77 signal over 10 ms for 1 s (how many times it is high) */
|
||||
static uint8_t rtc_dcf77_bins[100] = {0};
|
||||
/** the bin shift for the bit phase */
|
||||
static uint8_t rtc_dcf77_phase = 0;
|
||||
/** the maximum phase value */
|
||||
static int16_t rtc_dcf77_phase_max = INT16_MIN;
|
||||
/** if the current phase has been verified */
|
||||
static bool rtc_dcf77_phase_locked = false;
|
||||
/** number of invalid decoding */
|
||||
static uint8_t rtc_dcf77_invalid = 0;
|
||||
/** maximum number of invalid decoding before switching off */
|
||||
#define RTC_DCF77_INVALID_MAX 5
|
||||
|
||||
void rtc_dcf77_setup(void)
|
||||
{
|
||||
|
@ -64,54 +77,68 @@ void rtc_dcf77_setup(void)
|
|||
// setup signal input
|
||||
rcc_periph_clock_enable(RCC_GPIO(RTC_DCF77_SIGNAL_PORT)); // enable clock for signal input peripheral
|
||||
gpio_set_mode(GPIO(RTC_DCF77_SIGNAL_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(RTC_DCF77_SIGNAL_PIN)); // set signal pin to input
|
||||
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
|
||||
exti_select_source(EXTI(RTC_DCF77_SIGNAL_PIN), GPIO(RTC_DCF77_SIGNAL_PORT)); // mask external interrupt of this pin only for this port
|
||||
exti_set_trigger(EXTI(RTC_DCF77_SIGNAL_PIN), EXTI_TRIGGER_BOTH); // trigger on both edges
|
||||
exti_enable_request(EXTI(RTC_DCF77_SIGNAL_PIN)); // enable external interrupt
|
||||
nvic_enable_irq(NVIC_EXTI_IRQ(RTC_DCF77_SIGNAL_PIN)); // enable interrupt
|
||||
|
||||
// setup timer to measure pulses
|
||||
// setup timer to sample signal at 1kHz
|
||||
rcc_periph_clock_enable(RCC_TIM(RTC_DCF77_TIMER)); // enable clock for timer peripheral
|
||||
timer_reset(TIM(RTC_DCF77_TIMER)); // reset timer state
|
||||
timer_set_mode(TIM(RTC_DCF77_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
|
||||
timer_set_prescaler(TIM(RTC_DCF77_TIMER), RTC_DCF77_TIMER_MAX_TIME*(rcc_ahb_frequency/1000)/(1<<16)); // set prescaler to count up to the maximum time
|
||||
timer_enable_counter(TIM(RTC_DCF77_TIMER)); // start timer to measure time
|
||||
timer_set_prescaler(TIM(RTC_DCF77_TIMER), 1); // set prescaler to divide frequency by two, to be able to have a period of 1 kHz (72MHz/2/2^16=549Hz<1kHz)
|
||||
timer_set_period(TIM(RTC_DCF77_TIMER), rcc_ahb_frequency/2/1000-1); // set period to 1kHz (plus hand tuning)
|
||||
timer_clear_flag(TIM(RTC_DCF77_TIMER), TIM_SR_UIF); // clear update event flag
|
||||
timer_update_on_overflow(TIM(RTC_DCF77_TIMER)); // only use counter overflow as UEV source
|
||||
timer_enable_irq(TIM(RTC_DCF77_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
|
||||
nvic_enable_irq(NVIC_TIM_IRQ(RTC_DCF77_TIMER)); // catch interrupt in service routine
|
||||
}
|
||||
|
||||
void rtc_dcf77_on(void)
|
||||
{
|
||||
gpio_clear(GPIO(RTC_DCF77_ENABLE_PORT), GPIO(RTC_DCF77_ENABLE_PIN)); // enable module by pull pin low
|
||||
if (!gpio_get(GPIO(RTC_DCF77_ENABLE_PORT), GPIO(RTC_DCF77_ENABLE_PIN))) { // receiver is already turned on
|
||||
return; // do nothing
|
||||
}
|
||||
rtc_dcf77_frame = 0; // reset frame
|
||||
rtc_dcf77_phase_locked = false; // reset phase lock
|
||||
rtc_dcf77_phase_max = INT16_MIN; // restart searching for phase
|
||||
rtc_dcf77_invalid = 0; // reset invalid count
|
||||
gpio_clear(GPIO(RTC_DCF77_ENABLE_PORT), GPIO(RTC_DCF77_ENABLE_PIN)); // enable module by pulling pin low
|
||||
timer_set_counter(TIM(RTC_DCF77_TIMER), 0); // reset timer counter
|
||||
timer_enable_counter(TIM(RTC_DCF77_TIMER)); // start timer to sample signal
|
||||
}
|
||||
|
||||
void rtc_dcf77_off(void)
|
||||
{
|
||||
gpio_set(GPIO(RTC_DCF77_ENABLE_PORT), GPIO(RTC_DCF77_ENABLE_PIN)); // disable module by pull pin high
|
||||
timer_disable_counter(TIM(RTC_DCF77_TIMER)); // stop timer since we don't need to sample anymore
|
||||
}
|
||||
|
||||
uint8_t* rtc_dcf77_time(void)
|
||||
/** decode rtc_dcf77_frame DCF77 frame into rtc_dcf77_time DCF77 time
|
||||
* @note check valid for validity
|
||||
*/
|
||||
static void rtc_dcf77_decode(void)
|
||||
{
|
||||
static uint8_t to_return[6] = {0}; // arrays with date values to return
|
||||
uint8_t parity = 0; // to check parity
|
||||
rtc_dcf77_time.valid = false; // reset validity
|
||||
|
||||
if (rtc_dcf77_frame==0) { // no time received yet
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
if (!(rtc_dcf77_frame&((uint64_t)1<<20))) { // start of encode time should always be 1
|
||||
return NULL;
|
||||
if (!(rtc_dcf77_frame&((uint64_t)1<<20))) { // start of encoded time should always be 1
|
||||
return;
|
||||
}
|
||||
|
||||
// check minute parity
|
||||
parity = 0;
|
||||
uint8_t parity = 0; // to check parity
|
||||
for (uint8_t bit=21; bit<=28; bit++) {
|
||||
if (rtc_dcf77_frame&((uint64_t)1<<bit)) {
|
||||
parity++; // count the set bits
|
||||
}
|
||||
}
|
||||
if (parity%2) { // parity should be even
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
to_return[0] = 1*((rtc_dcf77_frame>>21)&(0x1))+2*((rtc_dcf77_frame>>22)&(0x1))+4*((rtc_dcf77_frame>>23)&(0x1))+8*((rtc_dcf77_frame>>24)&(0x1))+10*((rtc_dcf77_frame>>25)&(0x1))+20*((rtc_dcf77_frame>>26)&(0x1))+40*((rtc_dcf77_frame>>27)&(0x1)); // read minute (00-59)
|
||||
if (to_return[0]>59) { // minutes should not be more than 59
|
||||
return NULL;
|
||||
rtc_dcf77_time.minutes = 1*((rtc_dcf77_frame>>21)&(0x1))+2*((rtc_dcf77_frame>>22)&(0x1))+4*((rtc_dcf77_frame>>23)&(0x1))+8*((rtc_dcf77_frame>>24)&(0x1))+10*((rtc_dcf77_frame>>25)&(0x1))+20*((rtc_dcf77_frame>>26)&(0x1))+40*((rtc_dcf77_frame>>27)&(0x1)); // read minute (00-59)
|
||||
if (rtc_dcf77_time.minutes>59) { // minutes should not be more than 59
|
||||
return;
|
||||
}
|
||||
|
||||
// check hour parity
|
||||
parity = 0;
|
||||
for (uint8_t bit=29; bit<=35; bit++) {
|
||||
|
@ -120,12 +147,13 @@ uint8_t* rtc_dcf77_time(void)
|
|||
}
|
||||
}
|
||||
if (parity%2) { // parity should be even
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
to_return[1] = 1*((rtc_dcf77_frame>>29)&(0x1))+2*((rtc_dcf77_frame>>30)&(0x1))+4*((rtc_dcf77_frame>>31)&(0x1))+8*(((rtc_dcf77_frame>>30)>>2)&(0x1))+10*(((rtc_dcf77_frame>>30)>>3)&(0x1))+20*(((rtc_dcf77_frame>>30)>>4)&(0x1)); // read hour (00-23)
|
||||
if (to_return[1]>23) { // hours should not be more than 23
|
||||
return NULL;
|
||||
rtc_dcf77_time.hours = 1*((rtc_dcf77_frame>>29)&(0x1))+2*((rtc_dcf77_frame>>30)&(0x1))+4*((rtc_dcf77_frame>>31)&(0x1))+8*((rtc_dcf77_frame>>32)&(0x1))+10*((rtc_dcf77_frame>>33)&(0x1))+20*((rtc_dcf77_frame>>34)&(0x1)); // read hour (00-23)
|
||||
if (rtc_dcf77_time.hours>23) { // hours should not be more than 23
|
||||
return;
|
||||
}
|
||||
|
||||
// check date parity
|
||||
parity = 0;
|
||||
for (uint8_t bit=36; bit<=58; bit++) {
|
||||
|
@ -134,73 +162,125 @@ uint8_t* rtc_dcf77_time(void)
|
|||
}
|
||||
}
|
||||
if (parity%2) { // parity should be even
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
to_return[2] = 1*(((rtc_dcf77_frame>>30)>>6)&(0x1))+2*(((rtc_dcf77_frame>>30)>>7)&(0x1))+4*(((rtc_dcf77_frame>>30)>>8)&(0x1))+8*(((rtc_dcf77_frame>>30)>>9)&(0x1))+10*(((rtc_dcf77_frame>>30)>>10)&(0x1))+20*(((rtc_dcf77_frame>>30)>>11)&(0x1)); // read day of the month (01-31)
|
||||
if (to_return[2]==0 || to_return[2]>31) { // day of the month should be 1-31
|
||||
return NULL;
|
||||
rtc_dcf77_time.day = 1*((rtc_dcf77_frame>>36)&(0x1))+2*((rtc_dcf77_frame>>37)&(0x1))+4*((rtc_dcf77_frame>>38)&(0x1))+8*((rtc_dcf77_frame>>39)&(0x1))+10*((rtc_dcf77_frame>>40)&(0x1))+20*((rtc_dcf77_frame>>41)&(0x1)); // read day of the month (01-31)
|
||||
if (rtc_dcf77_time.day==0 || rtc_dcf77_time.day>31) { // day of the month should be 1-31
|
||||
return;
|
||||
}
|
||||
to_return[3] = 1*(((rtc_dcf77_frame>>30)>>12)&(0x1))+2*(((rtc_dcf77_frame>>30)>>13)&(0x1))+4*(((rtc_dcf77_frame>>30)>>14)&(0x1)); // read day of the week (1=Monday - 7=Sunday)
|
||||
if (to_return[3]==0 || to_return[3]>7) { // day of the week should be 1-7
|
||||
return NULL;
|
||||
rtc_dcf77_time.weekday = 1*((rtc_dcf77_frame>>42)&(0x1))+2*((rtc_dcf77_frame>>43)&(0x1))+4*((rtc_dcf77_frame>>44)&(0x1)); // read day of the week (1=Monday - 7=Sunday)
|
||||
if (rtc_dcf77_time.weekday==0 || rtc_dcf77_time.weekday>7) { // day of the week should be 1-7
|
||||
return;
|
||||
}
|
||||
to_return[4] = 1*(((rtc_dcf77_frame>>30)>>15)&(0x1))+2*(((rtc_dcf77_frame>>30)>>16)&(0x1))+4*(((rtc_dcf77_frame>>30)>>17)&(0x1))+8*(((rtc_dcf77_frame>>30)>>18)&(0x1))+10*(((rtc_dcf77_frame>>30)>>19)&(0x1)); // read month of the year (01-12)
|
||||
if (to_return[4]==0 || to_return[4]>12) { // month of the year should be 1-12
|
||||
return NULL;
|
||||
rtc_dcf77_time.month = 1*((rtc_dcf77_frame>>45)&(0x1))+2*((rtc_dcf77_frame>>46)&(0x1))+4*((rtc_dcf77_frame>>47)&(0x1))+8*((rtc_dcf77_frame>>48)&(0x1))+10*((rtc_dcf77_frame>>49)&(0x1)); // read month of the year (01-12)
|
||||
if (rtc_dcf77_time.month==0 || rtc_dcf77_time.month>12) { // month of the year should be 1-12
|
||||
return;
|
||||
}
|
||||
to_return[5] = 1*(((rtc_dcf77_frame>>30)>>20)&(0x1))+2*(((rtc_dcf77_frame>>30)>>21)&(0x1))+4*(((rtc_dcf77_frame>>30)>>22)&(0x1))+8*(((rtc_dcf77_frame>>30)>>23)&(0x1))+10*(((rtc_dcf77_frame>>30)>>24)&(0x1))+20*(((rtc_dcf77_frame>>30)>>25)&(0x1))+40*(((rtc_dcf77_frame>>30)>>26)&(0x1))+80*(((rtc_dcf77_frame>>30)>>27)&(0x1)); // read year of the century (00-99)
|
||||
if (to_return[5]>99) { // year should be <100
|
||||
return NULL;
|
||||
rtc_dcf77_time.year = 1*((rtc_dcf77_frame>>50)&(0x1))+2*((rtc_dcf77_frame>>51)&(0x1))+4*((rtc_dcf77_frame>>52)&(0x1))+8*((rtc_dcf77_frame>>53)&(0x1))+10*((rtc_dcf77_frame>>54)&(0x1))+20*((rtc_dcf77_frame>>55)&(0x1))+40*((rtc_dcf77_frame>>56)&(0x1))+80*((rtc_dcf77_frame>>57)&(0x1)); // read year of the century (00-99)
|
||||
if (rtc_dcf77_time.year>99) { // year should be <100
|
||||
return;
|
||||
}
|
||||
return to_return;
|
||||
|
||||
rtc_dcf77_time.valid = true; // if we managed it until here the decoding is successful
|
||||
}
|
||||
|
||||
/** interrupt service routine called when signal edge is detected, decoding the received DCF77 frame (composed by high pulses) */
|
||||
void EXTI_ISR(RTC_DCF77_SIGNAL_PIN)(void)
|
||||
{
|
||||
exti_reset_request(EXTI(RTC_DCF77_SIGNAL_PIN)); // reset interrupt
|
||||
static uint16_t old_state = 0; // save last port state to detect difference
|
||||
static uint8_t pulse = 0; // next pulse number in the DCF77 frame
|
||||
static uint16_t pulse_edge = 0; // time on when the last pulse (rising edge) has been detected
|
||||
static uint64_t rtc_dcf77_frame_tmp = 0; // the DCF77 frame bits as they get filled
|
||||
uint16_t time = timer_get_counter(TIM(RTC_DCF77_TIMER)); // get timer value
|
||||
/** find phase of 1 seconds DCF77 signal in the bins
|
||||
* searches the complete second for the highest correlation if the phase it not locked
|
||||
* searches only around the last phase if locked
|
||||
* saves the new phase with the highest correlation
|
||||
*/
|
||||
static void rtc_dcf77_phase_detector(void) {
|
||||
uint8_t integral_i = 0; // which bin has the highest integral/correlation
|
||||
int16_t integral_max = 0; // maximum integral value found
|
||||
|
||||
uint16_t new_state = gpio_get(GPIO(RTC_DCF77_SIGNAL_PORT), GPIO(RTC_DCF77_SIGNAL_PIN)); // save last port state to detect difference
|
||||
if (old_state!=new_state) { // pulse edge detected
|
||||
time = (uint32_t)(time-pulse_edge)*RTC_DCF77_TIMER_MAX_TIME/(1<<16); // get time since last rising edge (integer underflow possible)
|
||||
if (new_state) { // rising edge
|
||||
if (time < 980) { // glitch
|
||||
goto end; // ignore glitch
|
||||
} else if (time < 1030) { // a normal pulse
|
||||
pulse++; // go to next pulse
|
||||
if (pulse>58) { // something wrong happened
|
||||
pulse = 0; // restart
|
||||
}
|
||||
} else if (time < 1980) { // glitch
|
||||
goto end; // ignore glitch
|
||||
} else if (time < 2130) { // first pulse of a frame
|
||||
if (pulse==58) { // full frame received
|
||||
rtc_dcf77_frame = rtc_dcf77_frame_tmp; // save received complete frame
|
||||
rtc_dcf77_time_flag = true; // notify user
|
||||
}
|
||||
pulse = 0;
|
||||
} else { // something is wrong, restart
|
||||
pulse = 0;
|
||||
for (uint8_t start=0; start<(rtc_dcf77_phase_locked ? 10 : LENGTH(rtc_dcf77_bins)); start++) { // which bin has been used to start the convolution (only use +/- 15 bits of previous phase if locked)
|
||||
int16_t integral = 0; // value of the integral
|
||||
for (uint8_t bin=0; bin<LENGTH(rtc_dcf77_bins); bin++) { // go through bins to calculate correlation
|
||||
int8_t dfc77_signal = -1; // the signal of the reference DCF77 signal
|
||||
if (bin<10) { // the signal is always high for the first 100 ms
|
||||
dfc77_signal = 1; // use highest values
|
||||
} else if (bin<20) { // the signal has 50% chance of being high for the next 100 ms (encoding the bit)
|
||||
dfc77_signal = 0; // use middle value
|
||||
}
|
||||
pulse_edge = 0; // save new edge
|
||||
timer_set_counter(TIM(RTC_DCF77_TIMER), 0); // reset timer to count
|
||||
} else { // falling edge
|
||||
if (time < 90) { // glitch
|
||||
goto end; // ignore glitch
|
||||
} else if (time < 120) { // 0 received
|
||||
rtc_dcf77_frame_tmp &= ~((uint64_t)1<<pulse); // save 0 bit
|
||||
} else if (time < 190) { // glitch
|
||||
goto end; // ignore glitch
|
||||
} else if (time < 220) { // 1 received
|
||||
rtc_dcf77_frame_tmp |= ((uint64_t)1<<pulse); // save 1 bit
|
||||
}
|
||||
}
|
||||
// the rest of the time the signal is low (keep lowest value)
|
||||
integral += rtc_dcf77_bins[(start+bin+rtc_dcf77_phase+LENGTH(rtc_dcf77_bins)-5)%LENGTH(rtc_dcf77_bins)]*dfc77_signal; // calculate the correlation at this point and integrate it (start with previous phase - 15 bins)
|
||||
}
|
||||
if (integral>integral_max) { // we found a better correlation result
|
||||
integral_max = integral; // save new best result
|
||||
integral_i = (start+rtc_dcf77_phase+LENGTH(rtc_dcf77_bins)-5)%LENGTH(rtc_dcf77_bins); // start new best phase start
|
||||
}
|
||||
}
|
||||
|
||||
if ((int16_t)(integral_max+40)>rtc_dcf77_phase_max) { // only save new phase if it is better than the last one, with some margin to compensate for the drift (perfect correlation = 100, worst correlation = -800)
|
||||
rtc_dcf77_phase_max = integral_max; // save best phase value
|
||||
rtc_dcf77_phase = integral_i; // save bin index corresponding to start of the phase
|
||||
}
|
||||
}
|
||||
|
||||
/** interrupt service routine called for timer */
|
||||
void TIM_ISR(RTC_DCF77_TIMER)(void)
|
||||
{
|
||||
static uint8_t bin_state = 0; // how many samples have been stored in the bin
|
||||
static uint8_t bin_i = 0; // current bin filled
|
||||
static uint8_t bit_i = 0; // current bit in the DCF77 minute frame
|
||||
if (timer_get_flag(TIM(RTC_DCF77_TIMER), TIM_SR_UIF)) { // overflow update event happened
|
||||
timer_clear_flag(TIM(RTC_DCF77_TIMER), TIM_SR_UIF); // clear flag
|
||||
// fill bin with current sample state
|
||||
if (gpio_get(GPIO(RTC_DCF77_SIGNAL_PORT), GPIO(RTC_DCF77_SIGNAL_PIN))) {
|
||||
rtc_dcf77_bins[bin_i]++; // only need to increase if the signal is high
|
||||
}
|
||||
bin_state++; // remember we filled the bin
|
||||
|
||||
if (bin_state>=10) { // bin has 10x1 ms samples, it is now full
|
||||
bin_i = (bin_i+1)%LENGTH(rtc_dcf77_bins); // go to next bin
|
||||
rtc_dcf77_bins[bin_i] = 0; // restart bin
|
||||
bin_state = 0; // restart collecting
|
||||
}
|
||||
|
||||
if (0==bin_i && 0==bin_state) { // we have 1 s of samples
|
||||
if (bit_i<59) {
|
||||
rtc_dcf77_phase_detector(); // detect phase in signal
|
||||
// check modulation of first 100 ms
|
||||
uint16_t modulation = 0;
|
||||
for (uint8_t bin=0; bin<10; bin++) {
|
||||
modulation += rtc_dcf77_bins[(rtc_dcf77_phase+bin)%LENGTH(rtc_dcf77_bins)];
|
||||
}
|
||||
if (modulation<50) { // signal is not modulated, it might be the 60th pause bit
|
||||
bit_i = 0; // restart frame
|
||||
rtc_dcf77_frame = 0; // restart frame
|
||||
rtc_dcf77_phase_max = INT16_MIN; // restart searching for phase
|
||||
rtc_dcf77_phase_locked = false; // unlock phase since the decoding seems wrong
|
||||
} else { // modulation detected
|
||||
// check modulation of next 100 ms
|
||||
modulation = 0;
|
||||
for (uint8_t bin=10; bin<20; bin++) {
|
||||
modulation += rtc_dcf77_bins[(rtc_dcf77_phase+bin)%LENGTH(rtc_dcf77_bins)];
|
||||
}
|
||||
if (modulation<50) { // it's a 0
|
||||
// bit is already cleared
|
||||
} else { // it's a 1
|
||||
rtc_dcf77_frame |= (1ULL<<bit_i); // set bit
|
||||
}
|
||||
bit_i++; // go to next bit
|
||||
}
|
||||
} else { // complete DCF77 frame received
|
||||
rtc_dcf77_decode(); // decode frame
|
||||
if (rtc_dcf77_time.valid) { // decoded time is valid
|
||||
rtc_dcf77_time.milliseconds = rtc_dcf77_phase*10; // save milliseconds corresponding to phase
|
||||
rtc_dcf77_phase_locked = true; // lock phase since decoding succeeded
|
||||
rtc_dcf77_invalid = 0; // remember we had an valid decoding
|
||||
rtc_dcf77_time_flag = true; // notify user we have time
|
||||
} else {
|
||||
rtc_dcf77_invalid++; // remember we had an invalid decoding
|
||||
}
|
||||
if (rtc_dcf77_invalid>=RTC_DCF77_INVALID_MAX) { // too many invalid decoding
|
||||
rtc_dcf77_off(); // switch off receiver so it can re-tune
|
||||
}
|
||||
bit_i = 0; // restart frame
|
||||
rtc_dcf77_frame = 0; // restart frame
|
||||
}
|
||||
}
|
||||
} else { // no other interrupt should occur
|
||||
while (true); // unhandled exception: wait for the watchdog to bite
|
||||
}
|
||||
end:
|
||||
old_state = new_state; // save new state
|
||||
}
|
||||
|
|
|
@ -23,13 +23,24 @@
|
|||
/** set when time information has been received */
|
||||
extern volatile bool rtc_dcf77_time_flag;
|
||||
|
||||
/** decoded DCF77 time received */
|
||||
extern struct rtc_dcf77_time_t {
|
||||
bool valid; /**< if the time is valid */
|
||||
uint8_t milliseconds; /**< milliseconds (00-99) */
|
||||
uint8_t seconds; /**< seconds (always 0) */
|
||||
uint8_t minutes; /**< minutes (00-49) */
|
||||
uint8_t hours; /**< hours (00-23) */
|
||||
uint8_t day; /**< day of the month (01-31) */
|
||||
uint8_t weekday; /**< day of the week (1-7=Monday-Sunday) */
|
||||
uint8_t month; /**< month (01-12) */
|
||||
uint8_t year; /**< year within century (00-99) */
|
||||
} rtc_dcf77_time;
|
||||
|
||||
/** setup DCF77 time receiver module */
|
||||
void rtc_dcf77_setup(void);
|
||||
/** switch on DCF77 time receiver module */
|
||||
/** switch on DCF77 time receiver module
|
||||
* @note it switches back off after too many invalid decoding attempts
|
||||
*/
|
||||
void rtc_dcf77_on(void);
|
||||
/** switch off DCF77 time receiver module */
|
||||
void rtc_dcf77_off(void);
|
||||
/** get last received DCF77 time
|
||||
* @return array of {minutes (00-49), hours (00-23), date (01-31), day of the week (1-7=Monday-Sunday), month (01-12), year of the century (00-99)} if received time is valid, NULL else
|
||||
*/
|
||||
uint8_t* rtc_dcf77_time(void);
|
||||
|
|
Loading…
Reference in New Issue