mirror of
https://github.com/deruiter/DCF77-Analyzer-Clock-V2.0.git
synced 2025-11-04 16:17:45 +01:00
Added credits ;)
This commit is contained in:
@@ -26,6 +26,15 @@
|
||||
Erik de Ruiter
|
||||
2014
|
||||
|
||||
Edit:
|
||||
2014-12-01 changed code to accomodate Adafruit Audio FX Sound Board for Chime sound
|
||||
|
||||
|
||||
CREDITS:
|
||||
I learned a lot from the work of Matthias Dalheimer and Thijs Elenbaas who made their own DCF77 decoders.
|
||||
Without their work I would not have known where to start.
|
||||
I ended up writing my own code (using bits and pieces of their ideas) so I could understand what is happening...
|
||||
My code is far, very far from efficient or advanced but it does work and I know what is going on.
|
||||
|
||||
*/
|
||||
|
||||
@@ -110,12 +119,16 @@ LedControl lc1 = LedControl(7, 6, 5, 1, true); // Define pins for Maxim 72xx and
|
||||
#define DCFSyncTime 1600 // defines 2000 ms pulse for end of sequence
|
||||
|
||||
// define Arduino Pins
|
||||
#define BUZZER A1 // Piezo buzzer on Analog port
|
||||
#define BUZZER A1 // OUTPUT: Piezo buzzer on Analog port
|
||||
#define CHIMESWITCHPIN A2 // INPUT: Chime on/off switch
|
||||
#define CHIMEPIN A3 // OUTPUT: Chime Activate LOW=CHIME ON
|
||||
#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 SPEAKERVOLPIN 13 // After power on, set the speaker volume of the Adafruit Adio Board via this pin
|
||||
#define DCF77PIN 2 // INPUT: Connection pin to DCF 77 device. Must be pin 2 or 3!
|
||||
#define NOTUSEDPIN 3 // INPUT: not used at this moment
|
||||
#define DCF77SOUNDPIN 4 // INPUT: Switch DCF77 Sound ON/OFF
|
||||
#define TEMPRESETPIN 9 // INPUT: Push button to reset min/max temp memory
|
||||
|
||||
|
||||
// define miscellaneous parameters
|
||||
#define DEBUG_FLOW 0 // 1 = show info about functions calls
|
||||
@@ -149,6 +162,9 @@ LedControl lc1 = LedControl(7, 6, 5, 1, true); // Define pins for Maxim 72xx and
|
||||
#define BrightnessMaximDcfTime 4
|
||||
#define BrightnessMaximBufferBitError 15
|
||||
|
||||
// After power on, set the speaker volume of the Adafruit Adio Board via this pin
|
||||
#define SPEAKERVOLUME 12
|
||||
|
||||
// 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)
|
||||
@@ -207,7 +223,8 @@ 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
|
||||
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'
|
||||
@@ -245,11 +262,8 @@ int weekNumber; //Returns the number of the week in the year
|
||||
int errorCounter = 0;
|
||||
|
||||
// miscelleanous variables
|
||||
boolean Chime = 0;
|
||||
boolean daytime = 0;
|
||||
int loopTime = 0; // check Loop() timing
|
||||
|
||||
//buzzer related
|
||||
boolean daytimeChange = 1;
|
||||
boolean dayTime = 0;
|
||||
boolean chimeSwitch = 0;
|
||||
boolean dcf77SoundSwitch = 0;
|
||||
|
||||
@@ -274,12 +288,14 @@ 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);
|
||||
pinMode(DCF77PIN, INPUT); // define DCF77PIN as input
|
||||
pinMode(NOTUSEDPIN, INPUT); // define pin to shut off display as input
|
||||
pinMode(TEMPRESETPIN, INPUT); // define pin to reset High / Low temperature memory
|
||||
pinMode(DCF77SOUNDPIN, INPUT); // define pin for switch to shut off second beep sound
|
||||
pinMode(CHIMESWITCHPIN, OUTPUT); // output to activate hourly chime sound
|
||||
pinMode(CHIMEPIN, OUTPUT); // output to activate ticking sound
|
||||
pinMode(SPEAKERVOLPIN, OUTPUT); // output to set LOWER speaker volume on startup
|
||||
digitalWrite(SPEAKERVOLPIN, LOW);
|
||||
|
||||
// Initialize all variables and LED displays
|
||||
initialize();
|
||||
@@ -293,11 +309,21 @@ void setup()
|
||||
if (timeStatus() != timeSet)
|
||||
{ // Unable to sync with the RTC - activate RTCError LED
|
||||
lc.setLed(MaximLeds, RTCError / 10, RTCError % 10, true);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// RTC has set the system time - dim RTCError LED
|
||||
lc.setLed(MaximLeds, RTCError / 10, RTCError % 10, false);
|
||||
}
|
||||
|
||||
// After power on, set the speaker volume of the Adafruit Adio Board
|
||||
for(int i=0; i<=SPEAKERVOLUME; i++)
|
||||
{
|
||||
digitalWrite(SPEAKERVOLPIN, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(SPEAKERVOLPIN, LOW);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// use for test purposes
|
||||
//setTime(23, 59, 40, 31, 12, 13);
|
||||
//RTC.set(now());
|
||||
@@ -325,6 +351,10 @@ void loop()
|
||||
// display 'HI' and 'LO' temperature on specific moments
|
||||
switch (second())
|
||||
{
|
||||
case 5:
|
||||
// hourly chime OFF
|
||||
digitalWrite(CHIMEPIN, HIGH);
|
||||
break;
|
||||
case 30:
|
||||
// display 'HI' on display for Hi temperature
|
||||
lc1.clearDisplay(MaximDcfTime); // clear display
|
||||
@@ -361,8 +391,12 @@ void loop()
|
||||
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
|
||||
case 58:
|
||||
// hourly chime ACTIVATE
|
||||
if(chimeSwitch == 1 && dayTime == 1 && minute() == 59) digitalWrite(CHIMEPIN, LOW);
|
||||
break;
|
||||
default:
|
||||
// display current temperature
|
||||
displayTemp();
|
||||
break;
|
||||
} //switch
|
||||
@@ -385,15 +419,15 @@ void loop()
|
||||
// display date, week LED's, week nr etc. if time is changed
|
||||
if (minute() != previousMinute)
|
||||
{
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// DISPLAY SHUTS DOWN FROM 8 PM UNTIL 8 AM
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// DISPLAY SHUTS DOWN FROM 11 PM UNTIL 8 AM
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// check wether it is Day- or Nighttime
|
||||
if (hour() >= 8 && hour() < 23)
|
||||
if (hour() >= 8 && hour() < 21)
|
||||
{
|
||||
// it's DAYTIME so time to activate displays
|
||||
if (daytime == 0) // wake up displays is only once needed so check variable...
|
||||
if (daytimeChange == 1) // test variable because daytime routine is needed only once
|
||||
{
|
||||
// activate all the displays and status LED's
|
||||
for (int i = 0; i < 8; i++)
|
||||
@@ -402,34 +436,42 @@ void loop()
|
||||
} //for
|
||||
// Maxim Common Anode
|
||||
lc1.shutdown(0, false); // Common Anode display wake up
|
||||
} //if
|
||||
} //if (daytimeChange == 0)
|
||||
|
||||
daytime = 1; // set daytime variable to TRUE so display activation is disabled
|
||||
daytimeChange = 0; // set variable so daytime routine is performed only once
|
||||
dayTime = 1;
|
||||
displayData(); // display date, week LED's, week nr etc.
|
||||
} //if
|
||||
|
||||
} //if (hour() >= 8 && hour() < 21)
|
||||
|
||||
else
|
||||
|
||||
{
|
||||
daytime = 0; // 'reset' variable so display wakeup is performed when daytime is reached
|
||||
// time to shut down displays at night to save power...
|
||||
// it's NIGHTTIME so time to deactivate displays
|
||||
if (daytimeChange == 0) // test variable because nighttime routine is needed only once
|
||||
{
|
||||
// deactivate all the displays and status LED's
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
lc.shutdown(i, true); // display shut down
|
||||
lc.shutdown(i, true); // Common Cathode displays wakeup
|
||||
} //for
|
||||
// Maxim Common Anode
|
||||
lc1.shutdown(0, true); // display shut down
|
||||
lc1.shutdown(0, true); // Common Anode display wake up
|
||||
} //if (daytimeChange == 0)
|
||||
|
||||
dayTime = 0;
|
||||
daytimeChange = 1; // set variable so nighttime routine is performed only once
|
||||
|
||||
} //else
|
||||
|
||||
//display the DCF time
|
||||
//displayDCFTime();
|
||||
previousMinute = minute();
|
||||
}
|
||||
|
||||
} //if (minute() != previousMinute)
|
||||
|
||||
|
||||
// reset errorCounter display every hour
|
||||
if (dcfHour != previousHour)
|
||||
{
|
||||
// reser errorCounter to '0' every hour
|
||||
errorCounter = 0;
|
||||
ledDisplay(MaximBufferBitError, "R", 0);
|
||||
previousHour = dcfHour;
|
||||
@@ -819,6 +861,9 @@ void initialize(void)
|
||||
trailingEdge = 0;
|
||||
previousLeadingEdge = 0;
|
||||
bufferPosition = 0;
|
||||
|
||||
digitalWrite(CHIMEPIN, HIGH); // Set Chimepin to default state
|
||||
|
||||
// Reset DCFbitBuffer array, positions 0-58 (=59 bits)
|
||||
for (int i = 0; i < 59; i++) {
|
||||
DCFbitBuffer[i] = 0;
|
||||
@@ -910,7 +955,7 @@ void displayBuffer(String message)
|
||||
//
|
||||
// ledDisplay on Maxim 8 digit displays
|
||||
//
|
||||
// calles from processBuffer
|
||||
// called from processBuffer
|
||||
//================================================================================================================
|
||||
void ledDisplay(int addr, String leftOrRight, int value)
|
||||
{
|
||||
@@ -964,16 +1009,14 @@ void checkSwitches(void)
|
||||
|
||||
|
||||
//read state of switch CHIME
|
||||
chimeSwitch = digitalRead(CHIMEPIN);
|
||||
chimeSwitch = digitalRead(CHIMESWITCHPIN);
|
||||
|
||||
if (chimeSwitch == 1)
|
||||
{
|
||||
Chime = 1;
|
||||
lc.setLed(MaximLeds, ChimeLed / 10, ChimeLed % 10, true);
|
||||
} // if
|
||||
else
|
||||
{
|
||||
Chime = 0;
|
||||
lc.setLed(MaximLeds, ChimeLed / 10, ChimeLed % 10, false);
|
||||
} // else
|
||||
|
||||
@@ -1056,7 +1099,8 @@ week start on monday (1), and sunday is the last day (7). For that reason, i inc
|
||||
*/
|
||||
int dayWeekNumber(int y, int m, int d, int w)
|
||||
{
|
||||
int days[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // Number of days at the beginning of the month in a (not leap) year.
|
||||
int days[] = {
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; // Number of days at the beginning of the month in a (not leap) year.
|
||||
//Start to calculate the number of day
|
||||
if (m == 1 || m == 2) {
|
||||
//for any type of year, it calculate the number of days for January or february
|
||||
@@ -1092,15 +1136,16 @@ int dayWeekNumber(int y, int m, int d, int w)
|
||||
//================================================================================================================
|
||||
|
||||
/*****
|
||||
Purpose: Determine if a given year is a leap year
|
||||
Parameters: int year // The year to test
|
||||
Return value: int // '1' if the year is a leap year, '0'otherwise
|
||||
* Purpose: Determine if a given year is a leap year
|
||||
* Parameters: int year // The year to test
|
||||
* Return value: int // '1' if the year is a leap year, '0'otherwise
|
||||
*****/
|
||||
int calculateLeapYear(int year)
|
||||
{
|
||||
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1114,15 +1159,6 @@ int calculateLeapYear(int year)
|
||||
void displayData(void)
|
||||
{
|
||||
|
||||
// sound buzzer on whole hour
|
||||
if (minute() == 00 && Chime == 1)
|
||||
{
|
||||
// beep-beep on whole hour
|
||||
tone(BUZZER, 4000, 180);
|
||||
delay (250);
|
||||
tone(BUZZER, 4000, 180);
|
||||
}
|
||||
|
||||
// display Day of Week on LED's
|
||||
// first, clear all the 'Day' Led's (row '0') before displaying new value
|
||||
for (int i = 0; i < 7; i++) {
|
||||
@@ -1174,9 +1210,10 @@ void displayData(void)
|
||||
*/
|
||||
|
||||
// display Summer- or Wintertime LED
|
||||
if (dcfDST = 1) {
|
||||
if (dcfDST == 1) {
|
||||
lc.setLed(MaximLeds, SummerTimeLed / 10, SummerTimeLed % 10, true);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
lc.setLed(MaximLeds, WinterTimeLed / 10, WinterTimeLed % 10, true);
|
||||
}
|
||||
|
||||
@@ -1291,7 +1328,7 @@ void displayTemp(void)
|
||||
lc1.setChar(MaximDcfTime, 5, 1, false); // activate top dot
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
//================================================================================================================
|
||||
//
|
||||
// writeScratchpad - change data in memory of DS18B20 sensor
|
||||
@@ -1310,7 +1347,8 @@ void writeScratchpad(void)
|
||||
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};
|
||||
byte addr[8] = {
|
||||
0x28, 0x13, 0x95, 0x7B, 0x05, 0x00, 0x00, 0x70 };
|
||||
ds.select(addr);
|
||||
|
||||
// WRITE SCRATCHPAD
|
||||
@@ -1333,7 +1371,7 @@ void writeScratchpad(void)
|
||||
------ 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
|
||||
|
||||
@@ -1348,3 +1386,161 @@ void writeScratchpad(void)
|
||||
ds.write(0x48);
|
||||
}
|
||||
|
||||
//================================================================================================================
|
||||
//
|
||||
// ARCHIVE
|
||||
//
|
||||
//================================================================================================================
|
||||
|
||||
|
||||
Basic Usage of Onewire Library
|
||||
|
||||
|
||||
OneWire myWire(pin)
|
||||
Create the OneWire object, using a specific pin. Even though you can connect many 1 wire devices to the same pin, if you have a large number, smaller groups each on their own pin can help isolate wiring problems. You can create multiple OneWire objects, one for each pin.
|
||||
|
||||
myWire.search(addrArray)
|
||||
Search for the next device. The addrArray is an 8 byte array. If a device is found, addrArray is filled with the device's address and true is returned. If no more devices are found, false is returned.
|
||||
|
||||
myWire.reset_search()
|
||||
Begin a new search. The next use of search will begin at the first device.
|
||||
|
||||
myWire.reset()
|
||||
Reset the 1-wire bus. Usually this is needed before communicating with any device.
|
||||
|
||||
myWire.select(addrArray)
|
||||
Select a device based on its address. After a reset, this is needed to choose which device you will use, and then all communication will be with that device, until another reset.
|
||||
|
||||
myWire.skip()
|
||||
Skip the device selection. This only works if you have a single device, but you can avoid searching and use this to immediatly access your device.
|
||||
|
||||
myWire.write(num);
|
||||
Write a byte.
|
||||
|
||||
myWire.write(num, 1);
|
||||
Write a byte, and leave power applied to the 1 wire bus.
|
||||
|
||||
myWire.read()
|
||||
Read a byte.
|
||||
|
||||
myWire.crc8(dataArray, length)
|
||||
Compute a CRC check on an array of data.
|
||||
|
||||
|
||||
//================================================================================================================
|
||||
|
||||
|
||||
#include "Wire.h"
|
||||
#define DS1307_I2C_ADDRESS 0x68
|
||||
// Convert normal decimal numbers to binary coded decimal
|
||||
byte decToBcd(byte val)
|
||||
{
|
||||
return ( (val/10*16) + (val%10) );
|
||||
}
|
||||
// Convert binary coded decimal to normal decimal numbers
|
||||
byte bcdToDec(byte val)
|
||||
{
|
||||
return ( (val/16*10) + (val%16) );
|
||||
}
|
||||
// Stops the DS1307, but it has the side effect of setting seconds to 0
|
||||
// Probably only want to use this for testing
|
||||
/*void stopDs1307()
|
||||
{
|
||||
Wire.beginTransmission(DS1307_I2C_ADDRESS);
|
||||
Wire.send(0);
|
||||
Wire.send(0x80);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
// 1) Sets the date and time on the ds1307
|
||||
// 2) Starts the clock
|
||||
// 3) Sets hour mode to 24 hour clock
|
||||
// Assumes you're passing in valid numbers
|
||||
void setDateDs1307(byte second, // 0-59
|
||||
byte minute, // 0-59
|
||||
byte hour, // 1-23
|
||||
byte dayOfWeek, // 1-7
|
||||
byte dayOfMonth, // 1-28/29/30/31
|
||||
byte month, // 1-12
|
||||
byte year) // 0-99
|
||||
{
|
||||
Wire.beginTransmission(DS1307_I2C_ADDRESS);
|
||||
Wire.send(0);
|
||||
Wire.send(decToBcd(second)); // 0 to bit 7 starts the clock
|
||||
Wire.send(decToBcd(minute));
|
||||
Wire.send(decToBcd(hour)); // If you want 12 hour am/pm you need to set
|
||||
// bit 6 (also need to change readDateDs1307)
|
||||
Wire.send(decToBcd(dayOfWeek));
|
||||
Wire.send(decToBcd(dayOfMonth));
|
||||
Wire.send(decToBcd(month));
|
||||
Wire.send(decToBcd(year));
|
||||
Wire.endTransmission();
|
||||
}
|
||||
// Gets the date and time from the ds1307
|
||||
void getDateDs1307(byte *second,
|
||||
byte *minute,
|
||||
byte *hour,
|
||||
byte *dayOfWeek,
|
||||
byte *dayOfMonth,
|
||||
byte *month,
|
||||
byte *year)
|
||||
{
|
||||
// Reset the register pointer
|
||||
Wire.beginTransmission(DS1307_I2C_ADDRESS);
|
||||
Wire.send(0);
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
|
||||
// A few of these need masks because certain bits are control bits
|
||||
*second = bcdToDec(Wire.receive() & 0x7f);
|
||||
*minute = bcdToDec(Wire.receive());
|
||||
*hour = bcdToDec(Wire.receive() & 0x3f); // Need to change this if 12 hour am/pm
|
||||
*dayOfWeek = bcdToDec(Wire.receive());
|
||||
*dayOfMonth = bcdToDec(Wire.receive());
|
||||
*month = bcdToDec(Wire.receive());
|
||||
*year = bcdToDec(Wire.receive());
|
||||
}
|
||||
void setup()
|
||||
{
|
||||
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
|
||||
Wire.begin();
|
||||
Serial.begin(9600);
|
||||
// Change these values to what you want to set your clock to.
|
||||
// You probably only want to set your clock once and then remove
|
||||
// the setDateDs1307 call.
|
||||
second = 45;
|
||||
minute = 3;
|
||||
hour = 7;
|
||||
dayOfWeek = 5;
|
||||
dayOfMonth = 17;
|
||||
month = 4;
|
||||
year = 8;
|
||||
setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
|
||||
}
|
||||
void loop()
|
||||
{
|
||||
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
|
||||
getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
|
||||
Serial.print(hour, DEC);
|
||||
Serial.print(":");
|
||||
Serial.print(minute, DEC);
|
||||
Serial.print(":");
|
||||
Serial.print(second, DEC);
|
||||
Serial.print(" ");
|
||||
Serial.print(month, DEC);
|
||||
Serial.print("/");
|
||||
Serial.print(dayOfMonth, DEC);
|
||||
Serial.print("/");
|
||||
Serial.print(year, DEC);
|
||||
Serial.print(" Day_of_week:");
|
||||
Serial.println(dayOfWeek, DEC);
|
||||
delay(1000);
|
||||
}
|
||||
*/
|
||||
|
||||
//================================================================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user