initial
This commit is contained in:
175
wwvb/floats.csv
Normal file
175
wwvb/floats.csv
Normal file
@@ -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
|
||||
|
1086
wwvb/output.txt
Normal file
1086
wwvb/output.txt
Normal file
File diff suppressed because it is too large
Load Diff
482
wwvb/wwvb.ino
Normal file
482
wwvb/wwvb.ino
Normal file
@@ -0,0 +1,482 @@
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user