From 0dd2a95c423b9b91c9bff033019c868b11fe8d89 Mon Sep 17 00:00:00 2001 From: deruiter Date: Fri, 22 Aug 2014 14:42:05 +0200 Subject: [PATCH] Create DCF_77_ANALYZER_CLOCK.ino --- DCF_77_ANALYZER_CLOCK.ino | 1350 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1350 insertions(+) create mode 100644 DCF_77_ANALYZER_CLOCK.ino diff --git a/DCF_77_ANALYZER_CLOCK.ino b/DCF_77_ANALYZER_CLOCK.ino new file mode 100644 index 0000000..ecf51e0 --- /dev/null +++ b/DCF_77_ANALYZER_CLOCK.ino @@ -0,0 +1,1350 @@ +/* + This sketch is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This sketch 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() :() + + This is a sketch, aimed at people who are just beginning to discover the wonderful DCF77 / Radio Clock world. + The C++ code is far from optimized because I myself am an Arduino and C++ newbie! ;) + But in writing this code and learning a LOT from others, I gradually comprehended the inner workings of + DCF and C++. + + If you enjoy exploring the Arduino and DCF77 as much as I did, maybe by using and/or learning from this + sketch, my goal is reached. :o) + + Erik de Ruiter + 2014 + + +*/ + +//---------------------------------------------------------------------------------------------------------- +// Libraries +//---------------------------------------------------------------------------------------------------------- + +// Arduino (new) Time library .................................... http://www.pjrc.com/teensy/td_libs_Time.html +#include +// Enable this line if using Arduino Uno, Mega, etc. +#include +// Maxim 7219 displays library ................................... http://playground.arduino.cc/Main/LEDMatrix +#include +// a basic DS1307 library that returns time as a time_t .......... http://www.pjrc.com/teensy/td_libs_DS1307RTC.html +#include +//SPI interface library .......................................... http://arduino.cc/en/Reference/SPI +#include +//STREAMING.h .................................................... http://arduiniana.org/libraries/streaming/ +/* +New users sometimes wonder why the “Arduino language” doesn’t provide the kind +of concatenation or streaming operations they have become accustomed to in Java/VB/C#/C++, etc. + lcd << "GPS #" << gpsno << " date: " << day << "-" << month << "-" << year << endl; +This library works for any class that derives from Print: + Serial << "Counter: " << counter; + lcd << "Temp: " << t.get_temperature() << " degrees"; + my_pstring << "Hi Mom!" << endl; +With the new library you can also use formatting manipulators like this: + Serial << "Byte value: " << _HEX(b) << endl; + lcd << "The key pressed was " << _BYTE(c) << endl; +This syntax is familiar to many, is easy to read and learn, and, importantly, *** consumes no resources *** +(Because the operator functions are essentially just inline aliases for their print() counterparts, +no sketch gets larger or consumes more RAM as a result of their inclusion.) +*/ +#include +// OneWire lets you access 1-wire devices made by Maxim/Dallas, +// such as DS18S20, DS18B20, DS1822 .............................. http://www.pjrc.com/teensy/td_libs_OneWire.html +// The DallasTemperature library can do all this work for you! ... http://milesburton.com/Dallas_Temperature_Control_Library +#include + +//---------------------------------------------------------------------------------------------------------- +// DS18B20 initialization +//---------------------------------------------------------------------------------------------------------- +OneWire ds(8); // define Onewire instance DS on pin 8 + +//---------------------------------------------------------------------------------------------------------- +// Maxim 7219 Matrix Display initialization +//---------------------------------------------------------------------------------------------------------- +/* + clearDisplay(int addr) ........................................ clears the selected display + lc.shutdown(int addr, boolean) ................................ wake up the MAX72XX from power-saving mode (true = sleep, false = awake) + lc.setIntensity(int addr, value) .............................. set a medium brightness for the Leds (0=min - 15=max) + lc.setLed(int addr, int row, int col, boolean state) .......... switch on the led in row, column. remember that indices start at 0! + lc.setRow(int addr, int row, byte value) ...................... this function takes 3 arguments. example: lc.setRow(0,2,B10110000); + lc.setColumn(int addr, int col, byte value) ................... this function takes 3 arguments. example: lc.setColumn(0,5,B00001111); + lc.setDigit(int addr, int digit, byte value, boolean dp) ....... this function takes an argument of type byte and prints the corresponding digit on the specified column. + The range of valid values runs from 0..15. All values between 0..9 are printed as digits, + values between 10..15 are printed as their hexadecimal equivalent + lc.setChar(int addr, int digit, char value, boolean dp) ....... will display: 0 1 2 3 4 5 6 7 8 9 A B C D E F H L P; - . , _ (the blank or space char) + +pin 12/7 is connected to the DataIn +pin 11/6 is connected to the CLK +pin 10/5 is connected to CS/LOAD + +***** Please set the number of devices you have ***** +But the maximum default of 8 MAX72XX wil also work. +LedConrol(DATAIN, CLOCK, CS/LOAD, NUMBER OF MAXIM CHIPS) +*/ + +// lc is for the Maxim Common CATHODE displays +LedControl lc = LedControl(12, 11, 10, 8, false); // Define pins for Maxim 72xx and how many 72xx we use +// lc1 is for the Maxim Common ANODE displays +LedControl lc1 = LedControl(7, 6, 5, 1, true); // Define pins for Maxim 72xx and how many 72xx we use + + +//---------------------------------------------------------------------------------------------------------- +// Variable and array defenitions +//---------------------------------------------------------------------------------------------------------- +// Define DCF routine parameters +#define DCFRejectionTime 700 // Pulse-to-Pulse rejection time. +#define DCFRejectPulseWidth 50 // Minimal pulse width +#define DCFSplitTime 180 // distinguishes pulse width 100 ms and 200 ms. In practice we see 130 ms and 230 +#define DCFSyncTime 1600 // defines 2000 ms pulse for end of sequence + +// define Arduino Pins +#define BUZZER A1 // Piezo buzzer on Analog port +#define DCF_INTERRUPT 0 // Interrupt number associated with pin +#define DCF77PIN 2 // Connection pin to DCF 77 device. Must be pin 2 or 3! +#define CHIMEPIN 3 // switch CHIME ON/OFF +#define DCF77SOUNDPIN 4 // switch DCF77 Sound ON/OFF +#define TEMPRESETPIN 9 // Push button to reset min/max temp memory + +// define miscellaneous parameters +#define DEBUG_FLOW 0 // 1 = show info about functions calls +#define DS1307_I2C_ADDRESS 0x68 // define the RTC I2C address + +// definition of Maxim 7219 display number sequence +// first Maxim 7219 in 'daisychain' must be '0', next '1' etc. +// COMMON CATHODE DISPLAYS +#define MaximLedRingInner 0 +#define MaximLedRingOuter 1 +#define MaximPeriodPulse 2 +#define MaximBufferBitError 3 +#define MaximWeek 4 +#define MaximDate 5 +#define MaximRtcTime 6 +#define MaximLeds 7 + +// definition of Maxim 7219 display number sequence +// first Maxim 7219 in 'daisychain' must be '0', next '1' etc. +// COMMON ANODE DISPLAYS +#define MaximDcfTime 0 + +// definition of display brighness levels +#define BrightnessMaximLedRingOuter 1 +#define BrightnessMaximLedRingInner 1 +#define BrightnessMaximPeriodPulse 2 +#define BrightnessMaximWeek 3 +#define BrightnessMaximDate 9 +#define BrightnessMaximRtcTime 1 +#define BrightnessMaximLeds 6 +#define BrightnessMaximDcfTime 4 +#define BrightnessMaximBufferBitError 15 + +// definition of Status/Error Led's. Use division and modulo to seperate Row/Col values!! +// to lit a LED you need a ROW and COLUMN value. +// so, for example: BFLed/10 results in the value '1' (row) +// and BFLed%10 results in the value '3' (column) + +/* Row/Col LED numbers of Maxim 7219 chip + Row Col +Sunday 0 0 +Monday 0 1 +Tuesday 0 2 +Wednesday 0 3 +Thursday 0 4 +Friday 0 5 +Saturday 0 6 +Synced 0 7 +RTCError 1 0 +SummerTime 1 1 +WinterTime 1 2 +LeapYear 1 3 +BF 1 4 +EoM 1 5 +EoB 1 6 +rPW 1 7 +rPT 2 0 +DCFOk 2 1 +Chime 2 2 + +*/ +#define SyncedLed 07 +#define RTCError 10 +#define SummerTimeLed 11 +#define WinterTimeLed 12 +#define LeapYearLed 13 +#define BFLed 14 +#define EoMLed 15 +#define EoBLed 16 +#define rPWLed 17 +#define rPTLed 20 +#define DCFOKLed 21 +#define ChimeLed 22 + + +// Pulse flanks +static int leadingEdge = 0; +static int trailingEdge = 0; +static int previousLeadingEdge = 0; + +// used in +volatile unsigned char DCFSignalState = 0; + +// used in +int ss = 0; +int previousSecond = 0; +int previousSecond2 = 0; +unsigned char previousSignalState; + +// DCF Buffers and indicators +static int DCFbitBuffer[59]; // here, the received DCFbits are stored +const int bitValue[] = {1, 2, 4, 8, 10, 20, 40, 80}; // these are the decimal values of the received DCFbits + +/* not used at this moment +// Inserted a 'null' value ("") because an array starts with position zero '0' and I need it to start at '1' +const char dayNameLong[][10] = {"", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"}; +const char dayNameShort[][3] = {"", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"}; +const char monthNameLong [][10] = {"", "Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"}; +const char monthNameShort [][4] = {"", "Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"}; +*/ + +static int bufferPosition = 0; +static int endOfMinute = 0; +static int previousMinute = 0; +static int previousHour = 0; + +// used to check if switch state is changed +int buttonChimeToggle = 0; +int buttonDCF77SoundToggle = 0; +int buttonDisplayOffToggle = 0; + +// dcf variables to store decoded DCF time in +int dcfMinute = 0; +int dcfHour = 0; +int dcfDay = 0; +int dcfWeekDay = 0; +int dcfMonth = 0; +int dcfYear = 0; +int dcfDST = 0; +int leapYear = 0; + +// variables used to store weeknumber and daynumer values +int dayNumber; //Returns the number of day in the year +int weekNumber; //Returns the number of the week in the year + +// error counter variable +int errorCounter = 0; + +// miscelleanous variables +boolean Chime = 0; +boolean daytime = 0; +int loopTime = 0; // check Loop() timing + +//buzzer related +boolean chimeSwitch = 0; +boolean dcf77SoundSwitch = 0; + +// temperature variables +byte present = 0; +byte DS18B20Data[12]; +byte addr[8] = {0x28, 0x13, 0x95, 0x7B, 0x05, 0x00, 0x00, 0x70}; +int maxTemp = 0; +int minTemp = 0; +int lsByte = 0; +int msByte = 0; +int tempReading = 0; +int tempCelcius = 0; +boolean tempResetButton = 0; + + +//============================================================================== +// SETUP +//============================================================================== +void setup() +{ + // initialize Serial communication + Serial.begin(115200); + + // define DCF77PIN as input + pinMode(DCF77PIN, INPUT); + // define pin to shut off display as input + pinMode(CHIMEPIN, INPUT); + pinMode(TEMPRESETPIN, INPUT); + pinMode(DCF77SOUNDPIN, INPUT); + + // Initialize all variables and LED displays + initialize(); + // Initialize DCF77 signal listener interrupt + attachInterrupt(DCF_INTERRUPT, int0handler, CHANGE); + + // Initialize RTC and set as SyncProvider. + // Later RTC will be synced with DCF time + setSyncProvider(RTC.get); // the function to get the time from the RTC + // check if RTC has set the system time + if (timeStatus() != timeSet) + { // Unable to sync with the RTC - activate RTCError LED + lc.setLed(MaximLeds, RTCError / 10, RTCError % 10, true); + } else { + // RTC has set the system time - dim RTCError LED + lc.setLed(MaximLeds, RTCError / 10, RTCError % 10, false); + } + + // use for test purposes + //setTime(23, 59, 40, 31, 12, 13); + //RTC.set(now()); + +} + + +//============================================================================== +// LOOP +//============================================================================== +void loop() +{ + if (DEBUG_FLOW) Serial.println(" "); + + // check if switches are changed and act upon it + checkSwitches(); + + + // check if time is changed + if (second() != previousSecond) + { + //display -Real Time Clock- Time + displayRtcTime(); + + // display 'HI' and 'LO' temperature on specific moments + switch (second()) + { + case 30: + // display 'HI' on display for Hi temperature + lc1.clearDisplay(MaximDcfTime); // clear display + lc1.setChar(MaximDcfTime, 3, 'H', false); // Display 'H' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + lc1.setChar(MaximDcfTime, 2, '1', false); // Display 'I' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + break; + case 31: + case 32: + // display Max temperature on DCF display LED display + lc1.setChar(MaximDcfTime, 3, (maxTemp / 1000), false); + lc1.setChar(MaximDcfTime, 2, (maxTemp % 1000) / 100, true); + lc1.setChar(MaximDcfTime, 1, (maxTemp % 100) / 10, false); + lc1.setRow(MaximDcfTime, 0, B01001110); // Display 'C' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + lc1.setChar(MaximDcfTime, 5, 1, false); // activate top dot + break; + case 33: + // display 'LO' on display for Low temperature + lc1.clearDisplay(MaximDcfTime); // clear display + lc1.setChar(MaximDcfTime, 3, 'L', false); // Display 'L' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + lc1.setChar(MaximDcfTime, 2, '0', false); // Display 'O' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + break; + case 34: + case 35: + // display Min temperature on DCF display LED display + lc1.setChar(MaximDcfTime, 3, (minTemp / 1000), false); + lc1.setChar(MaximDcfTime, 2, (minTemp % 1000) / 100, true); + lc1.setChar(MaximDcfTime, 1, (minTemp % 100) / 10, false); + lc1.setRow(MaximDcfTime, 0, B01001110); // Display 'C' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + lc1.setChar(MaximDcfTime, 5, 1, false); // activate top dot + break; + case 36: + // display 'CU' on display for Current temperature + lc1.clearDisplay(MaximDcfTime); // clear display + lc1.setColumn(MaximDcfTime, 3, B01001110); // Display 'C' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + lc1.setColumn(MaximDcfTime, 2, B00111110); // Display 'O' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + break; + // display current temperature + default: + displayTemp(); + break; + } //switch + previousSecond = second(); + } //(second() != previousSecond) + + + + // call scanSignal if interrupt is triggered by incoming DCF77 pulse + if (DCFSignalState != previousSignalState) + { + scanSignal(); + + previousSignalState = DCFSignalState; + } //if (DCFSignalState != previousSignalState) + + + + + // display date, week LED's, week nr etc. if time is changed + if (minute() != previousMinute) + { + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // DISPLAY SHUTS DOWN FROM 11 PM UNTIL 8 AM + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // check wether it is Day- or Nighttime + if (hour() >= 8 && hour() < 23) + { + // it's DAYTIME so time to activate displays + if (daytime == 0) // wake up displays is only once needed so check variable... + { + // activate all the displays and status LED's + for (int i = 0; i < 8; i++) + { + lc.shutdown(i, false); // Common Cathode displays wakeup + } //for + // Maxim Common Anode + lc1.shutdown(0, false); // Common Anode display wake up + } //if + + daytime = 1; // set daytime variable to TRUE so display activation is disabled + displayData(); // display date, week LED's, week nr etc. + } //if + else + { + daytime = 0; // 'reset' variable so display wakeup is performed when daytime is reached + // time to shut down displays at night to save power... + for (int i = 0; i < 8; i++) + { + lc.shutdown(i, true); // display shut down + } //for + // Maxim Common Anode + lc1.shutdown(0, true); // display shut down + } //else + + //display the DCF time + //displayDCFTime(); + previousMinute = minute(); + } + + + + // reset errorCounter display every hour + if (dcfHour != previousHour) + { + // reser errorCounter to '0' every hour + errorCounter = 0; + ledDisplay(MaximBufferBitError, "R", 0); + previousHour = dcfHour; + } + + +} //loop + + +//================================================================================================================ +//================================================================================================================ +//================================================================================================================ +//================================================================================================================ +//================================================================================================================ + + +//================================================================================================================ +// +// scanSignal +// +// called from +//================================================================================================================ +/* + pulse pulse + width width + |- -| |-- --| |----- END OF MINUTE marker:2000ms -----| + ___ _______ ___ ___ _______ + | 0 | | 1 | | 0 | | 0 | | 1 | + | | | | | | | | | | + | | | | | | | | | | +______| |_______________| |___________| |___________________________________| |_______________| |__ _ _ _ + ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + 1000 2100 2000 2200 3000 3100 NO PULSE 5000 5100 6000 6200 << example millis() value + = end of Minute indication + ^ ^ ^ ^ ^ + DCFbit# 56 DCFbit# 57 DCFbit# 58 DCFbit# 0 DCFbit# 1 etc... << DCF bit received + + ^ ^ ^ + previous leading trailing + leading edge edge edge + + ^ + flanktime +*/ + + + +// Evaluates the signal as it is received. Decides whether we received a "1" or a "0" + +void scanSignal() +{ + + if (DEBUG_FLOW) Serial.print(" "); + + // store time of received pulse + int flankTime = millis(); + + + /////////////////////////////////////////////////////////////// + // Check for flank UP and perform checks on received DCF signal + if (DCFSignalState == 1) { + + leadingEdge = flankTime; // store flankTime to check validity of received period + + // If this flank UP is detected quickly after previous flank up this + // will be an incorrect period lenght that we shall reject + if ((leadingEdge - previousLeadingEdge) < DCFRejectionTime) // DCFRejectionTime = 700, should be 1000ms + { + // rPT - ERROR: FLANK TO FLANK TIME IS TO SHORT -> REJECTED + error(rPTLed); + return; + } // if ((leadingEdge - previousLeadingEdge) < DCFRejectionTime) + + + + // No further action is taken because pulse information is not complete yet, only after receiving DOWN flank + // we will know if the pulse is a '0' or '1' and we can do several checks. + return; + + } // if (DCFSignalState == 1) + + + /////////////////////////////////////////////////////////// + // Check for DOWN and perform checks on received DCF signal + if (DCFSignalState == 0) { + + + trailingEdge = flankTime; // store flankTime to calculate pulsewidth. + + + // If the detected pulse is too short it will be an incorrect pulse that we shall reject as well + if ((trailingEdge - leadingEdge) < DCFRejectPulseWidth) // DCFRejectPulseWidth = 50. should be 100 and 200 ms ideally + { + //rPW - ERROR: DETECTED PULSE IS TO SHORT -> REJECTED + error(rPWLed); + return; + } // if ((trailingEdge - leadingEdge) < DCFRejectPulseWidth) + + // display pulse width on LED display + ledDisplay(MaximPeriodPulse, "R", (trailingEdge - leadingEdge)); + // display period width on LED display + ledDisplay(MaximPeriodPulse, "L", (leadingEdge - previousLeadingEdge)); + + // END OF MINUTE check + //if (bufferPosition > 0 && (leadingEdge - previousLeadingEdge) > DCFSyncTime) // DCFSyncTime is 1600ms + if ((leadingEdge - previousLeadingEdge) > DCFSyncTime) // DCFSyncTime is 1600ms + { + // end of minute detected: + finalizeBuffer(); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + } // if + + + // refresh previousLeadingEdge time + previousLeadingEdge = leadingEdge; + + + // PROCESS RECEIVED DCFbit, distinguish between long and short pulses + if (trailingEdge - leadingEdge < DCFSplitTime) // DCFSplitTime == 180 + { + appendSignal(0); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + if (dcf77SoundSwitch == 1) buzzer(100); + } //if + else + { + appendSignal(1); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + if (dcf77SoundSwitch == 1) buzzer(200); + } //else + } // if (DCFSignalState == 0) +} // void scanSignal(); + + + +//================================================================================================================ +// +// appendSignal +// +// called from +//================================================================================================================ + + +/** + * Add new bit to buffer + */ +void appendSignal(unsigned char signal) +{ + if (DEBUG_FLOW) Serial.print(" "); + + // display bufferPosition on LED display + lc.setChar(MaximBufferBitError, 7, bufferPosition / 10, false); + lc.setChar(MaximBufferBitError, 6, bufferPosition % 10, false); + // display received DCFbit on LED Display + lc.setChar(MaximBufferBitError, 4, signal, false); + + // Fill array with DCFbit signal + DCFbitBuffer[bufferPosition] = signal; + + // display received bits on 1st Matrix displays + lc.setLed(MaximLedRingInner, bufferPosition / 8, bufferPosition % 8, signal); + + // increment bufferposition counter + bufferPosition++; + + + if (bufferPosition > 1) + { + // clear error messages on the screen. clear at second '1' to leave them a while the display... + lc.setLed(MaximLeds, BFLed / 10, BFLed % 10, false); + lc.setLed(MaximLeds, EoMLed / 10, EoMLed % 10, false); + lc.setLed(MaximLeds, EoBLed / 10, EoBLed % 10, false); + lc.setLed(MaximLeds, rPWLed / 10, rPWLed % 10, false); + lc.setLed(MaximLeds, rPTLed / 10, rPTLed % 10, false); + + } + + if (bufferPosition == 6) + { + // clear time status messages + + } + + if (bufferPosition == 56) + { + // warn for coming minute transition + //buzzer(100); + } + + if (bufferPosition > 59) + { + // EoB ERROR - clear both DCFbit displays because buffer is full before at end of time-sequence + lc.clearDisplay(MaximLedRingInner); // clear display + lc.clearDisplay(MaximLedRingOuter); // clear display + lc.clearDisplay(MaximDcfTime); // clear display + + // EoB - BUFFER IS FULL BEFORE END OF TIME-SEQUENCE, THIS MAY BE DUE TO NOISE GIVING ADDITIONAL PEAKS + error(EoBLed); + return; + + } // if (bufferPosition > 59) + + // buzzer sound with duration depending on DCFsignal + //signal == 0 ? buzzer(100) : buzzer(200); + +} // void + + +//================================================================================================================ +// +// finalizeBuffer +// +//================================================================================================================ + +/** + * Finalize filled buffer + */ +void finalizeBuffer(void) { + + if (DEBUG_FLOW) Serial.print(" "); + + if (bufferPosition == 59) + { + + // BUFFER FULL + + // reset RTC seconds to '0' + + // display BF on TFT screen + lc.setLed(MaximLeds, BFLed / 10, BFLed % 10, true); + + // display DCF 'OK' status TRUE + lc.setLed(MaximLeds, DCFOKLed / 10, DCFOKLed % 10, true); + + + // clear DCFbit led ring inner + lc.clearDisplay(MaximLedRingInner); + //copy minute information to DCFbt led ring outer + for (int i = 0; i < 59; i++) { + lc.setLed(MaximLedRingOuter, i / 8, i % 8, DCFbitBuffer[i]); + } // for + + + // process buffer and extract data + processBuffer(); + + + // Reset running buffer + bufferPosition = 0; + // Reset DCFbitBuffer array, positions 0-58 (=59 bits) + for (int i = 0; i < 59; i++) { + DCFbitBuffer[i] = 0; + } // for + + + } // if (bufferPosition == 59) + else + { + + // BUFFER NOT YET FULL at end of time-sequence + lc.setLed(MaximLeds, EoMLed / 10, EoMLed % 10, true); + + // CLEAR DISPLAYS + // clear both DCFbit displays because Buffer is not yet full at end of time-sequence + lc.clearDisplay(MaximLedRingInner); + lc.clearDisplay(MaximLedRingOuter); + + // Reset running buffer + bufferPosition = 0; + // Reset DCFbitBuffer array, positions 0-58 (=59 bits) + for (int i = 0; i < 59; i++) { + DCFbitBuffer[i] = 0; + } + + + } // else +} // void finalizeBuffer(void) + + + + +//================================================================================================================ +// +// processBuffer +// +// called from +//================================================================================================================ + +/** + * Evaluates the information stored in the buffer. This is where the DCF77 + * signal is decoded + */ +void processBuffer(void) { + + if (DEBUG_FLOW) Serial.print(" "); + + // Buffer is full and ready to be decoded + dcfMinute = bitDecode(21, 27); + dcfHour = bitDecode(29, 34); + dcfDay = bitDecode(36, 41); + dcfWeekDay = bitDecode(42, 44); + dcfMonth = bitDecode(45, 49); + dcfYear = bitDecode(50, 57); + + //call function to calculate day of year and weeknumber + dayWeekNumber(dcfYear, dcfMonth, dcfDay, dcfWeekDay); + + //Determine Summer- or Witertime + dcfDST = bitDecode(17, 17); + + // determine Leap Year + leapYear = calculateLeapYear(dcfYear); + + // set Arduino time and after that set RTC time + setTime(dcfHour, dcfMinute, 0, dcfDay, dcfMonth, dcfYear); + RTC.set(now()); + + // activate Synced LED + lc.setLed(MaximLeds, SyncedLed / 10, SyncedLed % 10, true); + + + +} // return to finalizeBuffer() + +//================================================================================================================ +// +// bitDecode +// +// called from +//================================================================================================================ + + +int bitDecode (int bitStart, int bitEnd) { + + if (DEBUG_FLOW) Serial.print(" "); + + // reset 'bitValue-array' counter + int i = 0; + int value = 0; + + // process bitrange bitStart > bitEnd + while (bitStart <= bitEnd) + { + // check if DCFbit in buffer is '1', discard when '0' + if (DCFbitBuffer[bitStart] == 1) { + // DCFbit in buffer == 1 so append its corresponding value to the variable 'value' + value = value + bitValue[i]; + } + // increment 'bitValue-array' counter + i++; + // increment bit-range counter + bitStart++; + } + return value; +} + + + + + +//================================================================================================================ +// +// buzzer +// +//================================================================================================================ + +void buzzer(int duration) +{ + tone(BUZZER, 1500, duration); +} + +//================================================================================================================ +// +// initialize +// +// calles from +//================================================================================================================ + +/** + * Initialize parameters + */ +void initialize(void) +{ + if (DEBUG_FLOW) Serial.print(" "); + + //--------------------------------------------------- + // Initialize Variables + //--------------------------------------------------- + leadingEdge = 0; + trailingEdge = 0; + previousLeadingEdge = 0; + bufferPosition = 0; + // Reset DCFbitBuffer array, positions 0-58 (=59 bits) + for (int i = 0; i < 59; i++) { + DCFbitBuffer[i] = 0; + } + + + //--------------------------------------------------- + // Initialize Maxim 72xx IC's + //--------------------------------------------------- + // Maxim Common Cathode + for (int i = 0; i < 8; i++) + { + lc.shutdown(i, true); // display shut down + delay(100); + lc.shutdown(i, false); // display wake up + lc.clearDisplay(i); // clear display + } + // Maxim Common Anode + lc1.shutdown(0, true); // display shut down + delay(100); + lc1.shutdown(0, false); // display wake up + lc1.clearDisplay(0); // clear display + + // Maxim Common Cathode + lc.setIntensity(MaximLedRingOuter, BrightnessMaximLedRingOuter); + lc.setIntensity(MaximLedRingInner, BrightnessMaximLedRingInner); + lc.setIntensity(MaximPeriodPulse, BrightnessMaximPeriodPulse); + lc.setIntensity(MaximWeek, BrightnessMaximWeek); + lc.setIntensity(MaximDate, BrightnessMaximDate); + lc.setIntensity(MaximRtcTime, BrightnessMaximRtcTime); + lc.setIntensity(MaximLeds, BrightnessMaximLeds); + lc.setIntensity(MaximBufferBitError, BrightnessMaximBufferBitError); + + // Maxim Common Anode + lc1.setIntensity(MaximDcfTime, BrightnessMaximDcfTime); + + + //--------------------------------------------------- + // Initialize Displays + //--------------------------------------------------- + + // set errorCounter display to '0' + ledDisplay(MaximBufferBitError, "R", 0); + + +} + + +//================================================================================================================ +// +// int0handler +// +//================================================================================================================ + +/** + * Interrupt handler that processes up-down flanks into pulses and stores these in the buffer + */ +void int0handler() +{ + if (DEBUG_FLOW) Serial.print(" maxTemp) maxTemp = tempCelcius; + if (tempCelcius < minTemp) minTemp = tempCelcius; + + + // display temperature on DCF display LED display + lc1.setChar(MaximDcfTime, 4, ' ', false); // deactivate colon digits + lc1.setChar(MaximDcfTime, 3, (tempCelcius / 1000), false); + lc1.setChar(MaximDcfTime, 2, (tempCelcius % 1000) / 100, true); + lc1.setChar(MaximDcfTime, 1, (tempCelcius % 100) / 10, false); + lc1.setRow(MaximDcfTime, 0, B01001110); // Display 'C' (Celcius) character. Binary pattern to lite up individual segments in this order is: .ABCDEFG + lc1.setChar(MaximDcfTime, 5, 1, false); // activate top dot +} + + +//================================================================================================================ +// +// writeScratchpad - change data in memory of DS18B20 sensor +// +// USE ONLY once in LOOP() IF YOU WANT TO CHANGE RESOLUTION +//================================================================================================================ + +void writeScratchpad(void) +{ + // This is done ONCE in setup() + + // INITIALIZATION + // All transactions on the 1-Wire bus begin with an initialization sequence. + // The initialization sequence consists of a reset pulse transmitted by the bus master followed by presence pulse(s) transmitted by the slave(s). + // The presence pulse lets the bus master know that slave devices (such as the DS18B20) are on the bus and are ready to operate. + ds.reset(); // The initialization sequence consists of a reset pulse transmitted by the bus master followed by presence pulse(s) transmitted by the slave(s). + + // Select a specific DS18x20 device + byte addr[8] = {0x28, 0x13, 0x95, 0x7B, 0x05, 0x00, 0x00, 0x70}; + ds.select(addr); + + // WRITE SCRATCHPAD + // This command allows the master to write 3 bytes of data to the DS18B20’s scratchpad. + // The first data byte is written into the TH register (byte 2 of the scratchpad), the second byte is written into the TL register (byte 3), + // and the third byte is written into the configuration register (byte 4). + // Data must be transmitted least significant bit first. All three bytes MUST be written before the master issues a reset, or the data may be corrupted. + ds.write(0x4E); + + ds.write(0); // write zero into the alarm register HIGH + ds.write(0); // write zero into the alarm register LOW + /* and write R1 and R2 into the configuration register to select the precision of the temperature + R1/R2 value | resolution | conversion time | increments + HEX DEC + 0 0 0 = 9 bits | 93,75 ms | 0,5 Celsius + 0 1 1 = 10 bits | 187,5 ms | 0,25 + 1 0 2 = 11 bits | 375 ms | 0,125 + 1 1 3 = 12 bits | 750 ms | 0,0625 + CONFIGURATION REGISTER: + ------ Bit ------ + 7 6 5 4 3 2 1 0 + 0 R1 R0 1 1 1 1 1 + */ + // CURRENT SETTING: + ds.write(0 << 5); // << 5 means shift value 5 positions to the left. ds.write(B00011111) does the same + + + // WRITE SCRATCHPAD DATA TO EEPROM + ds.reset(); + ds.select(addr); + // COPY SCRATCHPAD [48h] + // This command copies the contents of the scratchpad TH, TL and configuration registers (bytes 2, 3 and 4) to EEPROM. + // If the device is being used in parasite power mode, within 10μs (max) after this command is issued the master must + // enable a strong pullup on the 1-Wire bus for at least 10ms as described in the Powering the DS18B20 section. + ds.write(0x48); +} +