/** * Radiation counting */ #include "radiation.h" #include "time_base.h" #include "global_state.h" #include "iopins.h" #include #include #include #include #include #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); }