parent
8d1380bad6
commit
020c14a31f
@ -0,0 +1,15 @@ |
|||||||
|
/**
|
||||||
|
* Declarations of global variables |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef CPROJ_GLOBAL_VARIABLES_H |
||||||
|
#define CPROJ_GLOBAL_VARIABLES_H |
||||||
|
|
||||||
|
#include <stdbool.h> |
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
extern volatile bool req_update_display; |
||||||
|
extern volatile bool is_weak_battery; |
||||||
|
extern volatile uint16_t timestamp_100ms; |
||||||
|
|
||||||
|
#endif //CPROJ_GLOBAL_VARIABLES_H
|
@ -0,0 +1,140 @@ |
|||||||
|
/**
|
||||||
|
* High voltage source control logic |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "high_voltage.h" |
||||||
|
#include "iopins.h" |
||||||
|
#include "global_state.h" |
||||||
|
#include <stdbool.h> |
||||||
|
#include <avr/interrupt.h> |
||||||
|
#include <util/atomic.h> |
||||||
|
|
||||||
|
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 MINIMAL_VOLTAGE 350.0 |
||||||
|
|
||||||
|
// sensing via resistive divider
|
||||||
|
#define VREF 1.1 |
||||||
|
|
||||||
|
// in kiloohms
|
||||||
|
#define R_UPPER 10000.0 |
||||||
|
#define R_LOWER 27.0 |
||||||
|
|
||||||
|
#define ADC_MAXVAL 1023 |
||||||
|
|
||||||
|
#define RDIV_FACTOR (R_LOWER / (R_UPPER + R_LOWER)) |
||||||
|
|
||||||
|
/// ADC input voltage that's too low - PWM must start
|
||||||
|
#define VSEN_TURN_ON (TURN_ON_VOLTAGE * RDIV_FACTOR) |
||||||
|
/// ADC input voltage that's too high - PWM must stop
|
||||||
|
#define VSEN_TURN_OFF (TURN_OFF_VOLTAGE * RDIV_FACTOR) |
||||||
|
/// ADC input voltage that's lowest possible for the geiger tube to function
|
||||||
|
#define VSEN_MINIMAL (MINIMAL_VOLTAGE * RDIV_FACTOR) |
||||||
|
|
||||||
|
// the above, but converted to ADC word
|
||||||
|
#define ADCVAL_TURN_ON ((uint16_t) (ADC_MAXVAL * (VSEN_TURN_ON / VREF))) |
||||||
|
#define ADCVAL_TURN_OFF ((uint16_t) (ADC_MAXVAL * (VSEN_TURN_OFF / VREF))) |
||||||
|
#define ADCVAL_MINIMAL ((uint16_t) (ADC_MAXVAL * (VSEN_MINIMAL / VREF))) |
||||||
|
|
||||||
|
/// Channel used to measure VSEN
|
||||||
|
#define VSEN_ADC_CHANNEL 0 |
||||||
|
|
||||||
|
|
||||||
|
/// when capacitor was last fully charged
|
||||||
|
static volatile uint16_t ts_cap_charged = 0; |
||||||
|
|
||||||
|
static void pwm_on() |
||||||
|
{ |
||||||
|
TCCR0A |= _BV(COM0B1); |
||||||
|
is_pwm_on = true; |
||||||
|
} |
||||||
|
|
||||||
|
static void pwm_off() |
||||||
|
{ |
||||||
|
TCCR0A &= ~_BV(COM0B1); |
||||||
|
is_pwm_on = false; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
ISR(ADC_vect) |
||||||
|
{ |
||||||
|
// Service the boost converter
|
||||||
|
uint16_t analog = ADCW; |
||||||
|
|
||||||
|
if (is_pwm_on) { |
||||||
|
if (analog >= ADCVAL_TURN_OFF) { |
||||||
|
pwm_off(); |
||||||
|
ts_cap_charged = timestamp_100ms; |
||||||
|
} else { |
||||||
|
// If fail to reach target voltage in reasonable time,
|
||||||
|
// show weak battery icon and stop trying.
|
||||||
|
if ((timestamp_100ms - ts_cap_charged) > 10 && analog < ADCVAL_MINIMAL) { |
||||||
|
is_weak_battery = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (analog < ADCVAL_TURN_ON) { |
||||||
|
pwm_on(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static void init_pwm_out() |
||||||
|
{ |
||||||
|
// Output is OC0A
|
||||||
|
as_output(D5); |
||||||
|
|
||||||
|
// initialize the timer
|
||||||
|
// Fast PWM mode, Output to OC0A
|
||||||
|
|
||||||
|
// clock is 16MHz, presc /64, counting to 80 -> freq 3125Hz
|
||||||
|
// Duty cycle = appx. 60%
|
||||||
|
|
||||||
|
OCR0A = 80; |
||||||
|
OCR0B = 46; |
||||||
|
TCCR0A = _BV(WGM00) | _BV(WGM01); |
||||||
|
TCCR0B = _BV(CS01) | _BV(CS00) | _BV(WGM02); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static void init_adc() |
||||||
|
{ |
||||||
|
ADCSRA = |
||||||
|
// 128 prescaler -> 125 kHz
|
||||||
|
_BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0) |
||||||
|
// auto trigger
|
||||||
|
| _BV(ADATE) |
||||||
|
// interrupt enable
|
||||||
|
| _BV(ADIE); |
||||||
|
|
||||||
|
ADCSRB = 0; // free-running
|
||||||
|
DIDR0 = ADC0D; // disable the digital input buffer on the pin
|
||||||
|
|
||||||
|
ADMUX = |
||||||
|
// internal ref 1.1V
|
||||||
|
_BV(REFS0) | _BV(REFS1) |
||||||
|
// select channel
|
||||||
|
| VSEN_ADC_CHANNEL; |
||||||
|
|
||||||
|
sbi(ADCSRA, ADEN); // Enable ADC
|
||||||
|
sbi(ADCSRA, ADSC); // Start
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void init_high_voltage() |
||||||
|
{ |
||||||
|
init_pwm_out(); |
||||||
|
init_adc(); |
||||||
|
} |
||||||
|
|
||||||
|
void hv_disable() |
||||||
|
{ |
||||||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { |
||||||
|
// if ADC is disabled, the IRQ never fires and it won't be turned on
|
||||||
|
cbi(ADCSRA, ADEN); |
||||||
|
// Turn it off
|
||||||
|
pwm_off(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
/**
|
||||||
|
* High voltage |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef CPROJ_HIGH_VOLTAGE_H |
||||||
|
#define CPROJ_HIGH_VOLTAGE_H |
||||||
|
|
||||||
|
/// Init HV source. Requires interrupts enabled!
|
||||||
|
void init_high_voltage(); |
||||||
|
|
||||||
|
/// Disable the HV source
|
||||||
|
void hv_disable(); |
||||||
|
|
||||||
|
#endif //CPROJ_HIGH_VOLTAGE_H
|
@ -0,0 +1,52 @@ |
|||||||
|
/**
|
||||||
|
* Radiation counting |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "radiation.h" |
||||||
|
#include "time_base.h" |
||||||
|
#include "global_state.h" |
||||||
|
#include "iopins.h" |
||||||
|
|
||||||
|
#include <avr/interrupt.h> |
||||||
|
#include <stdbool.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#define MEAS_BIN_COUNT 120 |
||||||
|
typedef uint8_t meas_bin_t; |
||||||
|
#define MEAS_MAX_COUNT 255 |
||||||
|
|
||||||
|
/// measurements in the last X seconds
|
||||||
|
static volatile meas_bin_t measurements[MEAS_BIN_COUNT]; |
||||||
|
/// Currently active measurement bin, increments once per second
|
||||||
|
static volatile uint8_t meas_bin = 0; |
||||||
|
|
||||||
|
// geiger tube pin change interrupt
|
||||||
|
ISR(INT0_vect) |
||||||
|
{ |
||||||
|
if (measurements[meas_bin] < MEAS_MAX_COUNT) { |
||||||
|
measurements[meas_bin]++; |
||||||
|
} |
||||||
|
req_update_display = true; |
||||||
|
} |
||||||
|
|
||||||
|
void second_callback_irq() |
||||||
|
{ |
||||||
|
meas_bin++; |
||||||
|
if (meas_bin >= MEAS_BIN_COUNT) { |
||||||
|
meas_bin = 0; |
||||||
|
} |
||||||
|
measurements[meas_bin] = 0; |
||||||
|
req_update_display = true; |
||||||
|
} |
||||||
|
|
||||||
|
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); |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
/**
|
||||||
|
* Radiation counting |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef CPROJ_RADIATION_H |
||||||
|
#define CPROJ_RADIATION_H |
||||||
|
|
||||||
|
void init_radiation(); |
||||||
|
|
||||||
|
#endif //CPROJ_RADIATION_H
|
@ -0,0 +1,33 @@ |
|||||||
|
/**
|
||||||
|
* Time base |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "time_base.h" |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <avr/interrupt.h> |
||||||
|
|
||||||
|
/// timestamp counted in units of 100ms
|
||||||
|
volatile uint16_t timestamp_100ms = 0; |
||||||
|
/// sub-second counter, counts 0-9 then overflows
|
||||||
|
static volatile uint16_t subsec_counter = 0; |
||||||
|
|
||||||
|
// 100ms counter
|
||||||
|
ISR(TIMER1_COMPA_vect) |
||||||
|
{ |
||||||
|
timestamp_100ms++; |
||||||
|
|
||||||
|
subsec_counter++; |
||||||
|
if (subsec_counter == 10) { |
||||||
|
subsec_counter = 0; |
||||||
|
second_callback_irq(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void init_timebase() |
||||||
|
{ |
||||||
|
// CTC & presc=256
|
||||||
|
TCCR1B = (1 << WGM12) | (1 << CS12); |
||||||
|
TIMSK1 = (1 << OCIE1A); // Enable CTC interrupt
|
||||||
|
OCR1A = 6250; // 100ms
|
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
/**
|
||||||
|
* TODO file description |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef CPROJ_TIME_BASE_H |
||||||
|
#define CPROJ_TIME_BASE_H |
||||||
|
|
||||||
|
|
||||||
|
void second_callback_irq(); |
||||||
|
void init_timebase(); |
||||||
|
|
||||||
|
#endif //CPROJ_TIME_BASE_H
|
@ -0,0 +1,48 @@ |
|||||||
|
/**
|
||||||
|
* Dispay |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "user_interface.h" |
||||||
|
#include "twi.h" |
||||||
|
#include "ssd1306.h" |
||||||
|
#include "sevenseg.h" |
||||||
|
#include "global_state.h" |
||||||
|
|
||||||
|
static struct SevenSeg sseg = { |
||||||
|
.x0 = 0, |
||||||
|
.y0 = 0, |
||||||
|
.charwidth = 17, |
||||||
|
.thick = 3, |
||||||
|
//.charwidth = 16,
|
||||||
|
//.thick = 1,
|
||||||
|
.spacing = 4, |
||||||
|
}; |
||||||
|
|
||||||
|
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 show_current_radiation() |
||||||
|
{ |
||||||
|
// TODO
|
||||||
|
sseg_number(&sseg, timestamp_100ms, 5, 0); |
||||||
|
} |
||||||
|
|
||||||
|
void show_empty_battery_icon() |
||||||
|
{ |
||||||
|
// TODO
|
||||||
|
sseg_number(&sseg, 9999, 5, 0); |
||||||
|
} |
||||||
|
|
||||||
|
void show_loading_icon() |
||||||
|
{ |
||||||
|
// TODO
|
||||||
|
sseg_number(&sseg, 0, 5, 0); |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
/**
|
||||||
|
* UI |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef CPROJ_USER_INTERFACE_H |
||||||
|
#define CPROJ_USER_INTERFACE_H |
||||||
|
|
||||||
|
void init_user_interface(); |
||||||
|
|
||||||
|
void show_current_radiation(); |
||||||
|
|
||||||
|
void show_empty_battery_icon(); |
||||||
|
|
||||||
|
void show_loading_icon(); |
||||||
|
|
||||||
|
#endif //CPROJ_USER_INTERFACE_H
|
Loading…
Reference in new issue