IO_touch: every IO pin itself is a capacitive sensor
Without any external components or capacitive sensor periperal, any IO pin can serve as a capacitive sensor and you can use it for touch pad or so. :)
The touch pad that conencts with an analog pin forms a capacitor, and the anlog pin outputs a very short pulse to charge the capacitor. Then the pin turns to analog input, which has big input resistance, and the capacitor discharges slowly through this big resistance. When your finger touches the pads, the capacitance will change which cause a change in the discharging process (discharge slower).
By taking a measurement at a fixed time point after the pulse, we can detect the change in dicharge and ditect touch.
Here is the Arduino code for analog pins:
#include <Adafruit_NeoPixel.h> int Power = 11; int PIN = 12; #define NUMPIXELS 1 #define CALI_CNT 30 #define LED_PIN 25 #define THRESHOLD 100 Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); enum RGB_color { CLEAR, R, G, B }; RGB_color flash_r = CLEAR; RGB_color flash_g = CLEAR; RGB_color flash_b = CLEAR; int cali_1 = 0; int cali_2 = 0; int cali_3 = 0; int calibration(int pin) { int sum = 0; for (int i = 0; i < CALI_CNT; i++) { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); // turn the LED on (HIGH is the voltage level) delayMicroseconds(10); // wait for a second pinMode(pin, INPUT); delayMicroseconds(100); sum += analogRead(pin); delay(50); // wait for a second } return (sum/CALI_CNT); } void flash_RGB(RGB_color color) { switch (color) { case R: pixels.setPixelColor(0, pixels.Color(220, 0, 0)); pixels.show(); break; case G: pixels.setPixelColor(0, pixels.Color(0, 220, 0)); pixels.show(); break; case B: pixels.setPixelColor(0, pixels.Color(0, 0, 220)); pixels.show(); break; default: pixels.clear(); pixels.show(); break; } } RGB_color sense_touch(int pin, int cali, RGB_color color) { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); delayMicroseconds(10); pinMode(pin, INPUT); delayMicroseconds(100); if (abs(analogRead(pin) - cali) > THRESHOLD) { return color; } else { return CLEAR; } delay(50); } void setup() { pixels.begin(); pinMode(Power,OUTPUT); digitalWrite(Power, HIGH); pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); cali_1 = calibration(D0); cali_2 = calibration(D1); cali_3 = calibration(D2); digitalWrite(LED_PIN, HIGH); } void loop() { flash_r = CLEAR; flash_g = CLEAR; flash_b = CLEAR; RGB_color c1 = R; RGB_color c2 = G; RGB_color c3 = B; flash_r = sense_touch(D0, cali_1, c1); flash_RGB(flash_r); flash_g = sense_touch(D1, cali_2, c2); flash_RGB(flash_g); flash_b = sense_touch(D2, cali_3, c3); flash_RGB(flash_b); }
The mechanism for digital pins is similar. When touching the pad, capacitance changes and discharging process changes. However, digital pins are not connected with the internal ADC therefore can not measure this change through sampling the voltage at a fixed moment.
Note: the discharging time for digital pins are shorter since by default, if an RP2040 IO is configured to input, the pull down resistor is enabled, and this pull down resistor must be smaller than the input resistance of the internal ADC. So the capacitor discharges much faster.
The approach I'm using for digital pins is: when touching the pad, the discharge gets slower, therefore the falling edge arrives later. So I record the timestamp when the pulse outputs, and set the digital IO to input and attach to an interruption with it which is triggered by falling edge. The interruption routine record the timestamp and calculate the time difference between the trigger time and pulse output time. The time difference with a finger touch is longer than the one without (although it's only a few microseconds, but already enough to capture).
Here are the final source code with both analog and digital pins work:
main.cXIAO2PICO_PIN_MAP.h
platformio.ini
Note: I use VSCode + PlatformIO.
With this approach, theoretically, any IO pin of almost all MCUs could serve as a capacitive sensor. I'm pretty sure there are some imperfections in the code and the performance can be much better with further development, but the concept is shown here.