This project demonstrates a low-latency capacitive touch detection system using the Configurable Logic Block (CLB) and the Capacitive Voltage Divider (CVD) method on the PIC16F13145 microcontroller. The touch input is processed using hardware logic for ultra-fast and deterministic response, ideal for low-power and real-time embedded applications.
🔗 Key Features
- Capacitive touch detection using only 2 MSBs (ADC9, ADC8)
- Hardware-based noise filtering using majority vote
- Digital hysteresis logic for debouncing
- LED indicator mapped via CLB output
- CVD method for robust touch sensing
🔧 How It Works
CVD ADC Reading
The CVD method samples the capacitive pad via the ADC in a charge/discharge cycle
CLB Input
The 10-bit ADC result is sent to the CLB as a 10-bit bus. Only ADC9 and ADC8 are used to detect if the value is below 256 (touch condition).
CLB Pipeline
- Digital filtering: Applies a 3-sample majority filter on ADC9 and ADC8.
- Thresholding: Interprets ADC < 256 as touch and ADC > 512 as release.
- Hysteresis: Holds state to prevent flicker.
- Majority Vote Filter: Ensures consistent detection before triggering.
- Output Register: Drives GPIO-connected LED on touch detection.
💻 Software Structure
Main Application (CPU Code):
- Periodic ADC conversion triggered by a timer interrupt (every 100 ms)
- Result sent to CLB using CLB1_SWIN_Write16()
- UART prints ADC value for debugging
void ADC_Callback(void)
{
volatile adc_result_t adcVal = 0;
/* Read the result from the ADC */
adcVal = ADC_ConversionResultGet();
/* Send the ADC value to the CLB for further processing */
CLB1_SWIN_Write16(adcVal);
/* Print the ADC value over UART for debugging */
printf("ADC Value: %d \r\n", adcVal);
}
void Tmr_100ms_Callback(void)
{
/* Trigger new ADC conversion */
ADC_ConversionStart();
}
module CapTouch_Pipeline (
CLK, // CLB global clock
ADC9, ADC8, // Most significant ADC bits
TOUCH // Final touch detection output
);
input CLK;
input ADC9, ADC8;
output TOUCH;
// === Stage 1: Digital Filters on ADC Bits ===
reg [2:0] adc9_hist;
wire adc9_filtered;
always @(posedge CLK) begin
adc9_hist <= {adc9_hist[1:0], ADC9};
end
assign adc9_filtered = (adc9_hist[0] + adc9_hist[1] + adc9_hist[2]) >= 2;
reg [2:0] adc8_hist;
wire adc8_filtered;
always @(posedge CLK) begin
adc8_hist <= {adc8_hist[1:0], ADC8};
end
assign adc8_filtered = (adc8_hist[0] + adc8_hist[1] + adc8_hist[2]) >= 2;
// === Stage 2: Hysteresis Logic ===
reg touch_state;
always @(posedge CLK) begin
if (~adc9_filtered & ~adc8_filtered) // ADC < 256 → Touch
touch_state <= 1'b1;
else if (~adc9_filtered & adc8_filtered) // ADC ≥ 256 → No touch
touch_state <= 1'b0;
// Note: ADC9 == 1 (≥ 512) is already handled here
end
// === Stage 3: Majority Filter for Stability ===
reg [4:0] hist;
always @(posedge CLK) begin
hist <= {hist[3:0], touch_state};
end
wire [2:0] sum = hist[0] + hist[1] + hist[2] + hist[3] + hist[4];
wire majority = (sum >= 3);
// === Stage 4: Output Register ===
reg touch_out;
always @(posedge CLK) begin
touch_out <= majority;
end
assign TOUCH = touch_out;
endmodule
🚀 Why This Matters
This project shows how Microchip’s CLB can handle real-time touch processing tasks with minimal CPU usage, making it suitable for ultra-low-power and latency-sensitive applications like wearables, capacitive buttons, and industrial panels.