Last active
August 29, 2015 14:21
-
-
Save jgillick/eedbefe50453dbcd8132 to your computer and use it in GitHub Desktop.
Cap Sensor with Input Capture Interrupt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A non-blocking capacitive proximity sensor | |
* | |
* Circuit: | |
* | |
* PD4 PD7 | |
* ---- ---- | |
* | | | |
* |__/\/\/\___| | |
* 10M | | |
* | | |
* --- | |
* Sensor | |
* | |
* | |
* - Arduino Pin 4 (PD4) charges the circuit | |
* - Arduino Pin 7 (PD7) is connected to the sensor | |
* - Both pins are connected togeter via a resistor (5M - 10M) | |
*/ | |
#define PIN_CHARGE 4 | |
#define PIN_SENSE 7 | |
#define PIN_LED 11 | |
#define NUM_SAMPLES 20 | |
#define SMOOTHNESS 0.08 | |
volatile int8_t isDone = 0; | |
volatile int32_t time = 0, | |
overflows = 0; | |
int8_t sampleIndex = 0; | |
int32_t samplesTotal = 0, | |
sampleMax = 0, | |
sampleMin = 0, | |
sensorValue = 0, | |
rawValue = 0, | |
lastPrint; | |
int32_t samples[NUM_SAMPLES]; | |
ISR(TIMER1_OVF_vect) { | |
overflows++; | |
if (overflows >= 100) { | |
time = (overflows << 16); | |
TCCR1B = 0; | |
overflows = 0; | |
TCNT1 = 0; | |
TIMSK1 = 0; | |
TIFR1 = 0xff; | |
// Discharge | |
digitalWrite(PIN_CHARGE, LOW); | |
pinMode(PIN_SENSE, OUTPUT); | |
digitalWrite(PIN_SENSE, LOW); | |
} | |
} | |
ISR(TIMER1_CAPT_vect) { | |
time = (ICR1 + (overflows << 16)); | |
isDone = true; | |
// Reset | |
TCCR1B = 0; | |
overflows = 0; | |
TCNT1 = 0; | |
TIMSK1 = 0; | |
// Discharge | |
digitalWrite(PIN_CHARGE, LOW); | |
pinMode(PIN_SENSE, OUTPUT); | |
digitalWrite(PIN_SENSE, LOW); | |
} | |
void perpareInterrupt() { | |
// Clear all interrupt flags | |
TIFR1 = 0xff; | |
// Enable overflow and input capture interrupts | |
TIMSK1 = 1 << ICIE1 | 1 << TOIE1; | |
// 1.1V Bandgap reference on non-inverting (+) input and connect output to timer | |
ACSR = 1 << ACBG | 1 << ACIC; | |
// Start timer, prescale by 8 | |
TCCR1B = (1 << CS11); //(1<<CS10); | |
// Clear timer state | |
TCCR1A = 0; | |
// Reset timers | |
TCNT1 = 0; | |
} | |
void setup() { | |
Serial.begin(9600); | |
pinMode(PIN_LED, OUTPUT); | |
pinMode(PIN_SENSE, INPUT); | |
pinMode(PIN_CHARGE, OUTPUT); | |
sei(); | |
getNextSensorValue(); | |
} | |
void loop() { | |
readSensorValue(); | |
if (lastPrint + 250 < millis()) { | |
Serial.println(sensorValue); | |
lastPrint = millis(); | |
} | |
digitalWrite(PIN_LED, sensorValue > 280); | |
} | |
void readSensorValue() { | |
if (isDone) { | |
samples[sampleIndex++] = time; | |
if (sampleIndex == NUM_SAMPLES) { | |
sampleIndex = 0; | |
filterSamples(); | |
} | |
getNextSensorValue(); | |
} | |
} | |
void getNextSensorValue() { | |
pinMode(PIN_SENSE, INPUT); | |
isDone = 0; | |
overflows = 0; | |
perpareInterrupt(); | |
digitalWrite(PIN_CHARGE, HIGH); | |
} | |
void filterSamples() { | |
int32_t sum = 0, | |
lowVal = samples[0], | |
highVal = samples[0], | |
value; | |
// Add up all values within 15% of the median | |
for (int i = 0; i < NUM_SAMPLES; i++){ | |
value = samples[i]; | |
if (value < lowVal) { | |
lowVal = value; | |
} | |
else if (value > highVal) { | |
highVal = value; | |
} | |
sum += value; | |
} | |
// Get average | |
if (sum >= 0) { | |
sum -= highVal + lowVal; | |
value = sum / NUM_SAMPLES - 2; | |
} else { | |
value = 0; | |
} | |
rawValue = value; | |
// Only update if value is not within x% of existing sensor value | |
if (value != sensorValue && abs(value -sensorValue) > (SMOOTHNESS * sensorValue)) { | |
sensorValue = value; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment