Skip to content

Instantly share code, notes, and snippets.

@goebish
Created July 16, 2019 17:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save goebish/e18ce331e43442a6719751304b8905b5 to your computer and use it in GitHub Desktop.
Save goebish/e18ce331e43442a6719751304b8905b5 to your computer and use it in GitHub Desktop.
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <CircularBuffer.h> // https://github.com/abouvier/CircularBuffer/archive/master.zip
#include <MovingAverage.h> // https://github.com/abouvier/MovingAverage/archive/master.zip
#include <TinyTimer.h> // https://github.com/abouvier/TinyTimer/archive/master.zip
#define LED_PIN 4
#define BUZZER_PIN 9 // do not change, driven by hardware counter
#define GEIGER_PIN 2 // must be D2 or D3
#define VBAT_PIN A7
#define VTUBE_PIN A6 // HV+ --> 10M ohm --> VTUBE_PIN --> 47k ohm --> GND
#define VTUBE_MULT 192
// SPI PCD8544
#define PCD8544_CLK 13 // do not change, hardware SPI SCK
#define PCD8544_DIN 11 // do not change, hardware SPI MOSI
#define PCD8544_DC 6
#define PCD8544_CE 7
#define PCD8544_RST 8
#define PCD8544_BL 5 // backlight, must be D5 or D6 to use PWM (TIMER1 & TIMER2 are reused for other stuffs)
#define CYCLE_SIZE 60
#define BAT_AVERAGE 10
#define PRINT_DELAY 250
volatile uint16_t cps;
uint16_t last_cps;
MovingAverage<volatile uint16_t, CYCLE_SIZE> cpm;
MovingAverage<uint16_t, BAT_AVERAGE> vsense[3];
TinyTimer<millis> timers[2];
Adafruit_PCD8544 display(PCD8544_DC, PCD8544_CE, PCD8544_RST);
enum {
VBATTERY,
VTUBE,
VCC
};
////
// setup one-shot pulse generator for buzzer, use TIMER1
void osp_setup()
{
cli();
TCCR1B = 0; // halt counter
TCNT1 = 0; // start counting at bottom
ICR1 = 0; // TOP = 0
TCCR1A = (1 << COM1A0) | (1 << COM1A1) | (1 << WGM11); // OC1A=Set on Match, clear on BOTTOM. Mode 14 Fast PWM
TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10); // prescaler = 1 (Max ~4mS); Start counting now
OCR1A = 64000; // 0x7fff = 2ms pulse @16MHz, larger = shorter
DDRB = (1 << 1); // Set pin to output (OC1A = PB1 = Arduino D9)
sei();
}
// Test if there is a pulse still in progress
#define OSP_INPROGRESS() (TCNT1>0)
// trigger one-shot pulse
#define OSP_FIRE() (TCNT1 = OCR1A - 1)
// GM tube tick interrupt
void geiger_isr()
{
cps++;
// tick buzzer
if (!OSP_INPROGRESS()) {
OSP_FIRE();
}
}
void buffer()
{
cli();
last_cps = cps;
cps = 0;
sei();
cpm.push(last_cps);
vsense[VBATTERY].push(analogRead(VBAT_PIN));
vsense[VTUBE].push(analogRead(VTUBE_PIN));
vsense[VCC].push(readVcc());
}
void printdigit(uint8_t val)
{
if(val<10)
display.print("0");
display.print(val);
}
long readVcc()
{
long voltage = 0;
uint16_t wADC;
// Read 1.1V reference against AVcc
// set the reference to Vcc and the measurement to the internal 1.1V reference
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
ADCSRA |= _BV(ADEN); // enable the ADC
delay(20); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA, ADSC)); // measuring
wADC = ADCW; // Reading register "ADCW" takes care of how to read ADCL first and ADCH then.
voltage = 1127000L / wADC; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
return voltage; // Vcc in millivolts
}
#define AVG_VCC (vsense[VCC].average()/1000.0f)
void refresh_header()
{
display.setTextSize(1);
// main battery
display.setCursor(0, 0);
display.print(vsense[VBATTERY].average() * AVG_VCC / 1023.0f);
display.print("V");
// tube voltage
display.setCursor(84 - 6 * 4, 0);
display.print((uint16_t)floor((vsense[VTUBE].average() * AVG_VCC / 1023.0f) * VTUBE_MULT));
display.print("V");
}
void refresh()
{
display.clearDisplay();
refresh_header();
// CPM
display.setTextSize(2);
display.setCursor(0, 16);
uint32_t count = cpm.sum() * (60 / cpm.capacity());
display.print(count);
if (count >= 1000)
display.setTextSize(1);
display.print(" CPM ");
// CPS
display.setTextSize(1);
display.setCursor(0, 32);
display.print(last_cps);
display.print(" CPS ");
// STS-5 CPM to µSievert/hour:
// CPM / 171 = uSv/h
// Sievert <-> Roentgen:
// 1 R = 0.00933 Sv; 1 Sv = 107.185 R
display.setTextSize(1);
display.setCursor(0, 40);
display.print(count / 171.0f);
display.print(" uSv/h ");
display.display();
}
void setup()
{
osp_setup();
//encoder_setup();
pinMode(LED_PIN, OUTPUT);
pinMode(GEIGER_PIN, INPUT_PULLUP);
pinMode(PCD8544_BL, OUTPUT);
analogWrite(PCD8544_BL, 127);
display.begin(40,4); // contrast, bias
display.setRotation(2); // 180°, header on top
refresh();
attachInterrupt(digitalPinToInterrupt(GEIGER_PIN), geiger_isr, FALLING);
timers[1].init(refresh, PRINT_DELAY);
timers[0].init(buffer, 1000);
}
void loop()
{
TinyTimer<millis>::update(timers);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment