mirror of
https://github.com/deruiter/DCF77-Analyzer-Clock-V2.0.git
synced 2025-11-04 16:17:45 +01:00
DCF77-Analyzer-Clock-v2
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,353 @@
|
||||
//
|
||||
// This is the Superfilter sketch I use with the DCF Analyzer/Clock 2.0
|
||||
// Udo Klein did an amazing job with this filter
|
||||
//
|
||||
// Erik de Ruiter
|
||||
|
||||
/*
|
||||
Arduino Uno pin connections I used for the DCF Analyzer Clock
|
||||
|
||||
DCF input ................. A5 (19) = dcf77_sample_pin
|
||||
Output DCF Filtered ....... 12 = dcf77_filtered_pin
|
||||
Output DCF Semi Synthesized A2 (16) = dcf77_semi_synthesized_pin
|
||||
Output DCF Synthesized .... 6 = dcf77_synthesized_pin
|
||||
LED DCF output filtered ... A4 (18) = dcf77_monitor_pin = DCF Monitor LED
|
||||
LED 1 Hz pulse ............ 10 = dcf77_second_pulse_pin = Filter Locked LED
|
||||
LED DCF OK ................ 13 = dcf77_signal_good_indicator_pin = Signal Quality LED
|
||||
LED Difference Filtered ... 7 = dcf77_filter_diff_pin \
|
||||
LED Difference Semi Synth.. A0 = dcf77_semi_synthesized_diff_pin -> = Signal Difference LED
|
||||
LED Difference Synthesized 4 = dcf77_synthesized_diff_pin /
|
||||
*/
|
||||
|
||||
//
|
||||
// www.blinkenlight.net
|
||||
//
|
||||
// Copyright 2014, 2015 Udo Klein
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
|
||||
#include <dcf77.h>
|
||||
/*
|
||||
const uint8_t pon_pin = 51; // connect pon to ground !!!
|
||||
const uint8_t data_pin = 19;
|
||||
const uint8_t gnd_pin = 51;
|
||||
const uint8_t vcc_pin = 49;
|
||||
*/
|
||||
|
||||
const uint8_t dcf77_analog_samples = false;
|
||||
const uint8_t dcf77_analog_sample_pin = 5;
|
||||
const uint8_t dcf77_sample_pin = 19; // A5
|
||||
const uint8_t dcf77_inverted_samples = 0;
|
||||
#if defined(__AVR__)
|
||||
#define ledpin(led) (led)
|
||||
#else
|
||||
#define ledpin(led) (led<14? led: led+(54-14))
|
||||
#endif
|
||||
|
||||
const uint8_t dcf77_monitor_pin = ledpin(18); // A4
|
||||
|
||||
const bool provide_filtered_output = true;
|
||||
const uint8_t dcf77_filtered_pin = ledpin(12);
|
||||
const uint8_t dcf77_inverted_filtered_pin = ledpin(11);
|
||||
const uint8_t dcf77_filter_diff_pin = ledpin(7);
|
||||
|
||||
const bool provide_semi_synthesized_output = true;
|
||||
const uint8_t dcf77_semi_synthesized_pin = ledpin(16);
|
||||
const uint8_t dcf77_inverted_semi_synthesized_pin = ledpin(15);
|
||||
const uint8_t dcf77_semi_synthesized_diff_pin = ledpin(14);
|
||||
|
||||
const bool provide_synthesized_output = true;
|
||||
const uint8_t dcf77_synthesized_pin = ledpin(6);
|
||||
const uint8_t dcf77_inverted_synthesized_pin = ledpin(5);
|
||||
const uint8_t dcf77_synthesized_diff_pin = ledpin(4);
|
||||
|
||||
const uint8_t dcf77_second_pulse_pin = ledpin(10);
|
||||
|
||||
|
||||
const uint8_t dcf77_signal_good_indicator_pin = ledpin(13);
|
||||
|
||||
volatile uint16_t ms_counter = 0;
|
||||
volatile Internal::DCF77::tick_t tick = Internal::DCF77::undefined;
|
||||
|
||||
|
||||
template <bool enable, uint8_t threshold,
|
||||
uint8_t filtered_pin, uint8_t inverted_filtered_pin, uint8_t diff_pin>
|
||||
void set_output(uint8_t clock_state, uint8_t sampled_data, uint8_t synthesized_signal)
|
||||
{
|
||||
if (enable) {
|
||||
const uint8_t filtered_output = clock_state < threshold? sampled_data: synthesized_signal;
|
||||
digitalWrite(filtered_pin, filtered_output);
|
||||
digitalWrite(inverted_filtered_pin, !filtered_output);
|
||||
digitalWrite(diff_pin, filtered_output ^ sampled_data);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct Scope {
|
||||
static const uint16_t samples_per_second = 1000;
|
||||
static const uint8_t bins = 100;
|
||||
static const uint8_t samples_per_bin = samples_per_second / bins;
|
||||
|
||||
volatile uint8_t gbin[bins];
|
||||
volatile boolean samples_pending = false;
|
||||
volatile uint32_t count = 0;
|
||||
|
||||
void process_one_sample(const uint8_t sample) {
|
||||
static uint8_t sbin[bins];
|
||||
|
||||
static uint16_t ticks = 999; // first pass will init the bins
|
||||
++ticks;
|
||||
|
||||
if (ticks == 1000) {
|
||||
ticks = 0;
|
||||
memcpy((void *)gbin, sbin, bins);
|
||||
memset(sbin, 0, bins);
|
||||
samples_pending = true;
|
||||
++count;
|
||||
}
|
||||
sbin[ticks/samples_per_bin] += sample;
|
||||
}
|
||||
|
||||
void print() {
|
||||
uint8_t lbin[bins];
|
||||
|
||||
if (samples_pending) {
|
||||
noInterrupts();
|
||||
memcpy(lbin, (void *)gbin, bins);
|
||||
samples_pending = false;
|
||||
interrupts();
|
||||
|
||||
// ensure the count values will be aligned to the right
|
||||
for (int32_t val=count; val < 100000000; val *= 10) {
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.print((int32_t)count);
|
||||
Serial.print(", ");
|
||||
for (uint8_t bin=0; bin<bins; ++bin) {
|
||||
switch (lbin[bin]) {
|
||||
case 0: Serial.print(bin%10? '-': '+'); break;
|
||||
case 10: Serial.print('X'); break;
|
||||
default: Serial.print(lbin[bin]);
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Scope scope_1;
|
||||
Scope scope_2;
|
||||
|
||||
uint8_t sample_input_pin() {
|
||||
const uint8_t clock_state = DCF77_Clock::get_clock_state();
|
||||
const uint8_t sampled_data =
|
||||
#if defined(__AVR__)
|
||||
dcf77_inverted_samples ^ (dcf77_analog_samples? (analogRead(dcf77_analog_sample_pin) > 200)
|
||||
: digitalRead(dcf77_sample_pin));
|
||||
#else
|
||||
dcf77_inverted_samples ^ digitalRead(dcf77_sample_pin);
|
||||
#endif
|
||||
|
||||
digitalWrite(dcf77_monitor_pin, sampled_data);
|
||||
digitalWrite(dcf77_second_pulse_pin, ms_counter < 500 && clock_state >= Clock::locked);
|
||||
|
||||
const uint8_t synthesized_signal =
|
||||
tick == Internal::DCF77::long_tick ? ms_counter < 200:
|
||||
tick == Internal::DCF77::short_tick ? ms_counter < 100:
|
||||
tick == Internal::DCF77::sync_mark ? 0:
|
||||
// tick == DCF77::undefined --> default handling
|
||||
// allow signal to pass for the first 200ms of each second
|
||||
(ms_counter <=200 && sampled_data) ||
|
||||
// if the clock has valid time data then undefined ticks
|
||||
// are data bits --> first 100ms of signal must be high
|
||||
ms_counter <100;
|
||||
|
||||
set_output<provide_filtered_output, Clock::locked,
|
||||
dcf77_filtered_pin, dcf77_inverted_filtered_pin, dcf77_filter_diff_pin>
|
||||
(clock_state, sampled_data, synthesized_signal);
|
||||
|
||||
set_output<provide_semi_synthesized_output, Clock::unlocked,
|
||||
dcf77_semi_synthesized_pin, dcf77_inverted_semi_synthesized_pin, dcf77_semi_synthesized_diff_pin>
|
||||
(clock_state, sampled_data, synthesized_signal);
|
||||
|
||||
set_output<provide_synthesized_output, Clock::free,
|
||||
dcf77_synthesized_pin, dcf77_inverted_synthesized_pin, dcf77_synthesized_diff_pin>
|
||||
(clock_state, sampled_data, synthesized_signal);
|
||||
|
||||
ms_counter+= (ms_counter < 1000);
|
||||
|
||||
scope_1.process_one_sample(sampled_data);
|
||||
scope_2.process_one_sample(digitalRead(dcf77_synthesized_pin));
|
||||
|
||||
return sampled_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void output_handler(const Clock::time_t &decoded_time) {
|
||||
// reset ms_counter for 1 Hz ticks
|
||||
ms_counter = 0;
|
||||
|
||||
// status indicator --> always on if signal is good
|
||||
// blink 3s on 1s off if signal is poor
|
||||
// blink 1s on 3s off if signal is very poor
|
||||
// always off if signal is bad
|
||||
const uint8_t clock_state = DCF77_Clock::get_clock_state();
|
||||
digitalWrite(dcf77_signal_good_indicator_pin,
|
||||
clock_state >= Clock::locked ? 1:
|
||||
clock_state == Clock::unlocked? (decoded_time.second.digit.lo & 0x03) != 0:
|
||||
clock_state == Clock::free ? (decoded_time.second.digit.lo & 0x03) == 0:
|
||||
0);
|
||||
// compute output for signal synthesis
|
||||
Internal::DCF77_Encoder now;
|
||||
now.second = BCD::bcd_to_int(decoded_time.second);
|
||||
now.minute = decoded_time.minute;
|
||||
now.hour = decoded_time.hour;
|
||||
now.weekday = decoded_time.weekday;
|
||||
now.day = decoded_time.day;
|
||||
now.month = decoded_time.month;
|
||||
now.year = decoded_time.year;
|
||||
now.uses_summertime = decoded_time.uses_summertime;
|
||||
now.leap_second_scheduled = decoded_time.leap_second_scheduled;
|
||||
now.timezone_change_scheduled = decoded_time.timezone_change_scheduled;
|
||||
|
||||
now.undefined_minute_output = false;
|
||||
now.undefined_uses_summertime_output = false;
|
||||
now.undefined_abnormal_transmitter_operation_output = false;
|
||||
now.undefined_timezone_change_scheduled_output = false;
|
||||
|
||||
now.advance_minute();
|
||||
tick = now.get_current_signal();
|
||||
}
|
||||
|
||||
void setup_serial() {
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void output_splash_screen() {
|
||||
Serial.println();
|
||||
Serial.println(F("DCF77 Superfilter 3.0"));
|
||||
Serial.println(F("(c) 2015 Udo Klein"));
|
||||
Serial.println(F("www.blinkenlight.net"));
|
||||
Serial.println();
|
||||
Serial.print(F("Sample Pin: ")); Serial.println(dcf77_sample_pin);
|
||||
Serial.print(F("Inverted Mode: ")); Serial.println(dcf77_inverted_samples);
|
||||
#if defined(__AVR__)
|
||||
Serial.print(F("Analog Mode: ")); Serial.println(dcf77_analog_samples);
|
||||
#endif
|
||||
Serial.print(F("Monitor Pin: ")); Serial.println(dcf77_monitor_pin);
|
||||
Serial.println();
|
||||
|
||||
if (provide_filtered_output) {
|
||||
Serial.println(F("Filtered Output"));
|
||||
Serial.print(F(" Filtered Pin: ")); Serial.println(dcf77_filtered_pin);
|
||||
Serial.print(F(" Diff Pin: ")); Serial.println(dcf77_filter_diff_pin);
|
||||
Serial.print(F(" Inverse Filtered Pin: ")); Serial.println(dcf77_inverted_filtered_pin);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
if (provide_semi_synthesized_output) {
|
||||
Serial.println(F("Semi Synthesized Output"));
|
||||
Serial.print(F(" Filtered Pin: ")); Serial.println(dcf77_semi_synthesized_pin);
|
||||
Serial.print(F(" Diff Pin: ")); Serial.println(dcf77_semi_synthesized_diff_pin);
|
||||
Serial.print(F(" Inverse Filtered Pin: ")); Serial.println(dcf77_inverted_semi_synthesized_pin);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
if (provide_synthesized_output) {
|
||||
Serial.println(F("Synthesized Output"));
|
||||
Serial.print(F(" Filtered Pin: ")); Serial.println(dcf77_synthesized_pin);
|
||||
Serial.print(F(" Diff Pin: ")); Serial.println(dcf77_synthesized_diff_pin);
|
||||
Serial.print(F(" Inverse Filtered Pin: ")); Serial.println(dcf77_inverted_synthesized_pin);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
Serial.print(F("Second Pulse Pin: ")); Serial.println(dcf77_second_pulse_pin);
|
||||
Serial.print(F("Signal Good Pin: ")); Serial.println(dcf77_signal_good_indicator_pin);
|
||||
|
||||
Serial.println();
|
||||
|
||||
Serial.println();
|
||||
Serial.println(F("Initializing..."));
|
||||
Serial.println();
|
||||
};
|
||||
|
||||
void setup_pins() {
|
||||
if (provide_filtered_output) {
|
||||
pinMode(dcf77_filtered_pin, OUTPUT);
|
||||
pinMode(dcf77_filter_diff_pin, OUTPUT);
|
||||
pinMode(dcf77_inverted_filtered_pin, OUTPUT);
|
||||
}
|
||||
|
||||
if (provide_semi_synthesized_output) {
|
||||
pinMode(dcf77_semi_synthesized_pin, OUTPUT);
|
||||
pinMode(dcf77_semi_synthesized_diff_pin, OUTPUT);
|
||||
pinMode(dcf77_inverted_semi_synthesized_pin, OUTPUT);
|
||||
}
|
||||
|
||||
if (provide_synthesized_output) {
|
||||
pinMode(dcf77_synthesized_pin, OUTPUT);
|
||||
pinMode(dcf77_synthesized_diff_pin, OUTPUT);
|
||||
pinMode(dcf77_inverted_synthesized_pin, OUTPUT);
|
||||
}
|
||||
|
||||
pinMode(dcf77_monitor_pin, OUTPUT);
|
||||
pinMode(dcf77_signal_good_indicator_pin, OUTPUT);
|
||||
pinMode(dcf77_second_pulse_pin, OUTPUT);
|
||||
pinMode(dcf77_sample_pin, INPUT);
|
||||
digitalWrite(dcf77_sample_pin, HIGH);
|
||||
}
|
||||
|
||||
void setup_clock() {
|
||||
DCF77_Clock::setup();
|
||||
DCF77_Clock::set_input_provider(sample_input_pin);
|
||||
DCF77_Clock::set_output_handler(output_handler);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
setup_serial();
|
||||
output_splash_screen();
|
||||
setup_pins();
|
||||
setup_clock();
|
||||
/*
|
||||
pinMode(gnd_pin, OUTPUT);
|
||||
digitalWrite(gnd_pin, LOW);
|
||||
pinMode(pon_pin, OUTPUT);
|
||||
digitalWrite(pon_pin, LOW);
|
||||
pinMode(vcc_pin, OUTPUT);
|
||||
digitalWrite(vcc_pin, HIGH);
|
||||
*/
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Clock::time_t now;
|
||||
DCF77_Clock::get_current_time(now);
|
||||
|
||||
if (now.month.val > 0) {
|
||||
Serial.println();
|
||||
Serial.print(F("Decoded time: "));
|
||||
|
||||
DCF77_Clock::print(now);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
Serial.print(DCF77_Clock::get_clock_state());
|
||||
Serial.print(' ');
|
||||
DCF77_Clock::debug();
|
||||
|
||||
scope_1.print();
|
||||
scope_2.print();
|
||||
}
|
||||
Reference in New Issue
Block a user