diff --git a/README.md b/README.md index 9ac847e8..f0eebebb 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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. diff --git a/avr/libraries/ADCTouch/README.md b/avr/libraries/ADCTouch/README.md new file mode 100644 index 00000000..3ada4642 --- /dev/null +++ b/avr/libraries/ADCTouch/README.md @@ -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 +``` diff --git a/avr/libraries/ADCTouch/examples/Touch_LED/Touch_LED.ino b/avr/libraries/ADCTouch/examples/Touch_LED/Touch_LED.ino new file mode 100644 index 00000000..d7f11dc4 --- /dev/null +++ b/avr/libraries/ADCTouch/examples/Touch_LED/Touch_LED.ino @@ -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 + +// 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); +} diff --git a/avr/libraries/ADCTouch/examples/Touch_read/Touch_read.ino b/avr/libraries/ADCTouch/examples/Touch_read/Touch_read.ino new file mode 100755 index 00000000..ad5b3501 --- /dev/null +++ b/avr/libraries/ADCTouch/examples/Touch_read/Touch_read.ino @@ -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 + +// 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); +} diff --git a/avr/libraries/ADCTouch/keywords.txt b/avr/libraries/ADCTouch/keywords.txt new file mode 100755 index 00000000..16abb2a8 --- /dev/null +++ b/avr/libraries/ADCTouch/keywords.txt @@ -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 diff --git a/avr/libraries/ADCTouch/library.properties b/avr/libraries/ADCTouch/library.properties new file mode 100755 index 00000000..d1570b1c --- /dev/null +++ b/avr/libraries/ADCTouch/library.properties @@ -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 diff --git a/avr/libraries/ADCTouch/src/ADCTouch.cpp b/avr/libraries/ADCTouch/src/ADCTouch.cpp new file mode 100755 index 00000000..4ae246f9 --- /dev/null +++ b/avr/libraries/ADCTouch/src/ADCTouch.cpp @@ -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; +} diff --git a/avr/libraries/ADCTouch/src/ADCTouch.h b/avr/libraries/ADCTouch/src/ADCTouch.h new file mode 100755 index 00000000..05a3b665 --- /dev/null +++ b/avr/libraries/ADCTouch/src/ADCTouch.h @@ -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 diff --git a/avr/libraries/TinyWire/src/TinyWire.cpp b/avr/libraries/TinyWire/src/TinyWire.cpp index 421de1e2..511128f6 100644 --- a/avr/libraries/TinyWire/src/TinyWire.cpp +++ b/avr/libraries/TinyWire/src/TinyWire.cpp @@ -1,7 +1,5 @@ #include "TinyWire.h" -// Predefined object -TinyWire Wire; /** * @brief Construct a new TinyWire object diff --git a/avr/libraries/TinyWire/src/TinyWire.h b/avr/libraries/TinyWire/src/TinyWire.h index 63e264d7..c755ee33 100644 --- a/avr/libraries/TinyWire/src/TinyWire.h +++ b/avr/libraries/TinyWire/src/TinyWire.h @@ -50,6 +50,6 @@ class TinyWire static uint16_t read_bytes; }; -extern TinyWire Wire; +static TinyWire Wire; #endif