mirror of
https://github.com/grillbaer/esp32-geiger-counter.git
synced 2025-12-21 13:23:15 +01:00
cleanup and formating after PlatformIO migration
This commit is contained in:
@@ -8,7 +8,8 @@
|
|||||||
const float STS6_CPM_PER_USPH = 875;
|
const float STS6_CPM_PER_USPH = 875;
|
||||||
|
|
||||||
// Holds pulse counter history and performs calculations
|
// Holds pulse counter history and performs calculations
|
||||||
class GeigerData {
|
class GeigerData
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
const uint16_t sampleCount;
|
const uint16_t sampleCount;
|
||||||
const uint16_t sampleSeconds;
|
const uint16_t sampleSeconds;
|
||||||
@@ -21,9 +22,8 @@ private:
|
|||||||
uint16_t prev(uint16_t index);
|
uint16_t prev(uint16_t index);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GeigerData(uint16_t sampleCount, uint16_t sampleSeconds,
|
GeigerData(uint16_t sampleCount, uint16_t sampleSeconds,
|
||||||
float cpm_per_uSph);
|
float cpm_per_uSph);
|
||||||
virtual ~GeigerData();
|
virtual ~GeigerData();
|
||||||
|
|
||||||
virtual void addPulses(uint16_t pulses);
|
virtual void addPulses(uint16_t pulses);
|
||||||
|
|||||||
@@ -1,45 +1,53 @@
|
|||||||
#include "GeigerData.h"
|
#include "GeigerData.h"
|
||||||
|
|
||||||
GeigerData::GeigerData(uint16_t sampleCount, uint16_t sampleSeconds,
|
GeigerData::GeigerData(uint16_t sampleCount, uint16_t sampleSeconds,
|
||||||
float cpm_per_uSph) :
|
float cpm_per_uSph) : sampleCount(sampleCount), sampleSeconds(sampleSeconds), cpm_per_uSph(cpm_per_uSph), pulsesPerSample(new uint16_t[sampleCount])
|
||||||
sampleCount(sampleCount), sampleSeconds(sampleSeconds), cpm_per_uSph(
|
{
|
||||||
cpm_per_uSph), pulsesPerSample(new uint16_t[sampleCount]) {
|
|
||||||
currentSample = 0;
|
currentSample = 0;
|
||||||
for (int i = 0; i < sampleCount; i++) {
|
for (int i = 0; i < sampleCount; i++)
|
||||||
|
{
|
||||||
pulsesPerSample[i] = 0;
|
pulsesPerSample[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GeigerData::~GeigerData() {
|
GeigerData::~GeigerData()
|
||||||
|
{
|
||||||
delete[] pulsesPerSample;
|
delete[] pulsesPerSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GeigerData::next(uint16_t index) {
|
uint16_t GeigerData::next(uint16_t index)
|
||||||
|
{
|
||||||
return index + 1 < sampleCount ? index + 1 : 0;
|
return index + 1 < sampleCount ? index + 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GeigerData::prev(uint16_t index) {
|
uint16_t GeigerData::prev(uint16_t index)
|
||||||
|
{
|
||||||
return index > 0 ? index - 1 : sampleCount - 1;
|
return index > 0 ? index - 1 : sampleCount - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeigerData::addPulses(uint16_t pulses) {
|
void GeigerData::addPulses(uint16_t pulses)
|
||||||
|
{
|
||||||
if (pulsesPerSample[currentSample] <= UINT16_MAX - pulses)
|
if (pulsesPerSample[currentSample] <= UINT16_MAX - pulses)
|
||||||
pulsesPerSample[currentSample] += pulses;
|
pulsesPerSample[currentSample] += pulses;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeigerData::nextSample() {
|
void GeigerData::nextSample()
|
||||||
|
{
|
||||||
currentSample = next(currentSample);
|
currentSample = next(currentSample);
|
||||||
pulsesPerSample[currentSample] = 0;
|
pulsesPerSample[currentSample] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GeigerData::getCurrentSample() {
|
uint16_t GeigerData::getCurrentSample()
|
||||||
|
{
|
||||||
return currentSample;
|
return currentSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GeigerData::getPreviousPulses(uint16_t offset, uint16_t samples) {
|
uint32_t GeigerData::getPreviousPulses(uint16_t offset, uint16_t samples)
|
||||||
|
{
|
||||||
uint32_t pulses = 0;
|
uint32_t pulses = 0;
|
||||||
uint16_t index = (currentSample + sampleCount - offset) % sampleCount;
|
uint16_t index = (currentSample + sampleCount - offset) % sampleCount;
|
||||||
for (uint16_t i = 0; i < samples; i++) {
|
for (uint16_t i = 0; i < samples; i++)
|
||||||
|
{
|
||||||
pulses += pulsesPerSample[index];
|
pulses += pulsesPerSample[index];
|
||||||
index = prev(index);
|
index = prev(index);
|
||||||
}
|
}
|
||||||
@@ -47,7 +55,8 @@ uint32_t GeigerData::getPreviousPulses(uint16_t offset, uint16_t samples) {
|
|||||||
return pulses;
|
return pulses;
|
||||||
}
|
}
|
||||||
|
|
||||||
float GeigerData::toMicroSievertPerHour(uint32_t pulses, uint16_t samples) {
|
float GeigerData::toMicroSievertPerHour(uint32_t pulses, uint16_t samples)
|
||||||
|
{
|
||||||
float cpm = pulses / (sampleSeconds / 60. * samples);
|
float cpm = pulses / (sampleSeconds / 60. * samples);
|
||||||
return cpm / cpm_per_uSph;
|
return cpm / cpm_per_uSph;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,15 @@
|
|||||||
// on I2C GPIOs SCL 22 and SDA 21
|
// on I2C GPIOs SCL 22 and SDA 21
|
||||||
U8G2_SH1106_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 22, 21);
|
U8G2_SH1106_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 22, 21);
|
||||||
|
|
||||||
void initDisplay() {
|
void initDisplay()
|
||||||
|
{
|
||||||
// high I2c clock still results in about 100ms buffer transmission to OLED:
|
// high I2c clock still results in about 100ms buffer transmission to OLED:
|
||||||
u8g2.setBusClock(1000000);
|
u8g2.setBusClock(1000000);
|
||||||
u8g2.begin();
|
u8g2.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderDigits(char uSphStr[16], char cpmStr[16]) {
|
void renderDigits(char uSphStr[16], char cpmStr[16])
|
||||||
|
{
|
||||||
uint16_t y = 14;
|
uint16_t y = 14;
|
||||||
uint16_t xCpm = 56;
|
uint16_t xCpm = 56;
|
||||||
uint16_t xUSph = 127;
|
uint16_t xUSph = 127;
|
||||||
@@ -37,19 +39,20 @@ void renderDigits(char uSphStr[16], char cpmStr[16]) {
|
|||||||
u8g2.print("cnt/min");
|
u8g2.print("cnt/min");
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderHistoryBarGraph(GeigerData &geigerData) {
|
void renderHistoryBarGraph(GeigerData &geigerData)
|
||||||
|
{
|
||||||
const uint16_t bars = 120;
|
const uint16_t bars = 120;
|
||||||
const uint16_t maxBarHeight = 40;
|
const uint16_t maxBarHeight = 40;
|
||||||
const uint16_t samplesPerBar = geigerData.sampleCount / bars;
|
const uint16_t samplesPerBar = geigerData.sampleCount / bars;
|
||||||
const uint16_t barsPerMinute = 60
|
const uint16_t barsPerMinute = 60 / (samplesPerBar * geigerData.sampleSeconds);
|
||||||
/ (samplesPerBar * geigerData.sampleSeconds);
|
|
||||||
|
|
||||||
// determine max value for y scale:
|
// determine max value for y scale:
|
||||||
uint16_t offset = geigerData.getCurrentSample() % samplesPerBar + 1;
|
uint16_t offset = geigerData.getCurrentSample() % samplesPerBar + 1;
|
||||||
uint32_t maxPulses = 0;
|
uint32_t maxPulses = 0;
|
||||||
for (int16_t i = 0; i < bars - 1; i++) {
|
for (int16_t i = 0; i < bars - 1; i++)
|
||||||
|
{
|
||||||
const uint32_t prevPulses = geigerData.getPreviousPulses(offset,
|
const uint32_t prevPulses = geigerData.getPreviousPulses(offset,
|
||||||
samplesPerBar);
|
samplesPerBar);
|
||||||
if (prevPulses > maxPulses)
|
if (prevPulses > maxPulses)
|
||||||
maxPulses = prevPulses;
|
maxPulses = prevPulses;
|
||||||
|
|
||||||
@@ -57,13 +60,13 @@ void renderHistoryBarGraph(GeigerData &geigerData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const float maxUSph = geigerData.toMicroSievertPerHour(maxPulses,
|
const float maxUSph = geigerData.toMicroSievertPerHour(maxPulses,
|
||||||
samplesPerBar);
|
samplesPerBar);
|
||||||
const float uSphPerPixel = maxUSph > 40. ? 10. : maxUSph > 4. ? 1. :
|
const float uSphPerPixel = maxUSph > 40. ? 10. : maxUSph > 4. ? 1. : maxUSph > 0.4 ? 0.1 : 0.01;
|
||||||
maxUSph > 0.4 ? 0.1 : 0.01;
|
|
||||||
// labels and grid
|
// labels and grid
|
||||||
u8g2.setFont(u8g2_font_4x6_tn);
|
u8g2.setFont(u8g2_font_4x6_tn);
|
||||||
char s[10];
|
char s[10];
|
||||||
for (uint16_t i = 10; i <= maxBarHeight; i += 10) {
|
for (uint16_t i = 10; i <= maxBarHeight; i += 10)
|
||||||
|
{
|
||||||
u8g2.setCursor(0, 63 - i + 3);
|
u8g2.setCursor(0, 63 - i + 3);
|
||||||
if (uSphPerPixel >= 0.1)
|
if (uSphPerPixel >= 0.1)
|
||||||
sprintf(s, "%.0f", i * uSphPerPixel);
|
sprintf(s, "%.0f", i * uSphPerPixel);
|
||||||
@@ -71,20 +74,22 @@ void renderHistoryBarGraph(GeigerData &geigerData) {
|
|||||||
sprintf(s, ".%.0f", i * uSphPerPixel * 10);
|
sprintf(s, ".%.0f", i * uSphPerPixel * 10);
|
||||||
|
|
||||||
u8g2.print(s);
|
u8g2.print(s);
|
||||||
for (int16_t x = 127 - barsPerMinute; x >= 8; x -= barsPerMinute) {
|
for (int16_t x = 127 - barsPerMinute; x >= 8; x -= barsPerMinute)
|
||||||
|
{
|
||||||
u8g2.drawPixel(x, 63 - i);
|
u8g2.drawPixel(x, 63 - i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// bars
|
// bars
|
||||||
offset = geigerData.getCurrentSample() % samplesPerBar + 1;
|
offset = geigerData.getCurrentSample() % samplesPerBar + 1;
|
||||||
for (int16_t i = 0; i < bars - 1; i++) {
|
for (int16_t i = 0; i < bars - 1; i++)
|
||||||
|
{
|
||||||
const uint32_t prevPulses = geigerData.getPreviousPulses(offset,
|
const uint32_t prevPulses = geigerData.getPreviousPulses(offset,
|
||||||
samplesPerBar);
|
samplesPerBar);
|
||||||
const float uSph = geigerData.toMicroSievertPerHour(prevPulses,
|
const float uSph = geigerData.toMicroSievertPerHour(prevPulses,
|
||||||
samplesPerBar);
|
samplesPerBar);
|
||||||
offset += samplesPerBar;
|
offset += samplesPerBar;
|
||||||
uint16_t barHeight = 1 + (int) ((uSph / uSphPerPixel));
|
uint16_t barHeight = 1 + (int)((uSph / uSphPerPixel));
|
||||||
if (barHeight > 40)
|
if (barHeight > 40)
|
||||||
barHeight = 40;
|
barHeight = 40;
|
||||||
|
|
||||||
@@ -92,7 +97,8 @@ void renderHistoryBarGraph(GeigerData &geigerData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDisplay(GeigerData &geigerData, char uSphStr[16], char cpmStr[16]) {
|
void updateDisplay(GeigerData &geigerData, char uSphStr[16], char cpmStr[16])
|
||||||
|
{
|
||||||
u8g2.clearBuffer();
|
u8g2.clearBuffer();
|
||||||
renderDigits(uSphStr, cpmStr);
|
renderDigits(uSphStr, cpmStr);
|
||||||
renderHistoryBarGraph(geigerData);
|
renderHistoryBarGraph(geigerData);
|
||||||
|
|||||||
@@ -6,21 +6,27 @@
|
|||||||
|
|
||||||
const char *thingsPeakUrl = "api.thingspeak.com";
|
const char *thingsPeakUrl = "api.thingspeak.com";
|
||||||
|
|
||||||
bool connect() {
|
bool connect()
|
||||||
|
{
|
||||||
uint16_t retries = 3;
|
uint16_t retries = 3;
|
||||||
while (WiFi.status() != WL_CONNECTED && (--retries) > 0) {
|
while (WiFi.status() != WL_CONNECTED && (--retries) > 0)
|
||||||
|
{
|
||||||
Serial.print("Trying to connect to ");
|
Serial.print("Trying to connect to ");
|
||||||
Serial.print(wifiSsid);
|
Serial.print(wifiSsid);
|
||||||
Serial.print(" ... ");
|
Serial.print(" ... ");
|
||||||
WiFi.begin(wifiSsid, wifiPassword);
|
WiFi.begin(wifiSsid, wifiPassword);
|
||||||
uint16_t waitRemaining = 8;
|
uint16_t waitRemaining = 8;
|
||||||
while (WiFi.status() != WL_CONNECTED && (--waitRemaining) > 0) {
|
while (WiFi.status() != WL_CONNECTED && (--waitRemaining) > 0)
|
||||||
|
{
|
||||||
delay(500);
|
delay(500);
|
||||||
}
|
}
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED)
|
||||||
|
{
|
||||||
Serial.println("successful");
|
Serial.println("successful");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Serial.print("failed status=");
|
Serial.print("failed status=");
|
||||||
Serial.println(WiFi.status());
|
Serial.println(WiFi.status());
|
||||||
}
|
}
|
||||||
@@ -29,39 +35,43 @@ bool connect() {
|
|||||||
return WiFi.status() == WL_CONNECTED;
|
return WiFi.status() == WL_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initIngest() {
|
void initIngest()
|
||||||
|
{
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinitIngest() {
|
void deinitIngest()
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
{
|
||||||
|
if (WiFi.status() == WL_CONNECTED)
|
||||||
|
{
|
||||||
Serial.println("Disconnecting WiFi");
|
Serial.println("Disconnecting WiFi");
|
||||||
WiFi.disconnect(true, true);
|
WiFi.disconnect(true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ingest(GeigerData &geigerData, uint16_t intervalSamples) {
|
void ingest(GeigerData &geigerData, uint16_t intervalSamples)
|
||||||
|
{
|
||||||
if (!connect())
|
if (!connect())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WiFiClient client;
|
WiFiClient client;
|
||||||
if (!client.connect(thingsPeakUrl, 80)) {
|
if (!client.connect(thingsPeakUrl, 80))
|
||||||
|
{
|
||||||
Serial.print("Connecting to ");
|
Serial.print("Connecting to ");
|
||||||
Serial.print(thingsPeakUrl);
|
Serial.print(thingsPeakUrl);
|
||||||
Serial.println(" failed");
|
Serial.println(" failed");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
const uint32_t pulses = geigerData.getPreviousPulses(1,
|
const uint32_t pulses = geigerData.getPreviousPulses(1,
|
||||||
intervalSamples);
|
intervalSamples);
|
||||||
const uint32_t cpm = uint32_t(
|
const uint32_t cpm = uint32_t(
|
||||||
pulses
|
pulses / ((float)intervalSamples * geigerData.sampleSeconds / 60.) + 0.5);
|
||||||
/ ((float) intervalSamples * geigerData.sampleSeconds
|
|
||||||
/ 60.) + 0.5);
|
|
||||||
const float uSph = geigerData.toMicroSievertPerHour(pulses,
|
const float uSph = geigerData.toMicroSievertPerHour(pulses,
|
||||||
intervalSamples);
|
intervalSamples);
|
||||||
|
|
||||||
const String content = "api_key=" + String(thingspeakApiKey)
|
const String content = "api_key=" + String(thingspeakApiKey) + "&field1=" + String(cpm) + "&field2=" + String(uSph, 3);
|
||||||
+ "&field1=" + String(cpm) + "&field2=" + String(uSph, 3);
|
|
||||||
|
|
||||||
Serial.print("Ingesting cpm=");
|
Serial.print("Ingesting cpm=");
|
||||||
Serial.print(cpm);
|
Serial.print(cpm);
|
||||||
@@ -85,15 +95,18 @@ void ingest(GeigerData &geigerData, uint16_t intervalSamples) {
|
|||||||
client.print(content);
|
client.print(content);
|
||||||
|
|
||||||
uint16_t timeout = 40;
|
uint16_t timeout = 40;
|
||||||
while (client.available() == 0 && (--timeout) > 0) {
|
while (client.available() == 0 && (--timeout) > 0)
|
||||||
|
{
|
||||||
delay(50);
|
delay(50);
|
||||||
}
|
}
|
||||||
if (client.available() == 0) {
|
if (client.available() == 0)
|
||||||
|
{
|
||||||
Serial.println("failed (no response)");
|
Serial.println("failed (no response)");
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println("response:");
|
Serial.println("response:");
|
||||||
while (client.available()) {
|
while (client.available())
|
||||||
|
{
|
||||||
char c = client.read();
|
char c = client.read();
|
||||||
Serial.write(c);
|
Serial.write(c);
|
||||||
}
|
}
|
||||||
|
|||||||
234
src/main.cpp
234
src/main.cpp
@@ -6,24 +6,6 @@
|
|||||||
#include "ingest.h"
|
#include "ingest.h"
|
||||||
#include "GeigerData.h"
|
#include "GeigerData.h"
|
||||||
|
|
||||||
void setup() ;
|
|
||||||
void pulse() ;
|
|
||||||
uint32_t calcRemainingWait() ;
|
|
||||||
boolean wifiSwitchOn() ;
|
|
||||||
uint16_t takeSampleNoSleep() ;
|
|
||||||
uint16_t takeSampleLowPower() ;
|
|
||||||
void loop() ;
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#include "driver/pcnt.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "driver/rtc_io.h"
|
|
||||||
|
|
||||||
#include "display.h"
|
|
||||||
#include "ingest.h"
|
|
||||||
#include "GeigerData.h"
|
|
||||||
|
|
||||||
// ~400µs high pulses from Geiger tube on GPIO 18
|
// ~400µs high pulses from Geiger tube on GPIO 18
|
||||||
#define PULSE_PIN 18
|
#define PULSE_PIN 18
|
||||||
#define PULSE_GPIO GPIO_NUM_18
|
#define PULSE_GPIO GPIO_NUM_18
|
||||||
@@ -51,7 +33,14 @@ uint32_t sampleStart = 0;
|
|||||||
const int16_t ingestInterval = 60;
|
const int16_t ingestInterval = 60;
|
||||||
int16_t ingestCountdown;
|
int16_t ingestCountdown;
|
||||||
|
|
||||||
void setup() {
|
void pulse();
|
||||||
|
uint32_t calcRemainingWait();
|
||||||
|
boolean wifiSwitchOn();
|
||||||
|
uint16_t takeSampleNoSleep();
|
||||||
|
uint16_t takeSampleLowPower();
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
Serial.begin(921600);
|
Serial.begin(921600);
|
||||||
Serial.println("Starting!");
|
Serial.println("Starting!");
|
||||||
|
|
||||||
@@ -67,7 +56,8 @@ void setup() {
|
|||||||
// WiFi switch input
|
// WiFi switch input
|
||||||
pinMode(WIFI_SWITCH_PIN, INPUT_PULLUP);
|
pinMode(WIFI_SWITCH_PIN, INPUT_PULLUP);
|
||||||
|
|
||||||
if (wifiSwitchOn()) {
|
if (wifiSwitchOn())
|
||||||
|
{
|
||||||
initIngest();
|
initIngest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,97 +66,8 @@ void setup() {
|
|||||||
ingestCountdown = ingestInterval;
|
ingestCountdown = ingestInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// interrupt handler
|
void loop()
|
||||||
void pulse() {
|
{
|
||||||
++intPulseCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t calcRemainingWait() {
|
|
||||||
const uint32_t remaining = sampleMicros - (micros() - sampleStart);
|
|
||||||
return remaining > sampleMicros ? 0 : remaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean wifiSwitchOn() {
|
|
||||||
return digitalRead(WIFI_SWITCH_PIN) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t takeSampleNoSleep() {
|
|
||||||
attachInterrupt(PULSE_PIN, pulse, RISING);
|
|
||||||
|
|
||||||
int32_t remainingWait = calcRemainingWait();
|
|
||||||
delayMicroseconds(remainingWait);
|
|
||||||
sampleStart = micros();
|
|
||||||
noInterrupts();
|
|
||||||
const int16_t pulses = intPulseCount;
|
|
||||||
intPulseCount = 0;
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
return pulses;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t takeSampleLowPower() {
|
|
||||||
// To save battery power, use light sleep as much as possible.
|
|
||||||
// During light sleep, no counters or interrupts are working.
|
|
||||||
// Therefore simply wake up on each pulse signal change. This
|
|
||||||
// is fast enough for the low frequencies from a Geiger tube
|
|
||||||
// (below 2kHz):
|
|
||||||
// Wake up at end of sample period. Also
|
|
||||||
// wake up on pulse getting high and getting low.
|
|
||||||
// Waking up directly on rising/falling edges is not possible,
|
|
||||||
// so wait until level change.
|
|
||||||
// Switch to interrupt counting while awake for calculations
|
|
||||||
// and display update.
|
|
||||||
|
|
||||||
// stop interrupt (switch to active wakeup counting loop):
|
|
||||||
detachInterrupt(PULSE_PIN);
|
|
||||||
|
|
||||||
int32_t remainingWait = calcRemainingWait();
|
|
||||||
esp_sleep_wakeup_cause_t cause = ESP_SLEEP_WAKEUP_UNDEFINED;
|
|
||||||
while (cause != ESP_SLEEP_WAKEUP_TIMER && remainingWait > 0) {
|
|
||||||
|
|
||||||
if (digitalRead(PULSE_PIN)) {
|
|
||||||
// wait for low pulse start or sample time end
|
|
||||||
esp_sleep_enable_timer_wakeup(remainingWait);
|
|
||||||
gpio_wakeup_enable(PULSE_GPIO, GPIO_INTR_LOW_LEVEL);
|
|
||||||
esp_sleep_enable_gpio_wakeup();
|
|
||||||
esp_light_sleep_start();
|
|
||||||
cause = esp_sleep_get_wakeup_cause();
|
|
||||||
}
|
|
||||||
|
|
||||||
remainingWait = calcRemainingWait();
|
|
||||||
if (cause != ESP_SLEEP_WAKEUP_TIMER && remainingWait > 0) {
|
|
||||||
// wait for high pulse start or sample time end
|
|
||||||
esp_sleep_enable_timer_wakeup(remainingWait);
|
|
||||||
gpio_wakeup_enable(PULSE_GPIO, GPIO_INTR_HIGH_LEVEL);
|
|
||||||
esp_sleep_enable_gpio_wakeup();
|
|
||||||
esp_light_sleep_start();
|
|
||||||
cause = esp_sleep_get_wakeup_cause();
|
|
||||||
if (cause == ESP_SLEEP_WAKEUP_GPIO) {
|
|
||||||
++pulseCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remainingWait = calcRemainingWait();
|
|
||||||
}
|
|
||||||
|
|
||||||
// take sample and add to statistics
|
|
||||||
|
|
||||||
sampleStart = micros();
|
|
||||||
const int16_t pulses = pulseCount + intPulseCount;
|
|
||||||
// Serial.print("pc=");
|
|
||||||
// Serial.print(pulseCount);
|
|
||||||
// Serial.print(" ipc=");
|
|
||||||
// Serial.println(intPulseCount);
|
|
||||||
attachInterrupt(PULSE_PIN, pulse, RISING);
|
|
||||||
interrupts();
|
|
||||||
// reset counters AFTER enabling interrupt to avoid double-counting on high signal
|
|
||||||
pulseCount = 0;
|
|
||||||
intPulseCount = 0;
|
|
||||||
|
|
||||||
return pulses;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
|
|
||||||
// blinky
|
// blinky
|
||||||
|
|
||||||
@@ -174,18 +75,22 @@ void loop() {
|
|||||||
blinky = !blinky;
|
blinky = !blinky;
|
||||||
|
|
||||||
const uint16_t pulses =
|
const uint16_t pulses =
|
||||||
wifiSwitchOn() ? takeSampleNoSleep() : takeSampleLowPower();
|
wifiSwitchOn() ? takeSampleNoSleep() : takeSampleLowPower();
|
||||||
|
|
||||||
geigerData.addPulses(pulses);
|
geigerData.addPulses(pulses);
|
||||||
geigerData.nextSample();
|
geigerData.nextSample();
|
||||||
|
|
||||||
if (wifiSwitchOn()) {
|
if (wifiSwitchOn())
|
||||||
|
{
|
||||||
ingestCountdown--;
|
ingestCountdown--;
|
||||||
if (ingestCountdown <= 0) {
|
if (ingestCountdown <= 0)
|
||||||
|
{
|
||||||
ingestCountdown = ingestInterval;
|
ingestCountdown = ingestInterval;
|
||||||
ingest(geigerData, ingestInterval);
|
ingest(geigerData, ingestInterval);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
deinitIngest();
|
deinitIngest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,3 +122,102 @@ void loop() {
|
|||||||
|
|
||||||
updateDisplay(geigerData, uSphStr, cpmStr);
|
updateDisplay(geigerData, uSphStr, cpmStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interrupt handler
|
||||||
|
void pulse()
|
||||||
|
{
|
||||||
|
++intPulseCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t calcRemainingWait()
|
||||||
|
{
|
||||||
|
const uint32_t remaining = sampleMicros - (micros() - sampleStart);
|
||||||
|
return remaining > sampleMicros ? 0 : remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean wifiSwitchOn()
|
||||||
|
{
|
||||||
|
return digitalRead(WIFI_SWITCH_PIN) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t takeSampleNoSleep()
|
||||||
|
{
|
||||||
|
attachInterrupt(PULSE_PIN, pulse, RISING);
|
||||||
|
|
||||||
|
int32_t remainingWait = calcRemainingWait();
|
||||||
|
delayMicroseconds(remainingWait);
|
||||||
|
sampleStart = micros();
|
||||||
|
noInterrupts();
|
||||||
|
const int16_t pulses = intPulseCount;
|
||||||
|
intPulseCount = 0;
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
return pulses;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t takeSampleLowPower()
|
||||||
|
{
|
||||||
|
// To save battery power, use light sleep as much as possible.
|
||||||
|
// During light sleep, no counters or interrupts are working.
|
||||||
|
// Therefore simply wake up on each pulse signal change. This
|
||||||
|
// is fast enough for the low frequencies from a Geiger tube
|
||||||
|
// (below 2kHz):
|
||||||
|
// Wake up at end of sample period. Also
|
||||||
|
// wake up on pulse getting high and getting low.
|
||||||
|
// Waking up directly on rising/falling edges is not possible,
|
||||||
|
// so wait until level change.
|
||||||
|
// Switch to interrupt counting while awake for calculations
|
||||||
|
// and display update.
|
||||||
|
|
||||||
|
// stop interrupt (switch to active wakeup counting loop):
|
||||||
|
detachInterrupt(PULSE_PIN);
|
||||||
|
|
||||||
|
int32_t remainingWait = calcRemainingWait();
|
||||||
|
esp_sleep_wakeup_cause_t cause = ESP_SLEEP_WAKEUP_UNDEFINED;
|
||||||
|
while (cause != ESP_SLEEP_WAKEUP_TIMER && remainingWait > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (digitalRead(PULSE_PIN))
|
||||||
|
{
|
||||||
|
// wait for low pulse start or sample time end
|
||||||
|
esp_sleep_enable_timer_wakeup(remainingWait);
|
||||||
|
gpio_wakeup_enable(PULSE_GPIO, GPIO_INTR_LOW_LEVEL);
|
||||||
|
esp_sleep_enable_gpio_wakeup();
|
||||||
|
esp_light_sleep_start();
|
||||||
|
cause = esp_sleep_get_wakeup_cause();
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingWait = calcRemainingWait();
|
||||||
|
if (cause != ESP_SLEEP_WAKEUP_TIMER && remainingWait > 0)
|
||||||
|
{
|
||||||
|
// wait for high pulse start or sample time end
|
||||||
|
esp_sleep_enable_timer_wakeup(remainingWait);
|
||||||
|
gpio_wakeup_enable(PULSE_GPIO, GPIO_INTR_HIGH_LEVEL);
|
||||||
|
esp_sleep_enable_gpio_wakeup();
|
||||||
|
esp_light_sleep_start();
|
||||||
|
cause = esp_sleep_get_wakeup_cause();
|
||||||
|
if (cause == ESP_SLEEP_WAKEUP_GPIO)
|
||||||
|
{
|
||||||
|
++pulseCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingWait = calcRemainingWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
// take sample and add to statistics
|
||||||
|
|
||||||
|
sampleStart = micros();
|
||||||
|
const int16_t pulses = pulseCount + intPulseCount;
|
||||||
|
// Serial.print("pc=");
|
||||||
|
// Serial.print(pulseCount);
|
||||||
|
// Serial.print(" ipc=");
|
||||||
|
// Serial.println(intPulseCount);
|
||||||
|
attachInterrupt(PULSE_PIN, pulse, RISING);
|
||||||
|
interrupts();
|
||||||
|
// reset counters AFTER enabling interrupt to avoid double-counting on high signal
|
||||||
|
pulseCount = 0;
|
||||||
|
intPulseCount = 0;
|
||||||
|
|
||||||
|
return pulses;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user