usv/h and other improvements, use float

master
Ondřej Hruška 1 year ago
parent 020c14a31f
commit 27e4cd2f32
  1. 71
      src/graphic_empty_battery.c
  2. 65
      src/graphic_loading.c
  3. 4
      src/high_voltage.c
  4. 7
      src/main.c
  5. 140
      src/radiation.c
  6. 11
      src/radiation.h
  7. 5
      src/time_base.c
  8. 58
      src/user_interface.c
  9. 14
      src/user_interface.h

@ -0,0 +1,71 @@
/**
* Empty battery
*/
#include <stdint.h>
#include "ssd1306.h"
#include "user_interface.h"
void show_empty_battery()
{
ssd1306_clearScreen();
// *********
// **** *
// **** x *
// **** *
// *********
#define capwid 6
#define hei 24
#define caphei 12
#define wid 50
#define thic 2
#define inpad 2
#define charge 2
#define ofsx ((DISPLAY_W - capwid - wid)/2)
#define ofsy ((DISPLAY_H - hei)/2)
const uint8_t rects[6][4] = {
// cap
{
0, (hei - caphei) / 2,
capwid - 1, hei - (hei - caphei) / 2 - 1
},
// left line
{
capwid, 0,
capwid+thic - 1, hei - 1
},
// top line
{
capwid + thic, 0,
capwid + wid - thic - 1, thic - 1
},
// right line
{
capwid + wid - thic, 0,
capwid + wid - 1, hei - 1
},
// "remaining charge" line
{
capwid + wid - thic - inpad - charge, thic + inpad,
capwid + wid - thic - inpad - 1, hei - thic - inpad - 1
},
// bottom line
{
capwid + thic, hei - thic,
capwid + wid - thic - 1, hei - 1
}
};
for (int i = 0; i < 6; i++) {
ssd1306_fillRect(
ofsx + rects[i][0],
ofsy + rects[i][1],
ofsx + rects[i][2],
ofsy + rects[i][3]
);
}
}

@ -0,0 +1,65 @@
/**
* Loading
*/
#include <stdint.h>
#include <stdbool.h>
#include "ssd1306.h"
#include "user_interface.h"
void show_loading_screen(uint8_t progress_percent, bool clear)
{
if (clear) {
ssd1306_clearScreen();
}
// bar in a box
#define hei 20
#define wid DISPLAY_W
#define thic 2
#define inpad 3
#define ofsx ((DISPLAY_W - wid)/2)
#define ofsy ((DISPLAY_H - hei)/2)
const uint8_t rects[4][4] = {
// top
{
0, 0,
wid - 1, thic - 1
},
// left
{
0, thic,
thic - 1, hei - thic - 1
},
// right
{
wid - thic, thic,
wid - 1, hei - thic - 1
},
// bot
{
0, hei - thic,
wid - 1, hei - 1
},
};
for (int i = 0; i < 4; i++) {
ssd1306_fillRect(
ofsx + rects[i][0],
ofsy + rects[i][1],
ofsx + rects[i][2],
ofsy + rects[i][3]
);
}
//
ssd1306_fillRect(
ofsx + thic + inpad,
ofsy + thic + inpad,
ofsx + (uint8_t)(((uint16_t)wid * (uint16_t)progress_percent)/(uint16_t)100) - thic - inpad - 1,
ofsy + hei - thic - inpad - 1
);
}

@ -12,8 +12,8 @@
static volatile bool is_pwm_on = false;
// tube starting voltage is 350V
#define TURN_ON_VOLTAGE 355.0
#define TURN_OFF_VOLTAGE 380.0
#define TURN_ON_VOLTAGE 360.0
#define TURN_OFF_VOLTAGE 390.0
#define MINIMAL_VOLTAGE 350.0
// sensing via resistive divider

@ -19,6 +19,8 @@ void __attribute__((noreturn)) main()
{
init_user_interface();
show_loading_screen(0, true);
init_timebase();
init_radiation();
@ -54,10 +56,13 @@ void __attribute__((noreturn)) shutdown_due_to_weak_battery()
cli();
hv_disable();
show_empty_battery_icon();
show_empty_battery();
// try to preserve power; but the display will still drain the battery.
// we should probably shut it off too.
_delay_ms(2000);
turn_off_display();
for (;;) {
sleep_enable();
sleep_cpu();

@ -8,23 +8,35 @@
#include "iopins.h"
#include <avr/interrupt.h>
#include <stdbool.h>
#include <util/atomic.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#define MEAS_BIN_COUNT 120
typedef uint8_t meas_bin_t;
#define MEAS_MAX_COUNT 255
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 meas_bin_t measurements[MEAS_BIN_COUNT];
static volatile ticks_t measurements[MEAS_BIN_COUNT];
/// Currently active measurement bin, increments once per second
static volatile uint8_t meas_bin = 0;
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] < MEAS_MAX_COUNT) {
if (measurements[meas_bin] < TICKS_MAX) {
measurements[meas_bin]++;
}
req_update_display = true;
@ -33,11 +45,41 @@ ISR(INT0_vect)
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() {
@ -50,3 +92,89 @@ void init_radiation() {
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);
}

@ -5,6 +5,17 @@
#ifndef CPROJ_RADIATION_H
#define CPROJ_RADIATION_H
#include <stdbool.h>
#include <stdint.h>
void init_radiation();
/// get progress 0-100, 100 = normal radiation resumed
uint8_t rad_get_progress();
uint16_t rad_get_cpm();
/// Get current radiation dose rate u uSv/h, x10 (one decimal place)
uint16_t rad_get_usvh(uint8_t *out_decimals);
#endif //CPROJ_RADIATION_H

@ -3,8 +3,10 @@
*/
#include "time_base.h"
#include "global_state.h"
#include <stdint.h>
#include <stdbool.h>
#include <avr/interrupt.h>
/// timestamp counted in units of 100ms
@ -17,6 +19,9 @@ ISR(TIMER1_COMPA_vect)
{
timestamp_100ms++;
req_update_display = true;
subsec_counter++;
if (subsec_counter == 10) {
subsec_counter = 0;

@ -7,6 +7,9 @@
#include "ssd1306.h"
#include "sevenseg.h"
#include "global_state.h"
#include "radiation.h"
static bool ended_loading = false;
static struct SevenSeg sseg = {
.x0 = 0,
@ -18,31 +21,56 @@ static struct SevenSeg sseg = {
.spacing = 4,
};
void clear_screen()
{
ssd1306_clearScreen();
}
void init_user_interface()
{
TWI_Init();
ssd1306_128x32_i2c_init();
ssd1306_clearScreen();
// can't show anything useful at least until the first tick arrives, but more than 1 tick is needed
show_loading_icon();
}
void turn_off_display() {
ssd1306_displayOff();
}
static volatile uint16_t last_value = 0;
static volatile uint16_t last_value_d = 0;
void show_current_radiation()
{
// TODO
sseg_number(&sseg, timestamp_100ms, 5, 0);
}
// this is called from main, so we can sleep
void show_empty_battery_icon()
{
// TODO
sseg_number(&sseg, 9999, 5, 0);
}
if (!ended_loading) {
int progress = rad_get_progress();
if (progress == 100) {
show_loading_screen(100, false);
ended_loading = true;
void show_loading_icon()
{
// TODO
sseg_number(&sseg, 0, 5, 0);
// so user sees it
_delay_ms(250);
clear_screen();
// start showing values
} else {
if (progress < 10) progress = 10;
show_loading_screen(progress, false);
return;
}
}
// uint16_t cpm = rad_get_cpm();
// if (cpm != last_value) {
// last_value = cpm;
// sseg_number(&sseg, cpm, 5, 1);
// }
uint8_t decimals = 0;
uint16_t usvh = rad_get_usvh(&decimals);
if (usvh != last_value || decimals != last_value_d) {
last_value = usvh;
last_value_d = decimals;
sseg_number(&sseg, usvh, 5, decimals);
}
}

@ -5,12 +5,22 @@
#ifndef CPROJ_USER_INTERFACE_H
#define CPROJ_USER_INTERFACE_H
#define DISPLAY_W 128
#define DISPLAY_H 32
#include <stdint.h>
#include <stdbool.h>
void clear_screen();
void init_user_interface();
void show_current_radiation();
void show_empty_battery_icon();
void show_empty_battery();
void show_loading_screen(uint8_t progress_percent, bool clear);
void show_loading_icon();
void turn_off_display();
#endif //CPROJ_USER_INTERFACE_H

Loading…
Cancel
Save