You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
4.7 KiB
197 lines
4.7 KiB
/**
|
|
* Radiation counting
|
|
*/
|
|
|
|
#include "radiation.h"
|
|
#include "time_base.h"
|
|
#include "global_state.h"
|
|
#include "iopins.h"
|
|
|
|
#include <avr/interrupt.h>
|
|
#include <util/atomic.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#define MEAS_BIN_COUNT 120
|
|
typedef uint16_t ticks_t;
|
|
typedef uint8_t binnum_t;
|
|
#define TICKS_MAX 0xFFFF
|
|
|
|
#define NEEDED_TICKS_FOR_VALUE_DISPLAY 5
|
|
|
|
#define TICKS_NEEDED_FOR_AUTORANGE 10
|
|
|
|
uint32_t get_tick_count_in_bins(binnum_t bincount);
|
|
|
|
/// measurements in the last X seconds
|
|
static volatile ticks_t measurements[MEAS_BIN_COUNT];
|
|
/// Currently active measurement bin, increments once per second
|
|
static volatile binnum_t meas_bin = 0;
|
|
static volatile binnum_t meas_oldest_bin = 0;
|
|
static volatile binnum_t num_live_bins = 1;
|
|
|
|
static volatile binnum_t num_observed_bins = 60;
|
|
|
|
// geiger tube pin change interrupt
|
|
ISR(INT0_vect)
|
|
{
|
|
if (measurements[meas_bin] < TICKS_MAX) {
|
|
measurements[meas_bin]++;
|
|
}
|
|
req_update_display = true;
|
|
disp_show_tick_mark = 1;
|
|
}
|
|
|
|
void second_callback_irq()
|
|
{
|
|
meas_bin++;
|
|
if (num_live_bins < MEAS_BIN_COUNT) {
|
|
num_live_bins++;
|
|
}
|
|
if (meas_bin >= MEAS_BIN_COUNT) {
|
|
meas_bin = 0;
|
|
}
|
|
|
|
if (meas_oldest_bin == meas_bin) {
|
|
meas_oldest_bin++;
|
|
if (meas_oldest_bin >= MEAS_BIN_COUNT) {
|
|
meas_oldest_bin = 0;
|
|
}
|
|
}
|
|
|
|
measurements[meas_bin] = 0;
|
|
req_update_display = true;
|
|
|
|
/* autoranging */
|
|
|
|
uint16_t count;
|
|
bool found_range = 0;
|
|
for (int i = 5; i <= 60; i += 5) {
|
|
count = get_tick_count_in_bins(i);
|
|
if (count > TICKS_NEEDED_FOR_AUTORANGE) {
|
|
num_observed_bins = i * 2;
|
|
if (num_observed_bins > num_live_bins) {
|
|
num_observed_bins = num_live_bins;
|
|
}
|
|
found_range = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found_range) {
|
|
num_observed_bins = num_live_bins;
|
|
}
|
|
}
|
|
|
|
void init_radiation()
|
|
{
|
|
// clear the measurement buffer
|
|
memset((void *) measurements, 0, sizeof(measurements));
|
|
|
|
as_input(D2);
|
|
|
|
// using INT0 - arduino pin D2
|
|
EICRA = _BV(ISC01) | _BV(ISC00); // rising edge
|
|
EIMSK = _BV(INT0);
|
|
}
|
|
|
|
uint8_t rad_get_progress()
|
|
{
|
|
uint16_t ticks = get_tick_count_in_bins(num_live_bins);
|
|
|
|
if (ticks >= NEEDED_TICKS_FOR_VALUE_DISPLAY) {
|
|
return 100;
|
|
}
|
|
|
|
return (((uint16_t) ticks * 100) / (uint16_t) NEEDED_TICKS_FOR_VALUE_DISPLAY);
|
|
}
|
|
|
|
uint32_t get_tick_count_in_bins(binnum_t bincount)
|
|
{
|
|
if (bincount == 0) {
|
|
return 0;
|
|
}
|
|
|
|
uint32_t all_ticks = 0;
|
|
|
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
|
// going backwards
|
|
binnum_t bin = meas_bin;
|
|
for (;;) {
|
|
all_ticks += (uint32_t) measurements[bin];
|
|
|
|
if (bin == meas_oldest_bin) {
|
|
break;
|
|
}
|
|
|
|
if (bincount > 0) {
|
|
bincount--;
|
|
if (bincount == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bin > 0) {
|
|
bin--;
|
|
} else {
|
|
bin = MEAS_BIN_COUNT - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return all_ticks;
|
|
}
|
|
|
|
void rad_get_reading(struct rad_results *out)
|
|
{
|
|
if (!out) { return; }
|
|
|
|
// bins take 1 second
|
|
const float count = (float) get_tick_count_in_bins(num_observed_bins);
|
|
const float cpm = (count / (float) num_observed_bins) * 60.0f;
|
|
|
|
out->cpm_x10 = (uint32_t) roundf(cpm * 10.0f);
|
|
|
|
// https://sites.google.com/site/diygeigercounter/technical/gm-tubes-supported
|
|
|
|
const float usvh = (cpm / 153.8f);
|
|
|
|
if (usvh < 2.0f) {
|
|
out->danger_level = RAD_LEVEL_0_SAFE;
|
|
} else if (usvh < 10.0f) {
|
|
out->danger_level = RAD_LEVEL_1_ELEVATED;
|
|
} else if (usvh < 20.0f) {
|
|
out->danger_level = RAD_LEVEL_2_DANGER;
|
|
} else if (usvh < 1000.0f) {
|
|
out->danger_level = RAD_LEVEL_3_HIGH_DANGER;
|
|
} else {
|
|
out->danger_level = RAD_LEVEL_4_SEVERE;
|
|
}
|
|
|
|
// // for testing only
|
|
// if (usvh < 1.0f) {
|
|
// out->danger_level = RAD_LEVEL_0_SAFE;
|
|
// } else if (usvh < 3.0f) {
|
|
// out->danger_level = RAD_LEVEL_1_ELEVATED;
|
|
// } else if (usvh < 6.0f) {
|
|
// out->danger_level = RAD_LEVEL_2_DANGER;
|
|
// } else if (usvh < 9.0f) {
|
|
// out->danger_level = RAD_LEVEL_3_HIGH_DANGER;
|
|
// } else {
|
|
// out->danger_level = RAD_LEVEL_4_SEVERE;
|
|
// }
|
|
|
|
if (usvh < 99.0f) {
|
|
out->usvh_decimals = 3;
|
|
out->usvh_num = (uint32_t) roundf(usvh * 1000.0f);
|
|
} else if (usvh < 999.0f) {
|
|
out->usvh_decimals = 2;
|
|
out->usvh_num = (uint32_t) roundf(usvh * 100.0f);
|
|
} else if (usvh < 9999.0f) {
|
|
out->usvh_decimals = 1;
|
|
out->usvh_num = (uint32_t) roundf(usvh * 10.0f);
|
|
} else {
|
|
out->usvh_decimals = 0;
|
|
out->usvh_num = (uint32_t) roundf(usvh);
|
|
}
|
|
}
|
|
|