From 2d9aa994a8e7309c1526c59252975923dba18846 Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 11 Jan 2022 02:08:04 -0800 Subject: [PATCH] initial --- i2c-lcd/i2c-lcd.ino | 131 ++++ infrared-read/infrared-read.ino | 51 ++ quadalphanum/quadalphanum.ino | 82 +++ wwvb-ref/wwvb-ref.ino | 871 +++++++++++++++++++++++++ wwvb/floats.csv | 175 +++++ wwvb/output.txt | 1086 +++++++++++++++++++++++++++++++ wwvb/wwvb.ino | 482 ++++++++++++++ 7 files changed, 2878 insertions(+) create mode 100644 i2c-lcd/i2c-lcd.ino create mode 100644 infrared-read/infrared-read.ino create mode 100644 quadalphanum/quadalphanum.ino create mode 100644 wwvb-ref/wwvb-ref.ino create mode 100644 wwvb/floats.csv create mode 100644 wwvb/output.txt create mode 100644 wwvb/wwvb.ino diff --git a/i2c-lcd/i2c-lcd.ino b/i2c-lcd/i2c-lcd.ino new file mode 100644 index 0000000..c621b0b --- /dev/null +++ b/i2c-lcd/i2c-lcd.ino @@ -0,0 +1,131 @@ +#define SSD1306_NO_SPLASH + +// OLED display width and height, in pixels +#define SCREEN_WIDTH 128 +#define SCREEN_HEIGHT 32 +#define OLED_RESET -1 +// i2c address for oled +///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 +#define SCREEN_ADDRESS 0x3C + +#include +#include +#include +#include +#include +#include +#include +#include + +// set the LCD address to 0x27 for a 16 chars and 2 line display +LiquidCrystal_I2C lcd(0x27, 16, 2); + +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); + +void setup() { + lcd.init(); + lcd.backlight(); + lcd.setCursor(0, 0); + lcd.print("0x123456789abcde"); + lcd.setCursor(0, 1); + lcd.print("fghijklmnopqrstu"); + + Serial.begin(115200); + + // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally + if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { + Serial.println(F("SSD1306 allocation failed")); + for (;;); // Don't proceed, loop forever + } + + display.display(); + delay(50); // Pause for 2 seconds + + // Clear the buffer + display.clearDisplay(); + + testdrawstyles(); // Draw 'stylized' characters + + panic(); + // + // // Invert and restore display, pausing in-between + // display.invertDisplay(true); + // delay(1000); + // display.invertDisplay(false); + // delay(1000); + +} + +void panic() { + for (;;) { + display.invertDisplay(true); + delay(1000); + } +} + + +void loop() +{ +} + +#define LINE_HEIGHT_PX 9 + +void testdrawstyles(void) { + display.clearDisplay(); + display.setTextSize(1); // Normal 1:1 pixel scale + display.setTextColor(SSD1306_WHITE); // Draw white text + display.setCursor(0, 0 * LINE_HEIGHT_PX); + display.println(F("123456789112345678921")); + display.setCursor(0, 1 * LINE_HEIGHT_PX); + display.println(F("234567893123456789412")); + display.setCursor(0, 2 * LINE_HEIGHT_PX); + display.println(F("345678951234567896123")); + display.display(); + + display.startscrollright(0x00, 0xFF); + + + + /* + + display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text + display.println(3.141592); + + display.setTextSize(2); // Draw 2X-scale text + display.setTextColor(SSD1306_WHITE); + display.print(F("0x")); display.println(0xDEADBEEF, HEX); + + display.display(); + delay(2000); + */ +} + +/* + void testscrolltext(void) { + display.clearDisplay(); + + display.setTextSize(1.5); // Draw 2X-scale text + display.setTextColor(SSD1306_WHITE); + display.setCursor(10, 0); + display.println(F("1337CAFE")); + display.display(); // Show initial text + delay(70); + + // Scroll in various directions, pausing in-between: + display.startscrollright(0x00, 0x0F); + delay(2000); + display.stopscroll(); + delay(1000); + display.startscrollleft(0x00, 0x0F); + delay(2000); + display.stopscroll(); + delay(1000); + display.startscrolldiagright(0x00, 0x07); + delay(2000); + display.startscrolldiagleft(0x00, 0x07); + delay(2000); + display.stopscroll(); + delay(1000); + } + +*/ diff --git a/infrared-read/infrared-read.ino b/infrared-read/infrared-read.ino new file mode 100644 index 0000000..f4b54a5 --- /dev/null +++ b/infrared-read/infrared-read.ino @@ -0,0 +1,51 @@ +/* + ESP8266 BlinkWithoutDelay by Simon Peter + Blink the blue LED on the ESP-01 module + Based on the Arduino Blink without Delay example + This example code is in the public domain + + The blue LED on the ESP-01 module is connected to GPIO1 + (which is also the TXD pin; so we cannot use Serial.print() at the same time) + + Note that this sketch uses LED_BUILTIN to find the pin with the internal LED +*/ +#define IR_RX_PIN 14 +#define IR_TX_PIN 12 +#define SERIAL_BPS 115200 + +#define POWER_BUTTON 0xFFEA15 +#define EDIT_BUTTON 0xFF7887 +#define EXIT_BUTTON 0xFF38C7 +#define ONE_BUTTON 0xFF08F7 +#define TWO_BUTTON 0xFF8877 +#define THREE_BUTTON 0xFF48B7 +#define FOUR_BUTTON 0xFFC837 +#define FIVE_BUTTON 0xFF28D7 +#define SIX_BUTTON 0xFFA857 +#define SEVEN_BUTTON 0xFFE817 +#define EIGHT_BUTTON 0xFF18E7 +#define NINE_BUTTON 0xFF9867 +#define ZERO_BUTTON 0xFFB847 + +#include + +IRrecv irrecv(IR_RX_PIN); +decode_results results; + +int ledState = LOW; +volatile byte IRInputState; + +void setup() { + IrReceiver.begin(IR_RX_PIN, ENABLE_LED_FEEDBACK); // Start the receiver + pinMode(LED_BUILTIN, OUTPUT); + Serial.begin(SERIAL_BPS); + Serial.print("herro booted\n"); +} + +void loop() { + if (IrReceiver.decode()) { + Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX); + IrReceiver.printIRResultShort(&Serial); // optional use new print version + IrReceiver.resume(); // Enable receiving of the next value + } +} diff --git a/quadalphanum/quadalphanum.ino b/quadalphanum/quadalphanum.ino new file mode 100644 index 0000000..2e4d7cc --- /dev/null +++ b/quadalphanum/quadalphanum.ino @@ -0,0 +1,82 @@ +// Demo the quad alphanumeric display LED backpack kit +// scrolls through every character, then scrolls Serial +// input onto the display + +#include +#include +#include "Adafruit_LEDBackpack.h" + +Adafruit_AlphaNum4 one = Adafruit_AlphaNum4(); +Adafruit_AlphaNum4 two = Adafruit_AlphaNum4(); + +unsigned long ticks; + + +void setup() { + Serial.begin(9600); + + one.begin(0x71); // pass in the address + two.begin(0x70); + + one.writeDigitRaw(3, 0x0); + one.writeDigitRaw(0, 0xFFFF); + one.writeDisplay(); + delay(200); + one.writeDigitRaw(0, 0x0); + one.writeDigitRaw(1, 0xFFFF); + one.writeDisplay(); + delay(200); + one.writeDigitRaw(1, 0x0); + one.writeDigitRaw(2, 0xFFFF); + one.writeDisplay(); + delay(200); + one.writeDigitRaw(2, 0x0); + one.writeDigitRaw(3, 0xFFFF); + one.writeDisplay(); + delay(200); + + one.clear(); + one.writeDisplay(); + + two.clear(); + two.writeDisplay(); + + one.writeDigitAscii(0, '1'); + one.writeDigitAscii(1, '2'); + one.writeDigitAscii(2, '0'); + one.writeDigitAscii(3, '0'); + two.writeDigitAscii(0, '0'); + two.writeDigitAscii(1, '1'); + two.writeDigitAscii(2, '2'); + two.writeDigitAscii(3, '3'); + one.writeDisplay(); + two.writeDisplay(); + + delay(300); + + Serial.println("Start typing to display!"); +} + + +char displaybuffer[4] = {' ', ' ', ' ', ' '}; + +void loop() { + + ticks = millis(); + + + sprintf(displaybuffer, "%02d", ticks/1000); + sprintf(displaybuffer+2, "%02d", ticks-(ticks/1000)*1000); + + Serial.println(displaybuffer); + + // set every digit to the buffer + two.writeDigitAscii(0, displaybuffer[0]); + two.writeDigitAscii(1, displaybuffer[1]); + two.writeDigitAscii(2, displaybuffer[2]); + two.writeDigitAscii(3, displaybuffer[3]); + + // write it out! + two.writeDisplay(); + delay(10); +} diff --git a/wwvb-ref/wwvb-ref.ino b/wwvb-ref/wwvb-ref.ino new file mode 100644 index 0000000..ee0a8bd --- /dev/null +++ b/wwvb-ref/wwvb-ref.ino @@ -0,0 +1,871 @@ +/* WWVB Clock v 1.0 + * + * A WWVB (NIST Time Code Broadcast) receiving clock powered by an + * Arduino (ATMega328), a DS1307 Real Time Clock, and a C-Max + * C-Max CMMR-6P-60 WWVB receiver module. + * + * This code builds on Capt.Tagon's code at duinolab.blogspot.com + * which was a great reference. Specifically, I used almost without change + * his struct / unsigned long long overlay for the received WWVB Buffer, + * which apparently in turn draws on DCF77 decoding code by Rudi Niemeijer, + * Mathias Dalheimer, and "Captain." + * + * The RTC (DS1307) interface code builds in part on code by + * Jon McPhalen (www.jonmcphalen.com) + * + * There you have it. + * + * This code supports the "Atomic Clock" article in the April 2010 issue + * of Popular Science. There is also a schematic for this project. There + * is also WWVB signal simulator code, to facilitate debugging and + * hacking on this project when the reception of the WWVB signal + * itself is less than stellar. + * + * The code for both the clock and the WWVB simulator, and the schematic + * are available online at: + * http://www.popsci.com/diy/article/2010-03/build-clock-uses-atomic-timekeeping + * + * and on GitHub at: http://github.com/vinmarshall/WWVB-Clock + * + * Version 1.0 + * Notes: + * - No timezone support in this version. UTC only. + * - No explicit leapsecond (3 frame marker bits) support in this version. + * - 24 hour mode only + * + * + * Copyright (c) 2010 Vin Marshall (vlm@2552.com, www.2552.com) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define SERIAL_RATE 115200 +#define WWV_SIGNAL_PIN 14 +#define PPS_OUTPUT_PIN 16 +#define DEBUG1_OUTPUT_PIN 15 + + +#include +#include +LiquidCrystal_I2C lcd(0x27, 16, 2); + +void ICACHE_RAM_ATTR wwvbChange(); + +// +// Initializations + +// Debugging mode - prints debugging information on the Serial port. +boolean debug = true; + +// Front Panel Light +int lightPin = LED_BUILTIN; + +// WWVB Receiver Pin +int wwvbInPin = WWV_SIGNAL_PIN; + +// LCD init +//LiquidCrystal lcd(12, 11, 6, 5, 4, 3); + +// RTC init +// RTC uses pins Analog4 = SDA, Analog5 = SCL + +// RTC I2C Slave Address +#define DS1307 0xD0 >> 1 + +// RTC Memory Registers +#define RTC_SECS 0 +#define RTC_MINS 1 +#define RTC_HRS 2 +#define RTC_DAY 3 +#define RTC_DATE 4 +#define RTC_MONTH 5 +#define RTC_YEAR 6 +#define RTC_SQW 7 + +// Month abbreviations +char *months[12] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; + +// Day of Year to month translation (thanks to Capt.Tagon) +// End of Month - to calculate Month and Day from Day of Year +int eomYear[14][2] = { + {0,0}, // Begin + {31,31}, // Jan + {59,60}, // Feb + {90,91}, // Mar + {120,121}, // Apr + {151,152}, // May + {181,182}, // Jun + {212,213}, // Jul + {243,244}, // Aug + {273,274}, // Sep + {304,305}, // Oct + {334,335}, // Nov + {365,366}, // Dec + {366,367} // overflow +}; + + +// +// Globals + +// Timing and error recording +unsigned long pulseStartTime = 0; +unsigned long pulseEndTime = 0; +unsigned long frameEndTime = 0; +unsigned long lastRtcUpdateTime = 0; +boolean bitReceived = false; +boolean wasMark = false; +int framePosition = 0; +int bitPosition = 1; +char lastTimeUpdate[17]; +char lastBit = ' '; +int errors[10] = { 1,1,1,1,1,1,1,1,1,1 }; +int errIdx = 0; +int bitError = 0; +boolean frameError = false; + +// RTC clock variables +byte second = 0x00; +byte minute = 0x00; +byte hour = 0x00; +byte day = 0x00; +byte date = 0x01; +byte month = 0x01; +byte year = 0x00; +byte ctrl = 0x00; + +// WWVB time variables +byte wwvb_hour = 0; +byte wwvb_minute = 0; +byte wwvb_day = 0; +byte wwvb_year = 0; + + +/* WWVB time format struct - acts as an overlay on wwvbRxBuffer to extract time/date data. + * This points to a 64 bit buffer wwvbRxBuffer that the bits get inserted into as the + * incoming data stream is received. (Thanks to Capt.Tagon @ duinolab.blogspot.com) + */ +struct wwvbBuffer { + unsigned long long U12 :4; // no value, empty four bits only 60 of 64 bits used + unsigned long long Frame :2; // framing + unsigned long long Dst :2; // dst flags + unsigned long long Leapsec :1; // leapsecond + unsigned long long Leapyear :1; // leapyear + unsigned long long U11 :1; // no value + unsigned long long YearOne :4; // year (5 -> 2005) + unsigned long long U10 :1; // no value + unsigned long long YearTen :4; // year (5 -> 2005) + unsigned long long U09 :1; // no value + unsigned long long OffVal :4; // offset value + unsigned long long U08 :1; // no value + unsigned long long OffSign :3; // offset sign + unsigned long long U07 :2; // no value + unsigned long long DayOne :4; // day ones + unsigned long long U06 :1; // no value + unsigned long long DayTen :4; // day tens + unsigned long long U05 :1; // no value + unsigned long long DayHun :2; // day hundreds + unsigned long long U04 :3; // no value + unsigned long long HourOne :4; // hours ones + unsigned long long U03 :1; // no value + unsigned long long HourTen :2; // hours tens + unsigned long long U02 :3; // no value + unsigned long long MinOne :4; // minutes ones + unsigned long long U01 :1; // no value + unsigned long long MinTen :3; // minutes tens +}; + +struct wwvbBuffer * wwvbFrame; +unsigned long long receiveBuffer; +unsigned long long lastFrameBuffer; + + +/* + * setup() + * + * uC Initialization + */ + +void setup() { + Serial.begin(SERIAL_RATE); + Serial.println("*****************************************"); + Serial.println("*****************************************"); + Serial.println("*****************************************"); + Serial.print("*** ESP8266 Ready.\n"); + // Initialize the I2C Two Wire Communication for the RTC + //Wire.begin(); + + lcd.init(); + lcd.backlight(); + lcd.setCursor(0, 0); + lcd.print("booting"); + + + // Setup the light pin + pinMode(lightPin, OUTPUT); + digitalWrite(lightPin, LOW); + pinMode(DEBUG1_OUTPUT_PIN, OUTPUT); + + // Print a message to the LCD. + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("WWVB Clock v 1.0"); + lcd.setCursor(0, 1); + lcd.print("PopSci Apr. 2010"); + delay(5000); + + // Front panel light lights for 10 seconds on a successful frame rcpt. + digitalWrite(lightPin, HIGH); + + // Setup the WWVB Signal In Handling + pinMode(wwvbInPin, INPUT); + attachInterrupt(0, wwvbChange, CHANGE); + + // Setup the WWVB Buffer + lastFrameBuffer = 0; + receiveBuffer = 0; + wwvbFrame = (struct wwvbBuffer *) &lastFrameBuffer; + + Serial.println("*** setup() complete"); +} + + +/* + * loop() + * + * Main program loop + */ + +void loop() { + + // If we've received another bit, process it + if (bitReceived == true) { + Serial.println("*** bitReceived==true"); + processBit(); + } + + // Read from the RTC and update the display 4x per second + if (millis() - lastRtcUpdateTime > 250) { + + // Snag the RTC time and store it locally + //getRTC(); + + // And record the time of this last update. + lastRtcUpdateTime = millis(); + + // Update RTC if there has been a successfully received WWVB Frame + if (frameEndTime != 0) { + //updateRTC(); + frameEndTime = 0; + } + + // Update the display + updateDisplay(); + + } + +} + + +/* + * updateDisplay() + * + * Update the 2 line x 16 char LCD display + */ + +void updateDisplay() { + + // Turn off the front panel light marking a successfully + // received frame after 10 seconds of being on. + if (bcd2dec(second) >= 10) { + digitalWrite(lightPin, HIGH); + } + + // Update the LCD + lcd.clear(); + + // Update the first row + lcd.setCursor(0,0); + char *time = buildTimeString(); + lcd.print(time); + + // Update the second row + // Cycle through our list of status messages + lcd.setCursor(0,1); + int cycle = bcd2dec(second) / 10; // This gives us 6 slots for messages + char msg[17]; // 16 chars per line on display + + switch (cycle) { + + // Show the Date + case 0: + { + sprintf(msg, "%s %0.2i 20%0.2i", + months[bcd2dec(month)-1], bcd2dec(date), bcd2dec(year)); + break; + } + + // Show the WWVB signal strength based on the # of recent frame errors + case 1: + { + int signal = (10 - sumFrameErrors()) / 2; + sprintf(msg, "WWVB Signal: %i", signal); + break; + } + + // Show LeapYear and LeapSecond Warning bits + case 2: + { + const char *leapyear = ( ((byte) wwvbFrame->Leapyear) == 1)?"Yes":"No"; + const char *leapsec = ( ((byte) wwvbFrame->Leapsec) == 1)?"Yes":"No"; + sprintf(msg, "LY: %s LS: %s", leapyear, leapsec); + break; + } + + // Show our Daylight Savings Time status + case 3: + { + switch((byte)wwvbFrame->Dst) { + case 0: + sprintf(msg, "DST: No"); + break; + case 1: + sprintf(msg, "DST: Ending"); + break; + case 2: + sprintf(msg, "DST: Starting"); + break; + case 3: + sprintf(msg, "DST: Yes"); + break; + } + break; + } + + // Show the UT1 correction sign and amount + case 4: + { + char sign; + if ((byte)wwvbFrame->OffSign == 2) { + sign = '-'; + } else if ((byte)wwvbFrame->OffSign == 5) { + sign = '+'; + } else { + sign = '?'; + } + sprintf(msg, "UT1 %c 0.%i", sign, (byte) wwvbFrame->OffVal); + break; + } + + // Show the time and date of the last successfully received + // wwvb frame + case 5: + { + sprintf(msg, "[%s]", lastTimeUpdate); + break; + } + } + + lcd.print(msg); + +} + + +/* + * buildTimeString + * + * Prepare the string for displaying the time on line 1 of the LCD + */ + +char* buildTimeString() { + char rv[255]; + sprintf(rv,"%0.2i:%0.2i:%0.2i UTC %c", + bcd2dec(hour), + bcd2dec(minute), + bcd2dec(second), + lastBit); + return rv; +} + + +/* + * getRTC + * + * Read data from the DS1307 RTC over the I2C 2 wire interface. + * Data is stored in the uC's global clock variables. + */ +/* +void getRTC() { + + // Begin the Transmission + Wire.beginTransmission(DS1307); + + // Point the request at the first register (seconds) + Wire.write(RTC_SECS); + + // End the Transmission and Start Listening + Wire.endTransmission(); + Wire.requestFrom(DS1307, 8); + second = Wire.receive(); + minute = Wire.receive(); + hour = Wire.receive(); + day = Wire.receive(); + date = Wire.receive(); + month = Wire.receive(); + year = Wire.receive(); + ctrl = Wire.receive(); +} +*/ + + +/* + * setRTC + * + * Set the DS1307 RTC over the I2C 2 wire interface. + * Data is read from the uC's global clock variables. + */ +/* +void setRTC() { + + // Begin the Transmission + Wire.beginTransmission(DS1307); + + // Start at the beginning + Wire.write(RTC_SECS); + + // Send data for each register in order + Wire.write(second); + Wire.write(minute); + Wire.write(hour); + Wire.send(day); + Wire.send(date); + Wire.send(month); + Wire.send(year); + Wire.send(ctrl); + + // End the transmission + Wire.endTransmission(); +} +*/ + +/* + * updateRTC + * + * Update the time stored in the RTC to match the received WWVB frame. + */ +/* +void updateRTC() { + + // Find out how long since the frame's On Time Marker (OTM) + // We'll need this adjustment when we set the time. + unsigned int timeSinceFrame = millis() - frameEndTime; + byte secondsSinceFrame = timeSinceFrame / 1000; + if (timeSinceFrame % 1000 > 500) { + secondsSinceFrame++; + } + + // The OTM for a minute comes at the beginning of the frame, meaning that + // the WWVB time we have is now 1 minute + `secondsSinceFrame` seconds old. + incrementWwvbMinute(); + + // Set up data for the RTC clock write + second = secondsSinceFrame; + minute = ((byte) wwvbFrame->MinTen << 4) + (byte) wwvbFrame->MinOne; + hour = ((byte) wwvbFrame->HourTen << 4) + (byte) wwvbFrame->HourOne; + day = 0; // we're not using day of week at this time. + + // Translate wwvb day of year into a month and a day of month + // This routine is courtesy of Capt.Tagon + int doy = ((byte) wwvbFrame->DayHun * 100) + + ((byte) wwvbFrame->DayTen * 10) + + ((byte) wwvbFrame->DayOne); + + int i = 0; + byte isLeapyear = (byte) wwvbFrame->Leapyear; + while ( (i < 14) && (eomYear[i][isLeapyear] < doy) ) { + i++; + } + if (i>0) { + date = dec2bcd(doy - eomYear[i-1][isLeapyear]); + month = dec2bcd((i > 12)?1:i); + } + + year = ((byte) wwvbFrame->YearTen << 4) + (byte) wwvbFrame->YearOne; + + // And write the update to the RTC + //setRTC(); + + // Store the time of update for the display status line + sprintf(lastTimeUpdate, "%0.2i:%0.2i %0.2i/%0.2i/%0.2i", + bcd2dec(hour), bcd2dec(minute), bcd2dec(month), + bcd2dec(date), bcd2dec(year)); + +} +*/ + +/* + * processBit() + * + * Decode a received pulse. Pulses are decoded according to the + * length of time the pulse was in the low state. + */ + +void processBit() { + Serial.println("*** in processBit()"); + char buf[255]; + + // Clear the bitReceived flag, as we're processing that bit. + bitReceived = false; + + // determine the width of the received pulse + unsigned int pulseWidth = pulseEndTime - pulseStartTime; + + sprintf(buf,"got bit with pulseWidth=%d\n",pulseWidth); + Serial.print(buf); + + // Attempt to decode the pulse into an Unweighted bit (0), + // a Weighted bit (1), or a Frame marker. + + // Pulses < 0.2 sec are an error in reception. + if (pulseWidth < 100) { + buffer(-2); + bitError++; + wasMark = false; + + // 0.2 sec pulses are an Unweighted bit (0) + } else if (pulseWidth < 400) { + buffer(0); + wasMark = false; + + // 0.5 sec pulses are a Weighted bit (1) + } else if (pulseWidth < 700) { + buffer(1); + wasMark = false; + + // 0.8 sec pulses are a Frame Marker + } else if (pulseWidth < 900) { + + // Two Frame Position markers in a row indicate an + // end/beginning of frame marker + if (wasMark) { + + // For the display update + lastBit = '*'; + Serial.println("*** Frame Start"); + + // Verify that our position data jives with this being + // a Frame start/end marker + if ( (framePosition == 6) && + (bitPosition == 60) && + (bitError == 0)) { + + // Process a received frame + frameEndTime = pulseStartTime; + lastFrameBuffer = receiveBuffer; + digitalWrite(lightPin, LOW); + logFrameError(false); + + debugPrintFrame(); + + } else { + frameError = true; + } + + // Reset the position counters + framePosition = 0; + bitPosition = 1; + wasMark = false; + bitError = 0; + receiveBuffer = 0; + + // Otherwise, this was just a regular frame position marker + } else { + buffer(-1); + wasMark = true; + } + + // Pulses > 0.8 sec are an error in reception + } else { + buffer(-2); + bitError++; + wasMark = false; + } + + // Reset everything if we have more than 60 bits in the frame. This means + // the frame markers went missing somewhere along the line + if (frameError == true || bitPosition > 60) { + + // Debugging + Serial.println("*** Frame Error"); + + // Reset all of the frame pointers and flags + frameError = false; + logFrameError(true); + framePosition = 0; + bitPosition = 1; + wasMark = false; + bitError = 0; + receiveBuffer = 0; + } + +} + + +/* + * logFrameError + * + * Log the error in the buffer that is a window on the past 10 frames. + */ + +void logFrameError(boolean err) { + + // Add a 1 to log errors to the buffer + int add = err?1:0; + errors[errIdx] = add; + + // and move the buffer loop-around pointer + if (++errIdx >= 10) { + errIdx = 0; + } +} + + +/* + * sumFrameErrors + * + * Turn the errors in the frame error buffer into a number useful to display + * the quality of reception of late in the status messages. Sums the errors + * in the frame error buffer. + */ + +int sumFrameErrors() { + + // Sum all of the values in our error buffer + int i, rv; + for (i=0; i< 10; i++) { + rv += errors[i]; + } + + return rv; +} + + +/* + * debugPrintFrame + * + * Print the decoded frame over the seriail port + */ + +void debugPrintFrame() { + char time[255]; + byte minTen = (byte) wwvbFrame->MinTen; + byte minOne = (byte) wwvbFrame->MinOne; + byte hourTen = (byte) wwvbFrame->HourTen; + byte hourOne = (byte) wwvbFrame->HourOne; + byte dayHun = (byte) wwvbFrame->DayHun; + byte dayTen = (byte) wwvbFrame->DayTen; + byte dayOne = (byte) wwvbFrame->DayOne; + byte yearOne = (byte) wwvbFrame->YearOne; + byte yearTen = (byte) wwvbFrame->YearTen; + + byte wwvb_minute = (10 * minTen) + minOne; + byte wwvb_hour = (10 * hourTen) + hourOne; + byte wwvb_day = (100 * dayHun) + (10 * dayTen) + dayOne; + byte wwvb_year = (10 * yearTen) + yearOne; + + sprintf(time, "\nFrame Decoded: %0.2i:%0.2i %0.3i 20%0.2i\n", + wwvb_hour, wwvb_minute, wwvb_day, wwvb_year); + Serial.print(time); + +} + + +/* + * buffer + * + * Places the received bits in the receive buffer in the order they + * were recived. The first received bit goes in the highest order + * bit of the receive buffer. + */ + +void buffer(int bit) { + + // Process our bits + if (bit == 0) { + lastBit = '0'; + if (debug) { Serial.println("0"); } + + } else if (bit == 1) { + lastBit = '1'; + if (debug) { Serial.println("1"); } + + } else if (bit == -1) { + lastBit = 'M'; + if (debug) { Serial.println("M"); } + framePosition++; + + } else if (bit == -2) { + lastBit = 'X'; + if (debug) { Serial.println("X"); } + } + + // Push the bit into the buffer. The 0s and 1s are the only + // ones we care about. + if (bit < 0) { bit = 0; } + receiveBuffer = receiveBuffer | ( (unsigned long long) bit << (64 - bitPosition) ); + + // And increment the counters that keep track of where we are + // in the frame. + bitPosition++; +} + + +/* + * incrementWwvbMinute + * + * The frame On Time Marker occurs at the beginning of the frame. This means + * that the time in the frame is one minute old by the time it has been fully + * received. Adding one to the minute can be somewhat complicated, in as much + * as it can roll over the successive hours, days, and years in just the right + * circumstances. This handles that. + */ + +void incrementWwvbMinute() { + + // Increment the Time and Date + if (++(wwvbFrame->MinOne) == 10) { + wwvbFrame->MinOne = 0; + wwvbFrame->MinTen++; + } + + if (wwvbFrame->MinTen == 6) { + wwvbFrame->MinTen = 0; + wwvbFrame->HourOne++; + } + + if (wwvbFrame->HourOne == 10) { + wwvbFrame->HourOne = 0; + wwvbFrame->HourTen++; + } + + if ( (wwvbFrame->HourTen == 2) && (wwvbFrame->HourOne == 4) ) { + wwvbFrame->HourTen = 0; + wwvbFrame->HourOne = 0; + wwvbFrame->DayOne++; + } + + if (wwvbFrame->DayOne == 10) { + wwvbFrame->DayOne = 0; + wwvbFrame->DayTen++; + } + + if (wwvbFrame->DayTen == 10) { + wwvbFrame->DayTen = 0; + wwvbFrame->DayHun++; + } + + if ( (wwvbFrame->DayHun == 3) && + (wwvbFrame->DayTen == 6) && + (wwvbFrame->DayOne == (6 + (int) wwvbFrame->Leapyear)) ) { + // Happy New Year. + wwvbFrame->DayHun = 0; + wwvbFrame->DayTen = 0; + wwvbFrame->DayOne = 1; + wwvbFrame->YearOne++; + } + + if (wwvbFrame->YearOne == 10) { + wwvbFrame->YearOne = 0; + wwvbFrame->YearTen++; + } + + if (wwvbFrame->YearTen == 10) { + wwvbFrame->YearTen = 0; + } + +} + + +/* + * wwvbChange + * + * This is the interrupt servicing routine. Changes in the level of the + * received WWVB pulse are recorded here to be processed in processBit(). + */ + +void wwvbChange() { + digitalWrite(DEBUG1_OUTPUT_PIN, HIGH); + + int signalLevel = digitalRead(wwvbInPin); + + // Determine if this was triggered by a rising or a falling edge + // and record the pulse low period start and stop times + + //FIXME this might need to be HIGH + if (signalLevel == HIGH) { + pulseStartTime = millis(); + } else { + pulseEndTime = millis(); + bitReceived = true; + } + + digitalWrite(DEBUG1_OUTPUT_PIN, LOW); +} + + + +/* + * bcd2dec + * + * Utility function to convert 2 bcd coded hex digits into an integer + */ + +int bcd2dec(int bcd) { + return ( (bcd>>4) * 10) + (bcd % 16); +} + + +/* + * dec2bcd + * + * Utility function to convert an integer into 2 bcd coded hex digits + */ + +int dec2bcd(int dec) { + return ( (dec/10) << 4) + (dec % 10); +} + + diff --git a/wwvb/floats.csv b/wwvb/floats.csv new file mode 100644 index 0000000..479f0df --- /dev/null +++ b/wwvb/floats.csv @@ -0,0 +1,175 @@ +94.34 +39.62 +67.36 +48.64 +71.57 +78.93 +86.80 +37.59 +41.87 +76.45 +65.54 +70.19 +77.87 +73.15 +70.13 +33.27 +27.52 +87.68 +74.66 +49.75 +74.90 +68.83 +69.74 +58.10 +49.23 +61.75 +94.63 +85.94 +46.70 +68.18 +48.62 +75.80 +50.17 +52.28 +66.22 +68.36 +70.89 +46.68 +71.96 +90.99 +74.44 +97.34 +22.63 +25.14 +54.39 +47.70 +80.27 +75.28 +73.23 +63.09 +71.75 +73.39 +29.64 +60.99 +78.13 +73.29 +52.33 +68.42 +71.71 +60.31 +54.13 +76.60 +58.99 +75.99 +85.64 +74.30 +77.69 +79.76 +79.61 +60.93 +54.99 +45.50 +81.65 +74.05 +67.01 +85.79 +83.92 +76.03 +72.04 +32.79 +33.62 +67.26 +71.17 +78.02 +63.84 +67.86 +58.04 +71.88 +72.92 +72.11 +68.45 +68.71 +93.77 +65.92 +78.33 +63.78 +58.41 +48.74 +71.87 +53.10 +80.33 +58.18 +72.19 +79.94 +85.44 +78.55 +82.78 +71.12 +63.79 +62.94 +63.66 +58.44 +50.59 +91.02 +89.28 +68.35 +86.34 +31.90 +69.33 +65.45 +76.41 +83.79 +73.95 +73.08 +60.52 +51.60 +59.42 +82.91 +82.62 +64.72 +69.13 +67.46 +71.94 +78.55 +73.33 +70.58 +80.87 +77.23 +75.79 +87.83 +88.32 +79.55 +60.92 +71.68 +69.79 +83.03 +89.25 +76.60 +55.45 +67.67 +82.52 +77.72 +65.99 +60.15 +73.46 +68.14 +61.96 +85.54 +64.17 +83.86 +61.66 +79.66 +64.02 +45.70 +76.10 +63.10 +64.77 +94.71 +76.37 +75.78 +76.00 +35.66 +65.96 +68.23 +91.41 diff --git a/wwvb/output.txt b/wwvb/output.txt new file mode 100644 index 0000000..7d43bc2 --- /dev/null +++ b/wwvb/output.txt @@ -0,0 +1,1086 @@ +updateDisplay() +end of frame summary: frameHigh: 34695, frameLow: 2082 +float to attempt to bucket: 94.34 +updateDisplay() +tickInterval: 1140ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 14615, frameLow: 22269 +float to attempt to bucket: 39.62 +updateDisplay() +tickInterval: 1505ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 24736, frameLow: 11987 +float to attempt to bucket: 67.36 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 245 ms high +updateDisplay() +end of frame summary: frameHigh: 17876, frameLow: 18877 +float to attempt to bucket: 48.64 +updateDisplay() +tickInterval: 1094ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 26273, frameLow: 10438 +float to attempt to bucket: 71.57 +updateDisplay() +updateDisplay() +tickInterval: 1086ms +TICK: WWVB going low after 134 ms high +updateDisplay() +end of frame summary: frameHigh: 29047, frameLow: 7752 +float to attempt to bucket: 78.93 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 704 ms high +updateDisplay() +end of frame summary: frameHigh: 31925, frameLow: 4853 +float to attempt to bucket: 86.80 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 776 ms high +updateDisplay() +end of frame summary: frameHigh: 13861, frameLow: 23015 +float to attempt to bucket: 37.59 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 181 ms high +updateDisplay() +end of frame summary: frameHigh: 15438, frameLow: 21432 +float to attempt to bucket: 41.87 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 253 ms high +updateDisplay() +end of frame summary: frameHigh: 28144, frameLow: 8672 +float to attempt to bucket: 76.45 +updateDisplay() +tickInterval: 1140ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 24137, frameLow: 12689 +float to attempt to bucket: 65.54 +updateDisplay() +tickInterval: 1435ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25765, frameLow: 10940 +float to attempt to bucket: 70.19 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 125 ms high +updateDisplay() +end of frame summary: frameHigh: 28579, frameLow: 8124 +float to attempt to bucket: 77.87 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 502 ms high +updateDisplay() +end of frame summary: frameHigh: 26844, frameLow: 9852 +float to attempt to bucket: 73.15 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 352 ms high +updateDisplay() +end of frame summary: frameHigh: 25735, frameLow: 10963 +float to attempt to bucket: 70.13 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 600 ms high +updateDisplay() +end of frame summary: frameHigh: 12220, frameLow: 24511 +float to attempt to bucket: 33.27 +updateDisplay() +updateDisplay() +tickInterval: 1140ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 10140, frameLow: 26710 +float to attempt to bucket: 27.52 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 153 ms high +updateDisplay() +end of frame summary: frameHigh: 32277, frameLow: 4535 +float to attempt to bucket: 87.68 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 414 ms high +updateDisplay() +end of frame summary: frameHigh: 27496, frameLow: 9334 +float to attempt to bucket: 74.66 +updateDisplay() +tickInterval: 1598ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 18290, frameLow: 18476 +float to attempt to bucket: 49.75 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 154 ms high +updateDisplay() +end of frame summary: frameHigh: 27486, frameLow: 9211 +float to attempt to bucket: 74.90 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 476 ms high +updateDisplay() +end of frame summary: frameHigh: 25282, frameLow: 11449 +float to attempt to bucket: 68.83 +updateDisplay() +tickInterval: 1076ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25600, frameLow: 11108 +float to attempt to bucket: 69.74 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 230 ms high +updateDisplay() +end of frame summary: frameHigh: 21338, frameLow: 15388 +float to attempt to bucket: 58.10 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 326 ms high +updateDisplay() +end of frame summary: frameHigh: 18086, frameLow: 18652 +float to attempt to bucket: 49.23 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 137 ms high +updateDisplay() +updateDisplay() +end of frame summary: frameHigh: 22517, frameLow: 13949 +float to attempt to bucket: 61.75 +updateDisplay() +tickInterval: 1070ms +TICK: WWVB going low after 161 ms high +updateDisplay() +end of frame summary: frameHigh: 34783, frameLow: 1974 +float to attempt to bucket: 94.63 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 789 ms high +updateDisplay() +end of frame summary: frameHigh: 31628, frameLow: 5176 +float to attempt to bucket: 85.94 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 752 ms high +updateDisplay() +end of frame summary: frameHigh: 17222, frameLow: 19657 +float to attempt to bucket: 46.70 +updateDisplay() +tickInterval: 1239ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25108, frameLow: 11716 +float to attempt to bucket: 68.18 +updateDisplay() +tickInterval: 1089ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 17927, frameLow: 18941 +float to attempt to bucket: 48.62 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 186 ms high +updateDisplay() +end of frame summary: frameHigh: 27843, frameLow: 8888 +float to attempt to bucket: 75.80 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 189 ms high +updateDisplay() +end of frame summary: frameHigh: 18438, frameLow: 18314 +float to attempt to bucket: 50.17 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 217 ms high +updateDisplay() +end of frame summary: frameHigh: 19211, frameLow: 17537 +float to attempt to bucket: 52.28 +updateDisplay() +tickInterval: 1075ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 24317, frameLow: 12406 +float to attempt to bucket: 66.22 +updateDisplay() +tickInterval: 1139ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25101, frameLow: 11618 +float to attempt to bucket: 68.36 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 263 ms high +updateDisplay() +end of frame summary: frameHigh: 26004, frameLow: 10678 +float to attempt to bucket: 70.89 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 474 ms high +updateDisplay() +end of frame summary: frameHigh: 17154, frameLow: 19596 +float to attempt to bucket: 46.68 +updateDisplay() +updateDisplay() +tickInterval: 1149ms +TICK: WWVB going low after 110 ms high +updateDisplay() +end of frame summary: frameHigh: 26482, frameLow: 10317 +float to attempt to bucket: 71.96 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 714 ms high +updateDisplay() +end of frame summary: frameHigh: 33460, frameLow: 3314 +float to attempt to bucket: 90.99 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 294 ms high +updateDisplay() +end of frame summary: frameHigh: 27412, frameLow: 9413 +float to attempt to bucket: 74.44 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 556 ms high +updateDisplay() +updateDisplay() +updateDisplay() +updateDisplay() +updateDisplay() +updateDisplay() +updateDisplay() +updateDisplay() +updateDisplay() +some signal receivedupdateDisplay() +tickInterval: 8293ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 35784, frameLow: 977 +float to attempt to bucket: 97.34 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 542 ms high +updateDisplay() +updateDisplay() +updateDisplay() +some signal receivedupdateDisplay() +tickInterval: 2426ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 8314, frameLow: 28426 +float to attempt to bucket: 22.63 +updateDisplay() +updateDisplay() +tickInterval: 1139ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 9268, frameLow: 27603 +float to attempt to bucket: 25.14 +updateDisplay() +tickInterval: 1089ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 20059, frameLow: 16820 +float to attempt to bucket: 54.39 +updateDisplay() +tickInterval: 1139ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 17592, frameLow: 19289 +float to attempt to bucket: 47.70 +updateDisplay() +tickInterval: 1457ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 29472, frameLow: 7245 +float to attempt to bucket: 80.27 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 378 ms high +updateDisplay() +end of frame summary: frameHigh: 27663, frameLow: 9083 +float to attempt to bucket: 75.28 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 223 ms high +updateDisplay() +end of frame summary: frameHigh: 26879, frameLow: 9826 +float to attempt to bucket: 73.23 +updateDisplay() +tickInterval: 1079ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 23182, frameLow: 13561 +float to attempt to bucket: 63.09 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 103 ms high +updateDisplay() +end of frame summary: frameHigh: 26359, frameLow: 10378 +float to attempt to bucket: 71.75 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 185 ms high +updateDisplay() +end of frame summary: frameHigh: 26964, frameLow: 9779 +float to attempt to bucket: 73.39 +updateDisplay() +updateDisplay() +tickInterval: 1140ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 10926, frameLow: 25942 +float to attempt to bucket: 29.64 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 237 ms high +updateDisplay() +end of frame summary: frameHigh: 22479, frameLow: 14379 +float to attempt to bucket: 60.99 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 271 ms high +updateDisplay() +end of frame summary: frameHigh: 28783, frameLow: 8058 +float to attempt to bucket: 78.13 +updateDisplay() +tickInterval: 1048ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 27024, frameLow: 9847 +float to attempt to bucket: 73.29 +updateDisplay() +tickInterval: 1139ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 19294, frameLow: 17576 +float to attempt to bucket: 52.33 +updateDisplay() +tickInterval: 1139ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25171, frameLow: 11620 +float to attempt to bucket: 68.42 +updateDisplay() +tickInterval: 1139ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 26340, frameLow: 10392 +float to attempt to bucket: 71.71 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 260 ms high +updateDisplay() +end of frame summary: frameHigh: 22169, frameLow: 14592 +float to attempt to bucket: 60.31 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 132 ms high +updateDisplay() +end of frame summary: frameHigh: 19905, frameLow: 16865 +float to attempt to bucket: 54.13 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 162 ms high +updateDisplay() +end of frame summary: frameHigh: 28130, frameLow: 8591 +float to attempt to bucket: 76.60 +updateDisplay() +tickInterval: 1086ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 21674, frameLow: 15069 +float to attempt to bucket: 58.99 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 126 ms high +updateDisplay() +end of frame summary: frameHigh: 27888, frameLow: 8810 +float to attempt to bucket: 75.99 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 503 ms high +updateDisplay() +end of frame summary: frameHigh: 31444, frameLow: 5273 +float to attempt to bucket: 85.64 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 219 ms high +updateDisplay() +end of frame summary: frameHigh: 27289, frameLow: 9441 +float to attempt to bucket: 74.30 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 111 ms high +updateDisplay() +updateDisplay() +end of frame summary: frameHigh: 28290, frameLow: 8123 +float to attempt to bucket: 77.69 +updateDisplay() +tickInterval: 1092ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 29377, frameLow: 7454 +float to attempt to bucket: 79.76 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 348 ms high +updateDisplay() +end of frame summary: frameHigh: 29322, frameLow: 7510 +float to attempt to bucket: 79.61 +updateDisplay() +tickInterval: 1064ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 22441, frameLow: 14392 +float to attempt to bucket: 60.93 +updateDisplay() +tickInterval: 1065ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 20277, frameLow: 16594 +float to attempt to bucket: 54.99 +updateDisplay() +tickInterval: 1068ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 16780, frameLow: 20096 +float to attempt to bucket: 45.50 +updateDisplay() +tickInterval: 1098ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 30065, frameLow: 6756 +float to attempt to bucket: 81.65 +updateDisplay() +tickInterval: 1086ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 27245, frameLow: 9549 +float to attempt to bucket: 74.05 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 273 ms high +updateDisplay() +end of frame summary: frameHigh: 24613, frameLow: 12117 +float to attempt to bucket: 67.01 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 270 ms high +updateDisplay() +end of frame summary: frameHigh: 31488, frameLow: 5215 +float to attempt to bucket: 85.79 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 367 ms high +updateDisplay() +end of frame summary: frameHigh: 30789, frameLow: 5898 +float to attempt to bucket: 83.92 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 319 ms high +updateDisplay() +end of frame summary: frameHigh: 27893, frameLow: 8796 +float to attempt to bucket: 76.03 +updateDisplay() +tickInterval: 1063ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 26470, frameLow: 10273 +float to attempt to bucket: 72.04 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 110 ms high +updateDisplay() +end of frame summary: frameHigh: 12037, frameLow: 24676 +float to attempt to bucket: 32.79 +updateDisplay() +tickInterval: 1089ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 12362, frameLow: 24403 +float to attempt to bucket: 33.62 +updateDisplay() +updateDisplay() +tickInterval: 1175ms +TICK: WWVB going low after 137 ms high +updateDisplay() +end of frame summary: frameHigh: 24780, frameLow: 12062 +float to attempt to bucket: 67.26 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 435 ms high +updateDisplay() +end of frame summary: frameHigh: 26213, frameLow: 10619 +float to attempt to bucket: 71.17 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 329 ms high +updateDisplay() +end of frame summary: frameHigh: 28743, frameLow: 8096 +float to attempt to bucket: 78.02 +updateDisplay() +tickInterval: 1039ms +TICK: WWVB going low after 191 ms high +updateDisplay() +end of frame summary: frameHigh: 23525, frameLow: 13327 +float to attempt to bucket: 63.84 +updateDisplay() +tickInterval: 1097ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25006, frameLow: 11843 +float to attempt to bucket: 67.86 +updateDisplay() +tickInterval: 1086ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 21416, frameLow: 15484 +float to attempt to bucket: 58.04 +updateDisplay() +tickInterval: 1042ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 26469, frameLow: 10356 +float to attempt to bucket: 71.88 +updateDisplay() +tickInterval: 1077ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 26861, frameLow: 9977 +float to attempt to bucket: 72.92 +updateDisplay() +tickInterval: 1038ms +TICK: WWVB going low after 102 ms high +updateDisplay() +end of frame summary: frameHigh: 26519, frameLow: 10256 +float to attempt to bucket: 72.11 +updateDisplay() +tickInterval: 1099ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25099, frameLow: 11570 +float to attempt to bucket: 68.45 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 190 ms high +updateDisplay() +end of frame summary: frameHigh: 25172, frameLow: 11462 +float to attempt to bucket: 68.71 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 102 ms high +updateDisplay() +end of frame summary: frameHigh: 34294, frameLow: 2278 +float to attempt to bucket: 93.77 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 433 ms high +updateDisplay() +end of frame summary: frameHigh: 24154, frameLow: 12488 +float to attempt to bucket: 65.92 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 121 ms high +updateDisplay() +end of frame summary: frameHigh: 28675, frameLow: 7935 +float to attempt to bucket: 78.33 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 166 ms high +updateDisplay() +end of frame summary: frameHigh: 23361, frameLow: 13264 +float to attempt to bucket: 63.78 +updateDisplay() +tickInterval: 1141ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 21413, frameLow: 15248 +float to attempt to bucket: 58.41 +updateDisplay() +updateDisplay() +tickInterval: 1106ms +TICK: WWVB going low after 119 ms high +updateDisplay() +end of frame summary: frameHigh: 17947, frameLow: 18875 +float to attempt to bucket: 48.74 +updateDisplay() +tickInterval: 1041ms +TICK: WWVB going low after 113 ms high +updateDisplay() +end of frame summary: frameHigh: 26423, frameLow: 10344 +float to attempt to bucket: 71.87 +updateDisplay() +tickInterval: 1060ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 19536, frameLow: 17258 +float to attempt to bucket: 53.10 +updateDisplay() +tickInterval: 1141ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 29522, frameLow: 7231 +float to attempt to bucket: 80.33 +updateDisplay() +tickInterval: 1332ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 21334, frameLow: 15333 +float to attempt to bucket: 58.18 +updateDisplay() +tickInterval: 1093ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 26457, frameLow: 10193 +float to attempt to bucket: 72.19 +updateDisplay() +tickInterval: 1046ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 29296, frameLow: 7352 +float to attempt to bucket: 79.94 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 186 ms high +updateDisplay() +end of frame summary: frameHigh: 31284, frameLow: 5330 +float to attempt to bucket: 85.44 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 500 ms high +updateDisplay() +end of frame summary: frameHigh: 28766, frameLow: 7854 +float to attempt to bucket: 78.55 +updateDisplay() +tickInterval: 1141ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 30314, frameLow: 6304 +float to attempt to bucket: 82.78 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 272 ms high +updateDisplay() +updateDisplay() +end of frame summary: frameHigh: 25686, frameLow: 10431 +float to attempt to bucket: 71.12 +updateDisplay() +tickInterval: 1784ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 23384, frameLow: 13273 +float to attempt to bucket: 63.79 +updateDisplay() +tickInterval: 1058ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 23079, frameLow: 13590 +float to attempt to bucket: 62.94 +updateDisplay() +tickInterval: 1091ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 23329, frameLow: 13319 +float to attempt to bucket: 63.66 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 347 ms high +updateDisplay() +end of frame summary: frameHigh: 21412, frameLow: 15225 +float to attempt to bucket: 58.44 +updateDisplay() +updateDisplay() +tickInterval: 1087ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 18619, frameLow: 18183 +float to attempt to bucket: 50.59 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 167 ms high +updateDisplay() +end of frame summary: frameHigh: 33407, frameLow: 3296 +float to attempt to bucket: 91.02 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 302 ms high +updateDisplay() +end of frame summary: frameHigh: 32769, frameLow: 3936 +float to attempt to bucket: 89.28 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 804 ms high +updateDisplay() +end of frame summary: frameHigh: 25114, frameLow: 11628 +float to attempt to bucket: 68.35 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 586 ms high +updateDisplay() +end of frame summary: frameHigh: 31722, frameLow: 5018 +float to attempt to bucket: 86.34 +updateDisplay() +tickInterval: 1141ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 11736, frameLow: 25054 +float to attempt to bucket: 31.90 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 102 ms high +updateDisplay() +end of frame summary: frameHigh: 25481, frameLow: 11273 +float to attempt to bucket: 69.33 +updateDisplay() +tickInterval: 1098ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 24059, frameLow: 12699 +float to attempt to bucket: 65.45 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 151 ms high +updateDisplay() +end of frame summary: frameHigh: 27949, frameLow: 8631 +float to attempt to bucket: 76.41 +updateDisplay() +tickInterval: 1095ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 30699, frameLow: 5938 +float to attempt to bucket: 83.79 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 347 ms high +updateDisplay() +end of frame summary: frameHigh: 27091, frameLow: 9542 +float to attempt to bucket: 73.95 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 348 ms high +updateDisplay() +end of frame summary: frameHigh: 26743, frameLow: 9851 +float to attempt to bucket: 73.08 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 368 ms high +updateDisplay() +end of frame summary: frameHigh: 22166, frameLow: 14461 +float to attempt to bucket: 60.52 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 143 ms high +updateDisplay() +end of frame summary: frameHigh: 18907, frameLow: 17736 +float to attempt to bucket: 51.60 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 183 ms high +updateDisplay() +end of frame summary: frameHigh: 21781, frameLow: 14873 +float to attempt to bucket: 59.42 +updateDisplay() +tickInterval: 1092ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 30379, frameLow: 6260 +float to attempt to bucket: 82.91 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 110 ms high +updateDisplay() +end of frame summary: frameHigh: 30234, frameLow: 6358 +float to attempt to bucket: 82.62 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 668 ms high +updateDisplay() +updateDisplay() +end of frame summary: frameHigh: 23245, frameLow: 12671 +float to attempt to bucket: 64.72 +updateDisplay() +tickInterval: 1440ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25432, frameLow: 11357 +float to attempt to bucket: 69.13 +updateDisplay() +tickInterval: 1085ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 24743, frameLow: 11934 +float to attempt to bucket: 67.46 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 274 ms high +updateDisplay() +end of frame summary: frameHigh: 26345, frameLow: 10275 +float to attempt to bucket: 71.94 +updateDisplay() +tickInterval: 1141ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 28772, frameLow: 7857 +float to attempt to bucket: 78.55 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 455 ms high +updateDisplay() +end of frame summary: frameHigh: 26859, frameLow: 9768 +float to attempt to bucket: 73.33 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 209 ms high +updateDisplay() +end of frame summary: frameHigh: 25837, frameLow: 10768 +float to attempt to bucket: 70.58 +updateDisplay() +tickInterval: 1083ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 29621, frameLow: 7006 +float to attempt to bucket: 80.87 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 620 ms high +updateDisplay() +end of frame summary: frameHigh: 28276, frameLow: 8339 +float to attempt to bucket: 77.23 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 596 ms high +updateDisplay() +end of frame summary: frameHigh: 27760, frameLow: 8866 +float to attempt to bucket: 75.79 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 368 ms high +updateDisplay() +updateDisplay() +end of frame summary: frameHigh: 31857, frameLow: 4415 +float to attempt to bucket: 87.83 +updateDisplay() +tickInterval: 1072ms +TICK: WWVB going low after 593 ms high +updateDisplay() +end of frame summary: frameHigh: 32444, frameLow: 4289 +float to attempt to bucket: 88.32 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 419 ms high +updateDisplay() +end of frame summary: frameHigh: 29228, frameLow: 7512 +float to attempt to bucket: 79.55 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 465 ms high +updateDisplay() +end of frame summary: frameHigh: 22413, frameLow: 14378 +float to attempt to bucket: 60.92 +updateDisplay() +tickInterval: 1094ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 26347, frameLow: 10411 +float to attempt to bucket: 71.68 +updateDisplay() +tickInterval: 1141ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 25662, frameLow: 11109 +float to attempt to bucket: 69.79 +updateDisplay() +tickInterval: 1478ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 30417, frameLow: 6217 +float to attempt to bucket: 83.03 +updateDisplay() +tickInterval: 1054ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 32663, frameLow: 3935 +float to attempt to bucket: 89.25 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 705 ms high +updateDisplay() +end of frame summary: frameHigh: 28041, frameLow: 8568 +float to attempt to bucket: 76.60 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 482 ms high +updateDisplay() +updateDisplay() +end of frame summary: frameHigh: 20150, frameLow: 16192 +float to attempt to bucket: 55.45 +updateDisplay() +tickInterval: 1073ms +TICK: WWVB going low after 298 ms high +updateDisplay() +end of frame summary: frameHigh: 24909, frameLow: 11901 +float to attempt to bucket: 67.67 +updateDisplay() +tickInterval: 1060ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 30337, frameLow: 6428 +float to attempt to bucket: 82.52 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 494 ms high +updateDisplay() +end of frame summary: frameHigh: 28559, frameLow: 8189 +float to attempt to bucket: 77.72 +updateDisplay() +tickInterval: 1591ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 24182, frameLow: 12462 +float to attempt to bucket: 65.99 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 120 ms high +updateDisplay() +end of frame summary: frameHigh: 22041, frameLow: 14601 +float to attempt to bucket: 60.15 +updateDisplay() +tickInterval: 1050ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 26930, frameLow: 9730 +float to attempt to bucket: 73.46 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 353 ms high +updateDisplay() +end of frame summary: frameHigh: 24971, frameLow: 11676 +float to attempt to bucket: 68.14 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 123 ms high +updateDisplay() +end of frame summary: frameHigh: 22708, frameLow: 13944 +float to attempt to bucket: 61.96 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 229 ms high +updateDisplay() +end of frame summary: frameHigh: 31290, frameLow: 5289 +float to attempt to bucket: 85.54 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 680 ms high +updateDisplay() +updateDisplay() +end of frame summary: frameHigh: 22997, frameLow: 12843 +float to attempt to bucket: 64.17 +updateDisplay() +tickInterval: 1059ms +TICK: WWVB going low after 161 ms high +updateDisplay() +end of frame summary: frameHigh: 30818, frameLow: 5931 +float to attempt to bucket: 83.86 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 252 ms high +updateDisplay() +end of frame summary: frameHigh: 22676, frameLow: 14100 +float to attempt to bucket: 61.66 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 237 ms high +updateDisplay() +end of frame summary: frameHigh: 29249, frameLow: 7468 +float to attempt to bucket: 79.66 +updateDisplay() +updateDisplay() +tickInterval: 1894ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 23549, frameLow: 13236 +float to attempt to bucket: 64.02 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 441 ms high +updateDisplay() +end of frame summary: frameHigh: 16808, frameLow: 19971 +float to attempt to bucket: 45.70 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 150 ms high +updateDisplay() +end of frame summary: frameHigh: 27973, frameLow: 8786 +float to attempt to bucket: 76.10 +updateDisplay() +tickInterval: 1053ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 23223, frameLow: 13582 +float to attempt to bucket: 63.10 +updateDisplay() +tickInterval: 1064ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 23810, frameLow: 12953 +float to attempt to bucket: 64.77 +updateDisplay() +tickInterval: 1141ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 34772, frameLow: 1942 +float to attempt to bucket: 94.71 +updateDisplay() +tickInterval: 1073ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 28071, frameLow: 8685 +float to attempt to bucket: 76.37 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 160 ms high +updateDisplay() +end of frame summary: frameHigh: 27815, frameLow: 8888 +float to attempt to bucket: 75.78 +updateDisplay() +tickInterval: 1259ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 27834, frameLow: 8792 +float to attempt to bucket: 76.00 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 251 ms high +updateDisplay() +end of frame summary: frameHigh: 13060, frameLow: 23566 +float to attempt to bucket: 35.66 +updateDisplay() +updateDisplay() +tickInterval: 1277ms +TICK: WWVB going low after 101 ms high +updateDisplay() +end of frame summary: frameHigh: 24272, frameLow: 12524 +float to attempt to bucket: 65.96 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 319 ms high +updateDisplay() +end of frame summary: frameHigh: 25079, frameLow: 11676 +float to attempt to bucket: 68.23 +updateDisplay() +tickInterval: 1040ms +TICK: WWVB going low after 122 ms high +updateDisplay() +end of frame summary: frameHigh: 33552, frameLow: 3152 +float to attempt to bucket: 91.41 +updateDisplay() +tickInterval: 1310ms +TICK: WWVB going low after 101 ms high +updateDisplay() diff --git a/wwvb/wwvb.ino b/wwvb/wwvb.ino new file mode 100644 index 0000000..ede265f --- /dev/null +++ b/wwvb/wwvb.ino @@ -0,0 +1,482 @@ +#include +LiquidCrystal_I2C lcd(0x27, 16, 2); + +#define SERIAL_RATE 115200 +#define WWV_SIGNAL_PIN 14 +#define PPS_OUTPUT_PIN 16 +#define DEBUG1_OUTPUT_PIN 15 + +#define ONEBIT 1 +#define ZEROBIT 2 +#define MARKBIT 3 + +#define DEBUG false + +// we sample once per ms: +#define NUM_SAMPLES_PER_FRAME 700 + +#define CLOCKS_PER_MS 10 + +char statusString[25] = "LOS"; + +volatile unsigned int lowLatencyInState; +volatile unsigned int wwvbInState; +volatile unsigned int lastWWVBInState; + +volatile unsigned int stateStableCounter = 0; +volatile unsigned int stateStableMillis = 0; +volatile unsigned int lastStateStableMillis = 0; + +volatile unsigned int secondCounter = 0; +volatile unsigned int milliCounter = 0; +volatile unsigned int clockCounter = 0; + +volatile unsigned int timeToTick = 0; +volatile unsigned int oldLastLowMillis = 0; +volatile unsigned int lastLowMillis = 0; +volatile unsigned int oldLastHighMillis = 0; +volatile unsigned int lastHighMillis = 0; +volatile unsigned int frameReadyToStart = 0; +volatile unsigned int beginFrameSearch = 0; +volatile unsigned int frameSamples = 0; +volatile unsigned int lossOfSignal = 1; +volatile unsigned int displayUpdateRequired = 1; +volatile unsigned int frameSearch = 0; +volatile unsigned int frameStart = 0; +volatile unsigned int frameStartTime = 0; +volatile unsigned int frameHigh = 0; +volatile unsigned int frameHighReadOut = 0; +volatile unsigned int frameLow = 0; +volatile unsigned int frameLowReadOut = 0; +volatile unsigned int frameCounter = 0; +volatile unsigned int frameReadyForRead = 0; +volatile unsigned int lastBitReceived = 0; +volatile unsigned int millisSinceBoot = 0; +volatile unsigned int ppsActivationTime; +volatile unsigned int millisSinceSignalStateChange = 0; +volatile unsigned int minuteSync = 0; + +void ICACHE_RAM_ATTR WWVFallingEdge(); +void ICACHE_RAM_ATTR OSCEdge(); +void ICACHE_RAM_ATTR MilliEdge(); +void ICACHE_RAM_ATTR SecondEdge(); + + +#include "ESP8266TimerInterrupt.h" +ESP8266Timer ITimer; + +void setup() { + Serial.begin(SERIAL_RATE); + while (!Serial); + delay(200); + Serial.print("\n\n\n"); + Serial.println("************************************************"); + Serial.println("************************************************"); + Serial.println("*** ESP8266 Ready."); + Serial.println("************************************************"); + Serial.print(F("\nStarting WWVB on ")); + Serial.println(ARDUINO_BOARD); + Serial.println(ESP8266_TIMER_INTERRUPT_VERSION); + Serial.print(F("CPU Frequency = ")); + Serial.print(F_CPU / 1000000); + Serial.println(F(" MHz")); + + pinMode(LED_BUILTIN, OUTPUT); + pinMode(PPS_OUTPUT_PIN, OUTPUT); + pinMode(DEBUG1_OUTPUT_PIN, OUTPUT); + pinMode(WWV_SIGNAL_PIN, INPUT); + + // 100us timer: + if (ITimer.attachInterruptInterval(100, TimerHandler)) { + Serial.print(F("Starting ITimer OK, millis() = ")); Serial.println(millis()); + } else { + Serial.println(F("Can't set ITimer. Select another freq. or timer")); + } + + //attachInterrupt(digitalPinToInterrupt(LOSC_INPUT_PIN), OSCEdge, RISING); + lcd.init(); + lcd.backlight(); + lcd.setCursor(0, 0); + lcd.print("booting"); + + ppsActivationTime = millis(); +} + +void TimerHandler() { + //Serial.print(F("in timer OK, millis() = ")); Serial.println(millis()); + clockCounter++; + if(clockCounter > CLOCKS_PER_MS) { + clockCounter -= CLOCKS_PER_MS; + + // ***************************************************************************** + // LOW LATENCY HACK to respond in 100us to a falling + // start-of-second edge + // respond really fast to a falling edge if in the frameReadyToStart + // state + lowLatencyInState = digitalRead(WWV_SIGNAL_PIN); + if(!lowLatencyInState && frameReadyToStart && !lossOfSignal && !frameStart) { + // TICK! + // falling edge, beginning of a new frame and second + digitalWrite(PPS_OUTPUT_PIN, 1); + timeToTick = 1; + frameStart = 1; + frameStartTime = millisSinceBoot; + frameReadyToStart = 0; + frameSearch = 0; + } + // ***************************************************************************** + MilliEdge(); + } +} + +void SecondEdge() { + secondCounter++; + displayUpdateRequired = 1; +} + +void MilliEdge() { + digitalWrite(DEBUG1_OUTPUT_PIN, 1); + wwvbInState = digitalRead(WWV_SIGNAL_PIN); + + milliCounter++; + millisSinceBoot++; + + if(milliCounter > 1000) { + milliCounter -= 1000; + SecondEdge(); + } + + if(wwvbInState && (wwvbInState != lastWWVBInState)) { + // we are on the rising edge, last low was 1ms ago + oldLastLowMillis = lastLowMillis; + lastLowMillis = millisSinceBoot - 1; + } + + if(!wwvbInState && (wwvbInState != lastWWVBInState)) { + // we are on the falling edge, last high was 1ms ago + oldLastHighMillis = lastHighMillis; + lastHighMillis = millisSinceBoot - 1; + } + + + if(wwvbInState != lastWWVBInState) { + // we are on an edge + stateStableMillis = 0; + } else { + // nothing happening + stateStableMillis++; + } + + if(wwvbInState && (stateStableMillis > 180) && (stateStableMillis < 2000)) { + // if we are high but for less than 2s + // main screen turn on + lossOfSignal = 0; + frameSearch = 1; + } + + lastWWVBInState = wwvbInState; // copy/save for next loop + + if((stateStableMillis > 2000) && !lossOfSignal) { + // we have received nothing for 2 seconds, loss of signal: + lossOfSignal = 1; + frameStart = 0; + frameCounter = 0; + minuteSync = 0; + digitalWrite(DEBUG1_OUTPUT_PIN, 0); + return; + } + + if(!frameStart && frameSearch && wwvbInState) { + // if we have been high for 180ms (frameSearch) we are ready to start a new frame on the mark + frameHigh = 0; + frameLow = 0; + frameReadyToStart = 1; + digitalWrite(DEBUG1_OUTPUT_PIN, 0); + return; + } + + // frameReadyToStart -> frameStart (and PPS) happens in a 100us + // ISR above. + + if (frameStart && (frameSamples < NUM_SAMPLES_PER_FRAME)) { + frameSearch = 0; + //begin sampling + if (wwvbInState) { + frameHigh++; + } else { + frameLow++; + } + frameSamples++; + digitalWrite(DEBUG1_OUTPUT_PIN, 0); + return; + } + + if(frameStart && (frameSamples >= NUM_SAMPLES_PER_FRAME)) { + frameReadyForRead = 1; + frameHighReadOut = frameHigh; + frameLowReadOut = frameLow; + frameStart = 0; + frameHigh = 0; + frameLow = 0; + frameSamples = 0; + } + digitalWrite(DEBUG1_OUTPUT_PIN, 0); +} + +char pb[255]; +void loop() { + digitalWrite(LED_BUILTIN, !wwvbInState); + + if(timeToTick) { + timeToTick = 0; + TickSecond(); + } + + yield(); + + if(frameReadyForRead) { + frameReadyForRead = 0; + processFrame(); + } + + yield(); + + PPSLowIfRequired(); + + yield(); + + if (displayUpdateRequired) { + updateDisplay(); + displayUpdateRequired = 0; + } +} + +void SetPPSHigh() { + digitalWrite(PPS_OUTPUT_PIN, 1); +} + +void SetPPSLow() { + digitalWrite(PPS_OUTPUT_PIN, 0); +} + +void SendPPS() { + unsigned int tickInterval = millisSinceBoot - ppsActivationTime; + ppsActivationTime = millisSinceBoot; + SetPPSHigh(); +} + +void PPSLowIfRequired() { + if ((millisSinceBoot - ppsActivationTime) > 500) { + SetPPSLow(); + } +} + +void TickSecond() { + char buf[255]; + sprintf(buf, "*** TICK(%d): WWVB going low after %d ms high (EDGE)\n", frameCounter, millisSinceBoot - lastLowMillis); + SendPPS(); + Serial.print(buf); +} + +void processFrame() { + char buf[255]; + sprintf(buf, "end of frame summary: frameHigh: %d, frameLow: %d\n", frameHighReadOut, frameLowReadOut); + Serial.print(buf); + float rawVal = + (float)frameHighReadOut + / + ( (float)frameHighReadOut + (float)frameLowReadOut ); + + rawVal *= 1000; + unsigned int intRawVal = (int)rawVal; + if (intRawVal > 100000) { + intRawVal = 100000; + } + displayUpdateRequired++; + registerBit(convertDutyCycleToBit(intRawVal)); +} + +int convertDutyCycleToBit(unsigned int rawVal) { + char buf[255]; + /* + + 20% - marker + 50% - one bit + 80% - zero bit + our cutoff points will be 50% and 80% + */ + char bitbuf[20]; + + int output = 0; + + output = ZEROBIT; + sprintf(bitbuf, "ZERO"); + + if (rawVal < 800) { + output = ONEBIT; + sprintf(bitbuf, "ONE"); + } + + if (rawVal < 680) { + output = MARKBIT; + sprintf(bitbuf, "MARK"); + } + + sprintf(buf, "frame rawVal=%d, bit=%s\n", rawVal, bitbuf); + Serial.print(buf); + return output; +} + +void registerBit(int doot) { + if (minuteSync) { + frameCounter++; + } + + if (doot == MARKBIT) { + if (lastBitReceived == MARKBIT) { + // two mark bits in a row means we are in the first second of the minute + frameCounter = 0; + minuteSync = 1; + } + } + + if (!minuteSync) { + frameCounter = 0; + } + + sanityCheckFrame(doot); + lastBitReceived = doot; + logBit(doot); +} + +void logBit(int doot) { + +} + +void lossOfSync(int errorFrame) { + char buf[255]; + sprintf(buf, "ERROR: %d bit incorrect for framing, loss of sync!\n", errorFrame); + Serial.print(buf); + minuteSync = 0; + displayUpdateRequired++; +} + + +void sanityCheckFrame(int doot) { + if ( + ( + (frameCounter == 9) + || + (frameCounter == 19) + || + (frameCounter == 29) + || + (frameCounter == 39) + || + (frameCounter == 49) + ) + && doot != MARKBIT) { + lossOfSync(frameCounter); + } + + if ( + (doot == MARKBIT) + && + ( + (frameCounter != 0) + && + (frameCounter != 9) + && + (frameCounter != 19) + && + (frameCounter != 29) + && + (frameCounter != 39) + && + (frameCounter != 49) + ) + ) { + lossOfSync(frameCounter); + } +} + +void updateDisplay() { + //Serial.print("updateDisplay()\n"); + + if (lossOfSignal) { + sprintf(statusString, "LOS"); + } + + if (millisSinceBoot - frameStartTime < 10000) { + sprintf(statusString, "RX(syncing)"); + } + if (minuteSync) { + sprintf(statusString, "RX(bit %d)", frameCounter); + } + + char d[20]; + + if (lastBitReceived == MARKBIT) { + sprintf(d, "%d=MARK", frameCounter); + } + if (lastBitReceived == ONEBIT) { + sprintf(d, "%d=ONE ", frameCounter); + } + if (lastBitReceived == ZEROBIT) { + sprintf(d, "%d=ZERO", frameCounter); + } + + lcd.clear(); + lcd.setCursor(0, 0); + char msg[20]; + sprintf(msg, "up:%03d", secondCounter); + lcd.print(msg); + lcd.setCursor(0, 1); + sprintf(msg, "s:%s", statusString); + lcd.print(msg); + + if (minuteSync) { + lcd.setCursor(10, 0); + lcd.print(d); + } + + if(DEBUG) { + if(secondCounter % 10 == 0) { + serialDebug(); + } + } +} + +void fastSerialDebug() { + char buf[255]; + sprintf(buf,"stateStableMillis=%d\n",stateStableMillis); + Serial.print(buf); +} + +void serialDebug() { + char buf[255]; + sprintf(buf,"lossOfSignal=%d\n",lossOfSignal); + Serial.print(buf); + sprintf(buf,"frameReadyToStart=%d\n",frameReadyToStart); + Serial.print(buf); + sprintf(buf,"beginFrameSearch=%d\n",beginFrameSearch); + Serial.print(buf); + sprintf(buf,"frameSearch=%d\n",frameSearch); + Serial.print(buf); + sprintf(buf,"frameStart=%d\n",frameStart); + Serial.print(buf); + sprintf(buf,"frameStartTime=%d\n",frameStartTime); + Serial.print(buf); + sprintf(buf,"millisSinceBoot=%d\n",millisSinceBoot); + Serial.print(buf); + sprintf(buf,"frameStartAge=%d\n",millisSinceBoot-frameStartTime); + Serial.print(buf); + sprintf(buf,"secondCounter=%d\n",secondCounter); + Serial.print(buf); + sprintf(buf,"timeToTick=%d\n",timeToTick); + Serial.print(buf); + sprintf(buf,"frameHigh=%d\n",frameHigh); + Serial.print(buf); + sprintf(buf,"frameLow=%d\n",frameLow); + Serial.print(buf); +}