Skip to content

Instantly share code, notes, and snippets.

@jgillick
Last active August 29, 2015 14:21
Show Gist options
  • Save jgillick/eedbefe50453dbcd8132 to your computer and use it in GitHub Desktop.
Save jgillick/eedbefe50453dbcd8132 to your computer and use it in GitHub Desktop.
Cap Sensor with Input Capture Interrupt
/**
* 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