-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathGeigerduinoESP32.ino
More file actions
164 lines (149 loc) · 4.81 KB
/
GeigerduinoESP32.ino
File metadata and controls
164 lines (149 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
* Geigerduino Serial Geiger–Müller Counter for ESP32
*
* @author stig@sdm.nz
* @version 0.2
* @license GNU GPLv3
*
* Compatible with RadiationD-v1.1-CAJOE, 52DZ-DIY.com marked boards
* Note that these boards are 5v TTL (NOT 3.3v) so you need 5v Arduino (such as micro)
*
* Conversion factor is for J305 marked tube only. Update to match your tube.
* See https://www.cooking-hacks.com/documentation/tutorials/geiger-counter-radiation-sensor-board-arduino-raspberry-pi-tutorial#cpm_to_servants
*/
#include <SPI.h>
#include <limits.h>
//User variables
const int interrupt_pin = 0; //GM tube interrupt pin
const float conversion_factor = 0.0057; //GM tube SBM-20, see https://www.cooking-hacks.com/documentation/tutorials/geiger-counter-radiation-sensor-board-arduino-raspberry-pi-tutorial#cpm_to_servants
//Application
hw_timer_t * timer = NULL;
#define TX_FREQUENCY 2000 // 2 seconds
#define LOGGER_SIZE 60 // 60 data points
const int NULLDATA = ULONG_MAX;
volatile unsigned long counts = 0;
volatile unsigned long cpslogger[LOGGER_SIZE];
volatile unsigned long last_cpm = 0;
volatile int log_index = 0;
int last_log_index = 0;
int last_obs = 60;
unsigned long previous_millis = 0;
/**
* recordData
*
* Logs clicks each second using hardware timer
* for accuracy
*/
void IRAM_ATTR recordData() {
if (counts == ULONG_MAX)
counts = ULONG_MAX - 1;
cpslogger[log_index++] = counts;
if (log_index >= LOGGER_SIZE)
log_index = 0;
counts = 0;
}
/**
* setup()
*
* Start Geiger using interrupt pin
* Start Timer1 (hardware timer)
*/
void setup() {
//Start serial
Serial.begin(9600);
//Start Geiger
pinMode(interrupt_pin, INPUT);
digitalWrite(interrupt_pin, HIGH);
interrupts();
attachInterrupt(digitalPinToInterrupt(interrupt_pin), geigerClick, FALLING);
//Use ULONG_MAX to represent 'NULL data' on startup
for (int i = 0; i < LOGGER_SIZE; i++)
{
cpslogger[i] = NULLDATA;
}
//Begin counter reporting
timer = timerBegin(0, 80, true); //80 = 80Mhz
timerAttachInterrupt(timer, &recordData, true);
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer);
}
/**
* getData (int size - CPS observations requested, int period - Duration of observation to use for data)
*
* Returns 'count per period' based on specified quantity of most recent Count Per Second observations
* for a specified period.
*
* For example this can return 'CPS' using 5 most recent observations (size=5, period=1)
* or 'CPM' using 60 most recent observations (size=60, period=60)
*
* Maximum size is array length
*/
int getData(int size, int period, int current_index) {
int observations = 0;
//Max size is logger array length
if (size > LOGGER_SIZE)
size = LOGGER_SIZE;
unsigned long data = 0;
for (int i = 0; i < size; i++) {
//Find pointer between 0 to array length to start from and move backwards
int pointer = (current_index - i < 0) ? (current_index - i) + LOGGER_SIZE : current_index - i;
if (cpslogger[pointer] != NULLDATA) {
observations++;
data = data + cpslogger[pointer];
}
}
// Extrapolate found data to period required
data = (data * (period/observations));
return data;
}
/**
* Geiger-Mueller Tube Click
*
* Only increments count to avoid locking
*/
void geigerClick() {
counts++;
}
/**
* transmitData
*
* Sends CPS, CPM and radiation dose over Serial
*/
void transmitData() {
//Obtain log_index at start (volatile)
int current_index = log_index;
unsigned long cps = getData(TX_FREQUENCY/1000.0f, 1, current_index); //X observations / s
//Find optimal observations for current CPM
int obs;
if (last_cpm < 30) {
obs = 60; // Max 60 observations for update latency
} else if (last_cpm > 320) {
obs = 3; // Min 3 observations for accuracy
} else {
obs = (60.0f/last_cpm) * 20; //Ensure 60 observations per 20 CPM
}
//Limit observation increase so we don't extend observations into earlier high counts when ramping down
int max_obs = last_obs + (log_index - last_log_index < 0 ? LOGGER_SIZE + log_index - last_log_index : log_index - last_log_index);
if (obs > max_obs)
obs = max_obs;
unsigned long cpm = getData(obs, 60, current_index);
last_obs = obs;
last_log_index = current_index;
last_cpm = cpm;
char microseverts[6];
dtostrf(cpm * conversion_factor, 4, 2, microseverts);
char buffer[50];
sprintf(buffer, "CPS,%ld,CPM,%ld,OBS,%1d,uSv/hr,%s\r\n", cps, cpm, obs, microseverts);
Serial.print(buffer);
}
/**
* Main program
*/
void loop() {
unsigned long current_millis = millis();
if (current_millis - previous_millis >= TX_FREQUENCY)
{
previous_millis = current_millis;
transmitData();
}
}