-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathGeiger_counter.ino
156 lines (130 loc) · 3.82 KB
/
Geiger_counter.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Geiger counter firmware for dual-input ATtiny841 @ 11.0592MHz board
//
// Thomas Kircher <[email protected]>, 2018
// Note to self:
// Fuses must be set for external high-speed crystal oscillator:
// avrdude ... -U lfuse:w:0xFE:m
//
// 1 - unprogrammed, 0 - programmed
//
// CKDIV8 - 1 - Don't divide clock by 8
// CKOUT - 1 - Don't output system clock on a port pin
// - 1 - (reserved)
// SUT - 1 - System start-up time set to 1k clocks
//
// CKSEL3 - 1 |
// CKSEL2 - 1 | Crystal oscillator (>8MHz)
// CKSEL1 - 1 | CKSEL0 actually used for SUT setting (p.30)
// CKSEL0 - 0 |
// Global variables
unsigned char i;
unsigned char seconds = 0; // Number of seconds
unsigned short cpm_ch1 = 0; // Counts per minute from channel 1
unsigned short cpm_ch2 = 0; // Counts per minute from channel 2
volatile byte state = LOW; // Click state
// This is an implementation of AN2447 for ATtiny841
//
// We let the ADC input be the internal 1.1v bandgap reference (Vbg), and
// set the ADC reference to Vcc. Then we perform an ADC conversion (10-bit),
// which gives us:
// ADC = Vin x 2^10 / Vref, or Vcc = 2^10 x Vbg / ADC
//
// (12/11/2018 - Using a 3.3v regulator, so this is redundant)
/*
float battery_level() {
float Vcc = 0.0;
ADMUXA = 0b00001101; // Internal 1.1v BG reference - MUX[5:0] = 00 1101
ADMUXB = 0b00000000; // ADC reference is Vcc: REFS[2:0] = 000, gain set to 1
ADCSRA = 0b10000101; // Enable ADC, no interrupts, clock prescaler = 32
ADCSRB = 0b00001000; // Left-adjust result, no auto trigger
ADCSRA |= (1 << ADSC); // Start ADC conversion
while(ADCSRA & (1 << ADSC)); // Wait for conversion to complete
Vcc = (0x400 * 1.1) / ADCH; // Throw away the LSB, only use 8 bits.
return Vcc;
}
*/
void setup() {
// Initialize I/O pins
pinMode(2, OUTPUT); // LED
pinMode(3, OUTPUT); // Piezo
pinMode(10, INPUT); // Input channel 1
pinMode(7, INPUT); // Input channel 2
// Initialize port states
digitalWrite(2, LOW);
digitalWrite(3, LOW);
// Enable interrupts for PCINT[7:0]
GIMSK |= (1 << PCIE0);
// Enable pin change interrupts for PC0, PC3
PCMSK0 |= (1 << PCINT0) | (1 << PCINT3);
// Initialize timer
// On the ATtiny841, CTC (Clear Timer on Compare) is what the
// normal timer mode is called.
// No compare outputs, CTC mode (OCR1A), timer stopped for config
// WGM[3:0] = 0100 - see datasheet, p.113
TCCR1A = 0x00;
TCCR1B = 0x08;
// Zero the timer
TCNT1H = 0x00;
TCNT1L = 0x00;
// Reset the prescaler
GTCCR = 0x01;
// Set the timer interval to one second:
// 11.0592MHz with clk/256 prescale = 43200 = 0xA8C0
OCR1AH = 0xA8;
OCR1AL = 0xC0;
// Enable timer interrupt (CTC)
TIMSK1 = 0x02;
// Initialize serial comms
Serial.begin(57600);
// Say hello
Serial.println("Geiger counter initialized");
// Start timer
TCCR1B |= 0x04;
}
// the loop function runs over and over again forever
void loop() {
if(state == HIGH) {
// Blink
digitalWrite(2, HIGH);
delayMicroseconds(200);
digitalWrite(2, LOW);
// Also chirp
for(i = 0; i < 200; i++) {
digitalWrite(3, HIGH);
delayMicroseconds(47);
digitalWrite(3, LOW);
delayMicroseconds(47);
}
// Set state back to low
state = LOW;
}
}
// Pin state change interrupt
ISR(PCINT0_vect) {
// PA0 is channel 1, PA3 is channel 2
// Keep track of the number of counts on each channel, and
// set the click state high for either.
if(PINA & (1 << PINA0)) {
cpm_ch1++;
state = HIGH;
}
if(PINA & (1 << PINA3)) {
cpm_ch2++;
state = HIGH;
}
}
// Timer interrupt
//
// For now, we just output total counts every second
ISR(TIMER1_COMPA_vect) {
if(seconds < 60)
seconds++;
else {
seconds = 0;
}
Serial.print("counts: ");
Serial.print(cpm_ch1);
Serial.print(" ");
Serial.println(cpm_ch2);
}
// EOF