Files
2024-07-20 22:09:06 +08:00

248 lines
8.5 KiB
C++

/*
CapacitiveSense.h v.04 - Capacitive Sensing Library for 'duino / Wiring
https://github.com/PaulStoffregen/CapacitiveSensor
http://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html
http://playground.arduino.cc/Main/CapacitiveSensor
Copyright (c) 2009 Paul Bagder All right reserved.
Version 05 by Paul Stoffregen - Support non-AVR board: Teensy 3.x, Arduino Due
Version 04 by Paul Stoffregen - Arduino 1.0 compatibility, issue 146 fix
vim: set ts=4:
*/
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#include "pins_arduino.h"
#include "WConstants.h"
#endif
#include "CPlay_CapacitiveSensor.h"
/**************************************************************************/
/*!
@brief Function that handles the creation and setup of instances
@param sendPin send pin for the sensor
@param receivePin the receiving pin for the sensor
*/
/**************************************************************************/
CPlay_CapacitiveSensor::CPlay_CapacitiveSensor(uint8_t sendPin, uint8_t receivePin)
{
// initialize this instance's variables
error = 1;
loopTimingFactor = 300; // determined empirically - a hack
CS_Timeout_Millis = (2000 * (float)loopTimingFactor * (float)F_CPU) / 16000000;
CS_AutocaL_Millis = 20000;
_sendPin = sendPin;
_receivePin = receivePin;
// Serial.print("timeOut = ");
// Serial.println(CS_Timeout_Millis);
// get pin mapping and port for send Pin - from PinMode function in core
#ifdef NUM_DIGITAL_PINS
if ((sendPin != 255) && (sendPin >= NUM_DIGITAL_PINS)) error = -3;
if (receivePin >= NUM_DIGITAL_PINS) error = -2;
#endif
if (sendPin != -1) { // sendpin to OUTPUT if we have one
#ifdef ARDUINO_TEEONARDU_FLORA // terrible hack!
DDRD |= _BV(5);
#else
pinMode(sendPin, OUTPUT);
#endif
}
pinMode(receivePin, INPUT); // receivePin to INPUT
#ifdef ARDUINO_TEEONARDU_FLORA
// terrible hack!
PORTD &= ~_BV(5);
#else
digitalWrite(sendPin, LOW);
#endif
if (sendPin != -1) {
send_outport = portOutputRegister(digitalPinToPort(sendPin));
send_mask = digitalPinToBitMask(sendPin);
} else {
send_outport = NULL;
send_mask = 0;
}
recv_outport = portOutputRegister(digitalPinToPort(receivePin));
recv_inport = portInputRegister(digitalPinToPort(receivePin));
recv_mask = digitalPinToBitMask(receivePin);
recv_direction = portModeRegister(digitalPinToPort(receivePin));
// get pin mapping and port for receive Pin - from digital pin functions in Wiring.c
leastTotal = 0x0FFFFFFFL; // input large value for autocalibrate begin
lastCal = millis(); // set millis for start
}
// Public Methods //////////////////////////////////////////////////////////////
// Functions available in Wiring sketches, this library, and other libraries
/**************************************************************************/
/*!
@brief get a capacitive sensor reading
@param samples number of samples to take
@return the sensor reading
*/
/**************************************************************************/
long CPlay_CapacitiveSensor::capacitiveSensor(uint8_t samples)
{
total = 0;
if (samples == 0) return 0;
if (error < 0) {
return -1; // bad pin
}
pinMode(_receivePin, INPUT);
for (uint8_t i = 0; i < samples; i++) { // loop for samples parameter - simple lowpass filter
if (SenseOneCycle() < 0) return -2; // variable over timeout
}
// only calibrate if time is greater than CS_AutocaL_Millis and total is less than 10% of baseline
// this is an attempt to keep from calibrating when the sensor is seeing a "touched" signal
if ( (millis() - lastCal > CS_AutocaL_Millis) &&
abs(total - leastTotal) < (int)(.10 * (float)leastTotal) ) {
// Serial.println(); // debugging
// Serial.println("auto-calibrate");
// Serial.println();
// delay(2000); */
leastTotal = 0x0FFFFFFFL; // reset for "autocalibrate"
lastCal = millis();
}
/*else{ // debugging
Serial.print(" total = ");
Serial.print(total);
Serial.print(" leastTotal = ");
Serial.println(leastTotal);
Serial.print("total - leastTotal = ");
x = total - leastTotal ;
Serial.print(x);
Serial.print(" .1 * leastTotal = ");
x = (int)(.1 * (float)leastTotal);
Serial.println(x);
} */
// routine to subtract baseline (non-sensed capacitance) from sensor return
if (total < leastTotal) leastTotal = total; // set floor value to subtract from sensed value
return(total - leastTotal);
}
/**************************************************************************/
/*!
@brief get a raw sensor reading
@param samples the number of samples to take
@return -1 for error, -2 for timeout, other values are a raw sensor reading
*/
/**************************************************************************/
long CPlay_CapacitiveSensor::capacitiveSensorRaw(uint8_t samples)
{
total = 0;
if (samples == 0) return 0;
if (error < 0) return -1; // bad pin - this appears not to work
for (uint8_t i = 0; i < samples; i++) { // loop for samples parameter - simple lowpass filter
if (SenseOneCycle() < 0) return -2; // variable over timeout
}
return total;
}
/**************************************************************************/
/*!
@brief reset the auto calibration
*/
/**************************************************************************/
void CPlay_CapacitiveSensor::reset_CS_AutoCal(void){
leastTotal = 0x0FFFFFFFL;
}
/**************************************************************************/
/*!
@brief set the auto-calibration time
@param autoCal_millis the desired calibration time in milliseconds
*/
/**************************************************************************/
void CPlay_CapacitiveSensor::set_CS_AutocaL_Millis(unsigned long autoCal_millis){
CS_AutocaL_Millis = autoCal_millis;
}
/**************************************************************************/
/*!
@brief set the sensor timeout
@param timeout_millis the number of milliseconds to set the timeout to
*/
/**************************************************************************/
void CPlay_CapacitiveSensor::set_CS_Timeout_Millis(unsigned long timeout_millis){
CS_Timeout_Millis = (timeout_millis * (float)loopTimingFactor * (float)F_CPU) / 16000000; // floats to deal with large numbers
}
// Private Methods /////////////////////////////////////////////////////////////
// Functions only available to other functions in this library
/**************************************************************************/
/*!
@brief sense a single sicle
@return the reading
*/
/**************************************************************************/
int CPlay_CapacitiveSensor::SenseOneCycle(void)
{
if (send_mask != 0) {
noInterrupts();
*send_outport &= ~send_mask; // sendPin Register low
*recv_direction &= ~recv_mask; // receivePin to input (pullups are off)
*recv_direction |= recv_mask; // receivePin to OUTPUT
*recv_outport &= ~recv_mask; // pin is now LOW AND OUTPUT
delayMicroseconds(10);
*recv_direction &= ~recv_mask; // receivePin to input (pullups are off)
*send_outport |= send_mask; // sendPin Register high
interrupts();
while ( !(*recv_inport & recv_mask) && (total < CS_Timeout_Millis) ) { // while receive pin is LOW AND total is positive value
total++;
}
//Serial.print("SenseOneCycle(1): "); Serial.println(total);
if (total > CS_Timeout_Millis) {
return -2; // total variable over timeout
}
}
// set receive pin HIGH briefly to charge up fully - because the while loop above will exit when pin is ~ 2.5V
noInterrupts();
*send_outport &= ~send_mask; // sendPin Register low
*recv_direction |= recv_mask; // receivePin to OUTPUT
*recv_outport |= recv_mask; // pin is now HIGH AND OUTPUT
delayMicroseconds(10);
*recv_direction &= ~recv_mask; // receivePin to input (pullups are off)
*recv_outport &= ~recv_mask;
if (send_mask != 0) {
*send_outport &= ~send_mask; // sendPin Register high
}
interrupts();
while ((*recv_inport & recv_mask) && (total < CS_Timeout_Millis) ) {
total++; // while receive pin is HIGH AND total is less than timeout
}
//Serial.print("SenseOneCycle(2): "); Serial.println(total);
if (total >= CS_Timeout_Millis) {
return -2; // total variable over timeout
} else {
return 1;
}
}