Compare commits
2 Commits
master
...
b56272cfc6
Author | SHA1 | Date | |
---|---|---|---|
b56272cfc6 | |||
24c079663d |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.DS_Store
|
230
wwvb/wwvb.ino
230
wwvb/wwvb.ino
@ -12,11 +12,10 @@ LiquidCrystal_I2C lcd(0x27, 16, 2);
|
|||||||
|
|
||||||
#define DEBUG false
|
#define DEBUG false
|
||||||
|
|
||||||
// we sample once per ms:
|
|
||||||
#define NUM_SAMPLES_PER_FRAME 700
|
|
||||||
|
|
||||||
#define CLOCKS_PER_MS 10
|
#define CLOCKS_PER_MS 10
|
||||||
|
|
||||||
|
#define PPS_PULSEWIDTH_MS 100
|
||||||
|
|
||||||
char statusString[25] = "LOS";
|
char statusString[25] = "LOS";
|
||||||
|
|
||||||
volatile unsigned int lowLatencyInState;
|
volatile unsigned int lowLatencyInState;
|
||||||
@ -31,37 +30,29 @@ volatile unsigned int secondCounter = 0;
|
|||||||
volatile unsigned int milliCounter = 0;
|
volatile unsigned int milliCounter = 0;
|
||||||
volatile unsigned int clockCounter = 0;
|
volatile unsigned int clockCounter = 0;
|
||||||
|
|
||||||
|
volatile unsigned int highFor = 0;
|
||||||
|
volatile unsigned int lowFor = 0;
|
||||||
|
|
||||||
|
volatile unsigned int lastBitHighMS = 0;
|
||||||
volatile unsigned int timeToTick = 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 frameSamples = 0;
|
||||||
volatile unsigned int lossOfSignal = 1;
|
volatile unsigned int lossOfSignal = 1;
|
||||||
volatile unsigned int displayUpdateRequired = 1;
|
volatile unsigned int displayUpdateRequired = 1;
|
||||||
volatile unsigned int frameSearch = 0;
|
volatile unsigned int waitingForSecond = 0;
|
||||||
volatile unsigned int frameStart = 0;
|
volatile unsigned int frameStart = 0;
|
||||||
volatile unsigned int frameStartTime = 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 frameCounter = 0;
|
||||||
volatile unsigned int frameReadyForRead = 0;
|
volatile unsigned int bitReadyForRead = 0;
|
||||||
volatile unsigned int lastBitReceived = 0;
|
volatile unsigned int lastBitReceived = 0;
|
||||||
volatile unsigned int millisSinceBoot = 0;
|
volatile unsigned int millisSinceBoot = 0;
|
||||||
volatile unsigned int ppsActivationTime;
|
volatile unsigned int ppsActivationTime = 0;
|
||||||
volatile unsigned int millisSinceSignalStateChange = 0;
|
volatile unsigned int millisSinceSignalStateChange = 0;
|
||||||
volatile unsigned int minuteSync = 0;
|
volatile unsigned int minuteSync = 0;
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR WWVFallingEdge();
|
void ICACHE_RAM_ATTR TimerHandler();
|
||||||
void ICACHE_RAM_ATTR OSCEdge();
|
|
||||||
void ICACHE_RAM_ATTR MilliEdge();
|
void ICACHE_RAM_ATTR MilliEdge();
|
||||||
void ICACHE_RAM_ATTR SecondEdge();
|
void ICACHE_RAM_ATTR SecondEdge();
|
||||||
|
|
||||||
|
|
||||||
#include "ESP8266TimerInterrupt.h"
|
#include "ESP8266TimerInterrupt.h"
|
||||||
ESP8266Timer ITimer;
|
ESP8266Timer ITimer;
|
||||||
|
|
||||||
@ -74,10 +65,12 @@ void setup() {
|
|||||||
Serial.println("************************************************");
|
Serial.println("************************************************");
|
||||||
Serial.println("*** ESP8266 Ready.");
|
Serial.println("*** ESP8266 Ready.");
|
||||||
Serial.println("************************************************");
|
Serial.println("************************************************");
|
||||||
Serial.print(F("\nStarting WWVB on "));
|
Serial.println("************************************************");
|
||||||
|
Serial.print("\n\n\n");
|
||||||
|
Serial.print(F("*** Starting WWVB on "));
|
||||||
Serial.println(ARDUINO_BOARD);
|
Serial.println(ARDUINO_BOARD);
|
||||||
Serial.println(ESP8266_TIMER_INTERRUPT_VERSION);
|
Serial.println(ESP8266_TIMER_INTERRUPT_VERSION);
|
||||||
Serial.print(F("CPU Frequency = "));
|
Serial.print(F("*** CPU Frequency = "));
|
||||||
Serial.print(F_CPU / 1000000);
|
Serial.print(F_CPU / 1000000);
|
||||||
Serial.println(F(" MHz"));
|
Serial.println(F(" MHz"));
|
||||||
|
|
||||||
@ -88,43 +81,36 @@ void setup() {
|
|||||||
|
|
||||||
// 100us timer:
|
// 100us timer:
|
||||||
if (ITimer.attachInterruptInterval(100, TimerHandler)) {
|
if (ITimer.attachInterruptInterval(100, TimerHandler)) {
|
||||||
Serial.print(F("Starting ITimer OK, millis() = ")); Serial.println(millis());
|
Serial.print(F("Starting ITimer OK, millis() = "));
|
||||||
|
Serial.println(millis());
|
||||||
} else {
|
} else {
|
||||||
Serial.println(F("Can't set ITimer. Select another freq. or timer"));
|
Serial.println(
|
||||||
|
F("Can't set ITimer. Select another freq. or timer")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//attachInterrupt(digitalPinToInterrupt(LOSC_INPUT_PIN), OSCEdge, RISING);
|
|
||||||
lcd.init();
|
lcd.init();
|
||||||
lcd.backlight();
|
lcd.backlight();
|
||||||
lcd.setCursor(0, 0);
|
lcd.setCursor(0, 0);
|
||||||
lcd.print("booting");
|
lcd.print("booting");
|
||||||
|
|
||||||
ppsActivationTime = millis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimerHandler() {
|
void TimerHandler() {
|
||||||
//Serial.print(F("in timer OK, millis() = ")); Serial.println(millis());
|
|
||||||
clockCounter++;
|
clockCounter++;
|
||||||
|
|
||||||
|
// *****************************************************************
|
||||||
|
// *****************************************************************
|
||||||
|
// LOW LATENCY HACK to respond in 100us to a falling start-of-second
|
||||||
|
// edge respond really fast to a falling edge if in the waitingForSecond
|
||||||
|
// state
|
||||||
|
//lowLatencyInState = digitalRead(WWV_SIGNAL_PIN);
|
||||||
|
wwvbInState = digitalRead(WWV_SIGNAL_PIN);
|
||||||
|
// *****************************************************************
|
||||||
|
// *****************************************************************
|
||||||
|
|
||||||
if(clockCounter > CLOCKS_PER_MS) {
|
if(clockCounter > CLOCKS_PER_MS) {
|
||||||
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();
|
MilliEdge();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,96 +121,75 @@ void SecondEdge() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MilliEdge() {
|
void MilliEdge() {
|
||||||
digitalWrite(DEBUG1_OUTPUT_PIN, 1);
|
|
||||||
wwvbInState = digitalRead(WWV_SIGNAL_PIN);
|
|
||||||
|
|
||||||
milliCounter++;
|
milliCounter++;
|
||||||
millisSinceBoot++;
|
millisSinceBoot++;
|
||||||
|
|
||||||
|
wwvbInState = digitalRead(WWV_SIGNAL_PIN);
|
||||||
|
|
||||||
|
if(waitingForSecond && !wwvbInState) {
|
||||||
|
// TICK! falling edge, beginning of a new frame and second
|
||||||
|
// FIXME reenable pps
|
||||||
|
//digitalWrite(PPS_OUTPUT_PIN, 1);
|
||||||
|
waitingForSecond = 0;
|
||||||
|
timeToTick = 1;
|
||||||
|
lastBitHighMS = highFor;
|
||||||
|
bitReadyForRead = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(milliCounter > 1000) {
|
if(milliCounter > 1000) {
|
||||||
milliCounter -= 1000;
|
milliCounter -= 1000;
|
||||||
SecondEdge();
|
SecondEdge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(wwvbInState != lastWWVBInState) {
|
||||||
|
// any edge indicates we have some signal
|
||||||
|
lossOfSignal = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(wwvbInState && (wwvbInState != lastWWVBInState)) {
|
if(wwvbInState && (wwvbInState != lastWWVBInState)) {
|
||||||
// we are on the rising edge, last low was 1ms ago
|
// we are on the rising edge, last low was 1ms ago
|
||||||
oldLastLowMillis = lastLowMillis;
|
highFor = 0;
|
||||||
lastLowMillis = millisSinceBoot - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!wwvbInState && (wwvbInState != lastWWVBInState)) {
|
if(!wwvbInState && (wwvbInState != lastWWVBInState)) {
|
||||||
// we are on the falling edge, last high was 1ms ago
|
// we are on the falling edge, last high was 1ms ago
|
||||||
oldLastHighMillis = lastHighMillis;
|
lowFor = 0;
|
||||||
lastHighMillis = millisSinceBoot - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(wwvbInState == lastWWVBInState) {
|
||||||
if(wwvbInState != lastWWVBInState) {
|
if(wwvbInState) {
|
||||||
// we are on an edge
|
highFor++;
|
||||||
stateStableMillis = 0;
|
|
||||||
} else {
|
} else {
|
||||||
// nothing happening
|
lowFor++;
|
||||||
stateStableMillis++;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(wwvbInState && (stateStableMillis > 180) && (stateStableMillis < 2000)) {
|
if(wwvbInState && (highFor > 80) && !lossOfSignal) {
|
||||||
// if we are high but for less than 2s
|
// if we are high for at least 80ms but no LOS
|
||||||
// main screen turn on
|
// main screen turn on
|
||||||
lossOfSignal = 0;
|
// this enables the falling edge low latency detector
|
||||||
frameSearch = 1;
|
// that happens on a tick
|
||||||
|
waitingForSecond = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wwvbInState && (highFor > 2000) && !lossOfSignal) {
|
||||||
|
// we have received nothing for 2 seconds, loss of signal:
|
||||||
|
lossOfSignal = 1;
|
||||||
|
waitingForSecond = 1;
|
||||||
|
frameCounter = 0;
|
||||||
|
minuteSync = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastWWVBInState = wwvbInState; // copy/save for next loop
|
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];
|
char pb[255];
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
digitalWrite(LED_BUILTIN, !wwvbInState);
|
digitalWrite(LED_BUILTIN, !wwvbInState);
|
||||||
|
|
||||||
if(timeToTick) {
|
if(timeToTick) {
|
||||||
@ -234,9 +199,9 @@ void loop() {
|
|||||||
|
|
||||||
yield();
|
yield();
|
||||||
|
|
||||||
if(frameReadyForRead) {
|
if(bitReadyForRead) {
|
||||||
frameReadyForRead = 0;
|
bitReadyForRead = 0;
|
||||||
processFrame();
|
readBit();
|
||||||
}
|
}
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
@ -260,43 +225,34 @@ void SetPPSLow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SendPPS() {
|
void SendPPS() {
|
||||||
unsigned int tickInterval = millisSinceBoot - ppsActivationTime;
|
|
||||||
ppsActivationTime = millisSinceBoot;
|
ppsActivationTime = millisSinceBoot;
|
||||||
SetPPSHigh();
|
SetPPSHigh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPSLowIfRequired() {
|
void PPSLowIfRequired() {
|
||||||
if ((millisSinceBoot - ppsActivationTime) > 500) {
|
if ((millisSinceBoot - ppsActivationTime) > PPS_PULSEWIDTH_MS) {
|
||||||
SetPPSLow();
|
SetPPSLow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TickSecond() {
|
void TickSecond() {
|
||||||
char buf[255];
|
char buf[255];
|
||||||
sprintf(buf, "*** TICK(%d): WWVB going low after %d ms high (EDGE)\n", frameCounter, millisSinceBoot - lastLowMillis);
|
sprintf(buf, "*** TICK(%d): WWVB going low after %d ms high (EDGE)\n",
|
||||||
|
frameCounter, lastBitHighMS);
|
||||||
|
Serial.print(buf);
|
||||||
SendPPS();
|
SendPPS();
|
||||||
Serial.print(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void processFrame() {
|
void readBit() {
|
||||||
char buf[255];
|
char buf[255];
|
||||||
sprintf(buf, "end of frame summary: frameHigh: %d, frameLow: %d\n", frameHighReadOut, frameLowReadOut);
|
unsigned int ms = lastBitHighMS;
|
||||||
|
sprintf(buf, "*** carrier was high for %sms befor \n", ms);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
float rawVal =
|
|
||||||
(float)frameHighReadOut
|
|
||||||
/
|
|
||||||
( (float)frameHighReadOut + (float)frameLowReadOut );
|
|
||||||
|
|
||||||
rawVal *= 1000;
|
|
||||||
unsigned int intRawVal = (int)rawVal;
|
|
||||||
if (intRawVal > 100000) {
|
|
||||||
intRawVal = 100000;
|
|
||||||
}
|
|
||||||
displayUpdateRequired++;
|
displayUpdateRequired++;
|
||||||
registerBit(convertDutyCycleToBit(intRawVal));
|
registerBit(convertBit(ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
int convertDutyCycleToBit(unsigned int rawVal) {
|
int convertBit(unsigned int ms) {
|
||||||
char buf[255];
|
char buf[255];
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -312,6 +268,8 @@ int convertDutyCycleToBit(unsigned int rawVal) {
|
|||||||
output = ZEROBIT;
|
output = ZEROBIT;
|
||||||
sprintf(bitbuf, "ZERO");
|
sprintf(bitbuf, "ZERO");
|
||||||
|
|
||||||
|
return output;
|
||||||
|
/*
|
||||||
if (rawVal < 800) {
|
if (rawVal < 800) {
|
||||||
output = ONEBIT;
|
output = ONEBIT;
|
||||||
sprintf(bitbuf, "ONE");
|
sprintf(bitbuf, "ONE");
|
||||||
@ -325,6 +283,7 @@ int convertDutyCycleToBit(unsigned int rawVal) {
|
|||||||
sprintf(buf, "frame rawVal=%d, bit=%s\n", rawVal, bitbuf);
|
sprintf(buf, "frame rawVal=%d, bit=%s\n", rawVal, bitbuf);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
return output;
|
return output;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerBit(int doot) {
|
void registerBit(int doot) {
|
||||||
@ -361,7 +320,6 @@ void lossOfSync(int errorFrame) {
|
|||||||
displayUpdateRequired++;
|
displayUpdateRequired++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sanityCheckFrame(int doot) {
|
void sanityCheckFrame(int doot) {
|
||||||
if (
|
if (
|
||||||
(
|
(
|
||||||
@ -457,15 +415,7 @@ void serialDebug() {
|
|||||||
char buf[255];
|
char buf[255];
|
||||||
sprintf(buf,"lossOfSignal=%d\n",lossOfSignal);
|
sprintf(buf,"lossOfSignal=%d\n",lossOfSignal);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
sprintf(buf,"frameReadyToStart=%d\n",frameReadyToStart);
|
sprintf(buf,"waitingForSecond=%d\n",waitingForSecond);
|
||||||
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);
|
Serial.print(buf);
|
||||||
sprintf(buf,"millisSinceBoot=%d\n",millisSinceBoot);
|
sprintf(buf,"millisSinceBoot=%d\n",millisSinceBoot);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
@ -475,8 +425,8 @@ void serialDebug() {
|
|||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
sprintf(buf,"timeToTick=%d\n",timeToTick);
|
sprintf(buf,"timeToTick=%d\n",timeToTick);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
sprintf(buf,"frameHigh=%d\n",frameHigh);
|
sprintf(buf,"highFor=%d\n",highFor);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
sprintf(buf,"frameLow=%d\n",frameLow);
|
sprintf(buf,"lowFor=%d\n",lowFor);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user