Skip to content

Commit

Permalink
Add ADC touch library
Browse files Browse the repository at this point in the history
  • Loading branch information
MCUdude committed Nov 16, 2021
1 parent 0fb2446 commit 4d04e4f
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 4 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,6 @@ Due to the limited hardware not all default Arduino functions and libraries is s
- [transfer()](https://www.arduino.cc/en/Reference/SPITransfer)
- ~~[usingInterrupt()](https://www.arduino.cc/en/Reference/SPIusingInterrupt)~~ **Not implemented**


* [I2C master library, **TinyWire.h** (software implementation)](https://www.arduino.cc/en/reference/wire)
- [begin()](https://www.arduino.cc/en/Reference/WireBegin)
- [beginTransmission()](https://www.arduino.cc/en/Reference/WireBeginTransmission)
Expand Down Expand Up @@ -289,6 +288,9 @@ Due to the limited hardware not all default Arduino functions and libraries is s
- [put()](https://github.com/MCUdude/MicroCore/tree/master/avr/libraries/Flash/README.md#put)
- [get()](https://github.com/MCUdude/MicroCore/tree/master/avr/libraries/Flash/README.md#get)

* [Capacitive touch, **ADCTouch.h**](https://github.com/MCUdude/MicroCore/tree/master/avr/libraries/ADCTouch)
- [read()](https://github.com/MCUdude/MicroCore/tree/master/avr/libraries/ADCTouch/README.md#read)

## Acknowledgements
MicroCore is based Smeezekitty's [core13](https://sourceforge.net/projects/ard-core13/), which is an Arduino ATtiny13 hardware package for IDE 1.0.x.
Expand Down
48 changes: 48 additions & 0 deletions avr/libraries/ADCTouch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# ADCTouch
ADCTouch is a light-weight, bare-bone capacitive touch library specifically written and optimized for ATtiny13. It allows users to create capacitive touch sensors without any external hardware. Each capacitive touch sensor requires a separate ADC pin.
See the [examples](https://github.com/MCUdude/MicroCore/tree/master/avr/libraries/ADCTouch/examples) on how this library can be utilized.

Developed by [MCUdude](https://github.com/MCUdude/). Based on the work done by [nerdralph](https://github.com/nerdralph/nerdralph/blob/master/avr/adctouch.c) and [martin2250](https://github.com/martin2250/ADCTouch).


## How it works
From [martin2250's library](https://github.com/martin2250/ADCTouch):

To Acquire a reading, the library does the following:
* Charge the test pin to VCC through the internal pullup resistor (not directly to prevent short circuits)
* Discharge the internal ~14pF capacitor
* Set the pin to tristate
* Connect the ~14pF capacitor with the pin so that charge distributes evenly
* Measure the voltage of the internal cap using the ADC.
If the pin has a low capacitance, the stored charge will be small as will the resulting voltage, if the external capacitance is equal to 14pF, the volatage should be ~2.5V. Even higher capacitances will result in voltages > 2.5V. The ATtiny13 already has stray capacitances that will produce an output of ~390 and just a single external wire can boost that up to 500, so you really need offset compensation.
The accuracy is really good, most often even the LSB/smalles digit can still yield usable data and just vary by a single unit between readings (at only 64 samples, more will mean even less variation). The sensitivity is phenomenal, with a large enough surface, it can sense a person in more than 2 feet distance.


## samples
Static constant to set how many samples each reading will do before it returns the result.
Note that the assigned value must be a power of two.

### Declaration
``` c++
static const uint16_t samples;
```

### Usage
``` c++
const uint16_t ADCTouch::samples = 32; // Sample each touch pin 32 times
```


## read()
Function that reads an ADC pin and returns an average reading based on the number of samples.
Parameter has to be a `analog_pin_t` constant, `A0` to `A5`.

### Declaration
``` c++
static int16_t read(const analog_pin_t adc_channel);
```
### Usage
``` c++
int16_t reading = Touch.read(A2); // Read touch on analog pin A2
```
54 changes: 54 additions & 0 deletions avr/libraries/ADCTouch/examples/Touch_LED/Touch_LED.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/***********************************************************************|
| Capacitive touch library for ATtiny13 |
| |
| Touch_LED.ino |
| |
| A light-weight library for using the ADC inputs on the ATtiny13 as |
| capacitive touch sensors. |
| Developed by MCUdude, based on nerdralph's adctouch implementation. |
| https://github.com/MCUdude/MicroCore |
| |
| In this example we use A2 and A3 as touch sensor pins, and two LEDs |
| will light up if the touch pins are being touched and the value is |
| greater than the threshold. |
|***********************************************************************/

#include <ADCTouch.h>

// Sample each touch pin 32 times
const uint16_t ADCTouch::samples = 32;

// LED pins
const uint8_t LED1 = 1;
const uint8_t LED2 = 2;

// Touch reference values to zero out the offset
int16_t ref_A2;
int16_t ref_A3;

// Touch threshold for turning on or off the LEDs
// Lower is more sensitive
const uint8_t threshold = 5;


void setup()
{
// Set LED pins as output
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);

// Reference values to account for the capacitance of the touch pad
ref_A2 = Touch.read(A2);
ref_A3 = Touch.read(A3);
}

void loop()
{
// Read touch
int16_t touch_A2 = Touch.read(A2) - ref_A2;
int16_t touch_A3 = Touch.read(A3) - ref_A3;

// Turn on or off LED based on threshold
digitalWrite(LED1, touch_A2 > threshold);
digitalWrite(LED2, touch_A3 > threshold);
}
75 changes: 75 additions & 0 deletions avr/libraries/ADCTouch/examples/Touch_read/Touch_read.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/***********************************************************************|
| Capacitive touch library for ATtiny13 |
| |
| Touch_read.ino |
| |
| A light-weight library for using the ADC inputs on the ATtiny13 as |
| capacitive touch sensors. |
| Developed by MCUdude, based on nerdralph's adctouch implementation. |
| https://github.com/MCUdude/MicroCore |
| |
| In this example we use A2 and A3 as touch sensor pins, and prints out |
| the boolean and the actual measurement values to the serial monitor. |
| |
| SERIAL REMINDER |
| The baud rate is ignored on the ATtiny13 due to using a simplified |
| serial. The baud rate used is dependent on the processor speed. |
| Note that you can specify a custom baud rate if the following ones |
| does not fit your application. |
| |
| THESE CLOCKS USES 115200 BAUD: THIS CLOCK USES 57600 BAUD: |
| 20 MHz, 16 MHz, 9.6 MHz, 8 MHz 4.8 MHz |
| THESE CLOCKS USES 19200 BAUD: THIS CLOCK USES 9600 BAUD: |
| 1.2 MHz, 1 MHz 600 KHz |
| |
| If you get garbage output: |
| 1. Check baud rate as above |
| 2. Check if you have anything else connected to TX/RX like an LED |
| 3. Check OSCCAL (see MicroCore OSCCAL tuner example) |
|***********************************************************************/

#include <ADCTouch.h>

// Sample each touch pin 32 times
const uint16_t ADCTouch::samples = 32;

// Touch reference values to zero out the offset
int16_t ref_A2;
int16_t ref_A3;

// Touch threshold for turning on or off the LEDs
// Lower is more sensitive
const uint8_t threshold = 20;


void setup()
{
Serial.begin();

// Reference values to account for the capacitance of the touch pad
ref_A2 = Touch.read(A2);
ref_A3 = Touch.read(A3);
}

void loop()
{
// Read touch
int16_t val_A2 = Touch.read(A2);
int16_t val_A3 = Touch.read(A3);

// Remove offset
val_A2 -= ref_A2;
val_A3 -= ref_A3;

Serial.print(F("A2 touch bool: "));
Serial.print(val_A2 > threshold); // Send (boolean) pressed or not pressed
Serial.print(F(", A2 touch value: "));
Serial.print(val_A2);

Serial.print(F("\tA3 touch bool: "));
Serial.print(val_A3 > threshold); // Send (boolean) pressed or not pressed
Serial.print(F(", A3 touch value: "));
Serial.print(val_A3);
Serial.print('\n');
delay(100);
}
22 changes: 22 additions & 0 deletions avr/libraries/ADCTouch/keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#######################################
# Syntax Coloring Map For ADCTouch
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

ADCTouch KEYWORD1
Touch KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

read KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################

samples LITERAL1
9 changes: 9 additions & 0 deletions avr/libraries/ADCTouch/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=ADCTouch
version=1.0.0
author=MCUdude
maintainer=MCUdude
sentence=Create Touch Sensors with a single analog pin without external hardware
paragraph=ADCTouch uses the internal wiring of AVR microcontroller to measure capacitance
category=Sensors
url=https://github.com/MCUdude/MicroCore
architectures=avr
50 changes: 50 additions & 0 deletions avr/libraries/ADCTouch/src/ADCTouch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
ADCTouch.cpp - Library for Capacittive touch sensors using only one ADC PIN
Created by martin2250, April 23, 2014.
Released into the public domain.
*/

#include "ADCTouch.h"

// Predefined object
ADCTouch Touch;

ADCTouch::ADCTouch()
{

}

int16_t ADCTouch::read(const analog_pin_t adc_channel)
{
// Compile time check for number of samples
if(samples == 0 || samples > 512 || (samples & (samples - 1)))
badArg("Number of samples must be a power of two, greater than zero and max 512!");

uint16_t samples_left = samples;
int16_t level = 0;
uint8_t digitalPin = pgm_read_byte(analog_pin_to_digital_pin + adc_channel);
do
{
ADMUX = (1 << ADLAR) | adc_channel; // Select ADC channel
DDRB |= (1 << digitalPin); // Discharge touchpad

ADCSRA |= (1 << ADEN); // Enable ADC & discharge S/H cap
_delay_us(1); // Sample and hold RC time
ADCSRA = 0; // ADC off
PORTB |= (1 << digitalPin); // Charge touchpad

DDRB &= ~(1 << digitalPin); // Input mode
PORTB &= ~(1 << digitalPin); // Pullup off

// Enable ADC with /16 prescaler, equalize S/H cap charge
ADCSRA = (1 << ADPS2) | (0 << ADPS1) | (0 << ADPS0) | (1 << ADEN);
_delay_us(1); // Sample and hold RC time

ADCSRA |= (1 << ADSC); // Start ADC conversion
while (bit_is_set(ADCSRA, ADSC)); // Wait for conversion to complete
level += ADCH;
ADCSRA = 0; // ADC off
}
while(--samples_left);
return level / samples;
}
37 changes: 37 additions & 0 deletions avr/libraries/ADCTouch/src/ADCTouch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
ADCTouch.h - Library for Capacittive touch sensors using a single ADC pin
Created by MCUdude
Based on the work done by martin2250 and nerdralph.
Released into the public domain.
*/

#ifndef ADCTOUCH_H
#define ADCTOUCH_H

#include "Arduino.h"

// Maps analog pins to digital pins
const uint8_t PROGMEM analog_pin_to_digital_pin[] =
{
5, // A0
2, // A1
4, // A2
3, // A3
NOT_A_PIN,
NOT_A_PIN
};

class ADCTouch
{
public:
ADCTouch();
static int16_t read(const analog_pin_t adc_channel);
static const uint16_t samples;

private:
static void badArg(const char*) __attribute__((error("")));
};

extern ADCTouch Touch;

#endif
2 changes: 0 additions & 2 deletions avr/libraries/TinyWire/src/TinyWire.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "TinyWire.h"

// Predefined object
TinyWire Wire;

/**
* @brief Construct a new TinyWire object
Expand Down
2 changes: 1 addition & 1 deletion avr/libraries/TinyWire/src/TinyWire.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ class TinyWire
static uint16_t read_bytes;
};

extern TinyWire Wire;
static TinyWire Wire;

#endif

0 comments on commit 4d04e4f

Please sign in to comment.