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.
 
 
 
atmega-geiger/src/radiation.c

180 lines
4.1 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 uint8_t ticks_t;
typedef uint8_t binnum_t;
#define TICKS_MAX 255
#define NEEDED_TICKS_FOR_VALUE_DISPLAY 5
#define TICKS_NEEDED_FOR_AUTORANGE 15
uint16_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;
}
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() {
ticks_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);
}
uint16_t get_tick_count_in_bins(binnum_t bincount) {
if (bincount == 0) {
return 0;
}
uint16_t all_ticks = 0;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
// going backwards
binnum_t bin = meas_bin;
for (;;) {
ticks_t in_bin = measurements[bin];
if ((0xFFFF - all_ticks) < in_bin) {
all_ticks = 0xFFFF;
} else {
all_ticks += in_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;
}
uint16_t rad_get_cpm() {
// bins take 1 second
float count = get_tick_count_in_bins(num_observed_bins);
float cpm = (count / (float)num_observed_bins) * 60.0f;
return (uint16_t) roundf(cpm * 10.0f);
}
uint16_t rad_get_usvh(uint8_t *out_decimals) {
float count = get_tick_count_in_bins(num_observed_bins);
float cpm = (count / (float)num_observed_bins) * 60.0f;
// https://sites.google.com/site/diygeigercounter/technical/gm-tubes-supported
float usvh = (cpm / 153.8f);
if (usvh < 99.0f) {
*out_decimals = 3;
return (uint16_t) roundf(usvh * 1000.0f);
}
if (usvh < 999.0f) {
*out_decimals = 2;
return (uint16_t) roundf(usvh * 100.0f);
}
if (usvh < 9999.0f) {
*out_decimals = 1;
return (uint16_t) roundf(usvh * 10.0f);
}
*out_decimals = 0;
return (uint16_t) roundf(usvh);
}