3-button capacitive touch combination lock with CAP1188 or AT24QT1070

Hello all,

I have been in a rut the past couple of days on this project.

PROJECT GOAL:
Create a 3-button capacitive touch combination lock with CAP1188 or AT24QT1070

WHY:
I am creating a puzzle for an escape room where a user would have to touch 3 metal vases in the correct order to disable a magnetic lock.

I can get the touch to register in the serial monitor however how would I go about registering that as a key press?

This is the code I would like to use for the combination lock

/***************************************************
This is a library for the CAP1188 I2C/SPI 8-chan Capacitive Sensor

Designed specifically to work with the CAP1188 sensor from Adafruit
----> https://www.adafruit.com/products/1602

These sensors use I2C/SPI to communicate, 2+ pins are required to 
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada for Adafruit Industries. 
BSD license, all text above must be included in any redistribution
****************************************************/

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_CAP1188.h>

// Reset Pin is used for I2C or SPI
#define CAP1188_RESET  4

// CS pin is used for software or hardware SPI
//#define CAP1188_CS  10

// These are defined for software SPI, for hardware SPI, check your
// board's SPI pins in the Arduino documentation
//#define CAP1188_MOSI  11
//#define CAP1188_MISO  12
//#define CAP1188_CLK  13

volatile byte interrupt = 0;

// For I2C, connect SDA to your Arduino's SDA pin, SCL to SCL pin
// On UNO/Duemilanove/etc, SDA == Analog 4, SCL == Analog 5
// On Leonardo/Micro, SDA == Digital 2, SCL == Digital 3
// On Mega/ADK/Due, SDA == Digital 20, SCL == Digital 21

// Use I2C, no reset pin!
Adafruit_CAP1188 cap = Adafruit_CAP1188();

// Or...Use I2C, with reset pin
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_RESET);

// Or... Hardware SPI, CS pin & reset pin
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_CS, CAP1188_RESET);

// Or.. Software SPI: clock, miso, mosi, cs, reset
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_CLK, CAP1188_MISO, CAP1188_MOSI, CAP1188_CS, CAP1188_RESET);

void setup() {
Serial.begin(9600);
Serial.println("CAP1188 test!");
pinMode(3,INPUT);
// Raise SPI slave select (SS) pins
// Communication begins when you drop the individual select signals to LOW
digitalWrite(10,HIGH);


// Initialize the sensor, if using i2c you can pass in the i2c address
// if (!cap.begin(0x28)) {
if (!cap.begin()) {
  Serial.println("CAP1188 not found");
  while (1);
}
Serial.println("CAP1188 found!");
pinMode(3, INPUT);
// Turn off multitouch so only one button pressed at a time
cap.writeRegister(0x2A, 0x80);  // 0x2A default 0x80 use 0x41  — Set multiple touches back to off
cap.writeRegister(0x41, 0x39);  // 0x41 default 0x39 use 0x41  — Set "speed up" setting back to off
cap.writeRegister(0x72, 0x00);  // 0x72 default 0x00  — Sets LED links back to off (default)
cap.writeRegister(0x44, 0x41);  // 0x44 default 0x40 use 0x41  — Set interrupt on press but not release
cap.writeRegister(0x28, 0x00);  // 0x28 default 0xFF use 0x00  — Turn off interrupt repeat on button hold
EIFR = 1; // clear flag for interrupt 1
attachInterrupt(1, routine_Interrupt_CAP1188, FALLING);
}

void loop() {

// Serial.println(digitalRead(3));
uint8_t touched = cap.touched();

if (touched == 0) {
  // No touch detected
  // return;
}

for (uint8_t i=0; i<8; i++) {
  if (touched & (1 << i)) {
    Serial.print("C"); Serial.print(i+1); Serial.print("\t");Serial.println();
  }
}

delay(50);
//Serial.print("Interrupt: ");  Serial.println(interrupt);
}

void routine_Interrupt_CAP1188()  {
++interrupt;
}

Any ideas or help would be greatly appreciated. Thanks

I can get the serial monitor to detect a touch but cannot get it to register as a key press.

Can you explain a bit more what you mean by this.
It seems to me that if you can detect a touch then there is nothing stopping you registering it as a key press.

Grumpy_Mike:
Can you explain a bit more what you mean by this.
It seems to me that if you can detect a touch then there is nothing stopping you registering it as a key press.

I agree. I am still an noob at this and it would register as 10 key presses or so. I tried an interrupt and debounce with then it messed up the combination lock code...

I tried an interrupt and debounce

It is a capacitance sensor, it can not suffer from bouncing.

t would register as 10 key presses or so

It sounds like you only detect when it is touched not when it becomes touched.
You have to keep a track of the last value you read and only take action when you read it and it reports as touched and the last time it was read it was reported as not touched.

Grumpy_Mike:
It is a capacitance sensor, it can not suffer from bouncing.
It sounds like you only detect when it is touched not when it becomes touched.
You have to keep a track of the last value you read and only take action when you read it and it reports as touched and the last time it was read it was reported as not touched.

Okay Ive updated my code above and it now detect one input at a time and as one press. However still can figure out how to integrate that into the combination lock code. I am not ask for anyone to write this code, just some guidance. Thanks for the reply!

I am not ask for anyone to write this code, just some guidance.

OK getting two codes to run is covered here:-
http://www.thebox.myzen.co.uk/Tutorial/Merging_Code.html

What you need to do is to use the variables generated in the key sensing code to control the combination code.
If a variable is declared outside of a function then it is global and can be accessed by all functions.

wow, finally got this to work!

this is the code I ended up with for anyone finding this post.

/***************************************************
  This is a library for the CAP1188 I2C/SPI 8-chan Capacitive Sensor

  Designed specifically to work with the CAP1188 sensor from Adafruit
  ----> https://www.adafruit.com/products/1602

  These sensors use I2C/SPI to communicate, 2+ pins are required to
  interface

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_CAP1188.h>
const int buttonPin1 = 7;          // pin that the TOUCH SENSOR is attached to
const int buttonPin2 = 6;          // pin that the TOUCH SENSOR is attached to
const int buttonPin3 = 5;          // pin that the TOUCH SENSOR is attached to
const int correctLedPin = 2;       // pin that the LED is attached to
const int wrongLedPin = 4;         // pin that the LED is attached to
const int grantedLedPin = 8;       // pin that the RELAY is attached to

// Reset Pin is used for I2C or SPI
#define CAP1188_RESET  4

// CS pin is used for software or hardware SPI
#define CAP1188_CS  10

// These are defined for software SPI, for hardware SPI, check your
// board's SPI pins in the Arduino documentation
#define CAP1188_MOSI  11
#define CAP1188_MISO  12
#define CAP1188_CLK  13

volatile byte interrupt = 0;

// For I2C, connect SDA to your Arduino's SDA pin, SCL to SCL pin
// On UNO/Duemilanove/etc, SDA == Analog 4, SCL == Analog 5
// On Leonardo/Micro, SDA == Digital 2, SCL == Digital 3
// On Mega/ADK/Due, SDA == Digital 20, SCL == Digital 21

// Use I2C, no reset pin!
// Adafruit_CAP1188 cap = Adafruit_CAP1188();

// Or...Use I2C, with reset pin
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_RESET);

// Or... Hardware SPI, CS pin & reset pin
Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_CS, CAP1188_RESET);

// Or.. Software SPI: clock, miso, mosi, cs, reset
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_CLK, CAP1188_MISO, CAP1188_MOSI, CAP1188_CS, CAP1188_RESET);

// variables that are changed by the program
int buttonPushCounter = 0;    // counter for the number of button presses
int val = 0;

int bS1 = 0;   // current state of the button
int lBS1 = 0;  // previous state of the button

int bS2 = 0;  // current state of the button
int lBS2 = 0; // previous state of the button

int bS3 = 0;  // current state of the button
int lBS3 = 0; // previous state of the button

//int bS4 = 0;  // current state of the button
//int lBS4 = 0; // previous state of the button

//int bS5 = 0;  // current state of the button
//int lBS5 = 0; // previous state of the button

void setup() {
  Serial.begin(9600);
  Serial.println("CAP1188 test!");
  pinMode(3, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(7, INPUT);
  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(8, OUTPUT);
  // Raise SPI slave select (SS) pins
  // Communication begins when you drop the individual select signals to LOW
  digitalWrite(10, HIGH);
  digitalWrite(buttonPin1, HIGH);
  digitalWrite(buttonPin2, HIGH);
  digitalWrite(buttonPin3, HIGH);

  // Initialize the sensor, if using i2c you can pass in the i2c address - NOT USING I2C
  // if (!cap.begin(0x28)) {
  if (!cap.begin()) {
    Serial.println("CAP1188 not found");
    while (1);
  }
  Serial.println("CAP1188 found!");
  pinMode(3, INPUT);
  // Turn off multitouch so only one button pressed at a time
  cap.writeRegister(0x2A, 0x80);  // 0x2A default 0x80 use 0x41  — Set multiple touches back to off
  cap.writeRegister(0x41, 0x39);  // 0x41 default 0x39 use 0x41  — Set "speed up" setting back to off
  //cap.writeRegister(0x72, 0x01);  // 0x72 default 0x00  — Sets LED links back to off (default)
  cap.writeRegister(0x44, 0x41);  // 0x44 default 0x40 use 0x41  — Set interrupt on press but not release
  cap.writeRegister(0x28, 0x00);  // 0x28 default 0xFF use 0x00  — Turn off interrupt repeat on button hold
  EIFR = 1; // clear flag for interrupt 1
  attachInterrupt(1, routine_Interrupt_CAP1188, FALLING);
  
  //Adjust sensitivity by changing 0x00 value after the "|" mark
  uint8_t reg = cap.readRegister( 0x1f ) & 0x0f;
  cap.writeRegister( 0x1f, reg | 0x60 ); // or whatever value you want
}

void loop() {
  // read the state of the button
  static int buttonPushCounter = 0;
  bS1 = digitalRead(buttonPin1);
  bS2 = digitalRead(buttonPin2);
  bS3 = digitalRead(buttonPin3);
  // Serial.println(digitalRead(3));
  uint8_t touched = cap.touched();

  if (touched == 0) {
    // No touch detected
    // return;
  }

  for (uint8_t i = 0; i < 8; i++) {
    if (touched & (1 << i)) {
      //  Serial.print("C"); Serial.print(i+1); Serial.println("\t");
    }
  }

  delay(50);
  ////////////////////////////////
  if (bS1 != lBS1) {
    // either the button was just pressed or just released
    if (bS1 == HIGH) {
      // it was just pressed
      buttonPushCounter = buttonPushCounter + 1;
      Serial.println(buttonPushCounter);
      digitalWrite(grantedLedPin, LOW);
      digitalWrite(correctLedPin, HIGH);
      delay(100);
      digitalWrite(correctLedPin, LOW);
      if (val == 0)
      {
        val = 1;
      }
    }
  }
  lBS1 = bS1;
  ////////////////////////////////
  if (bS2 != lBS2) {
    // either the button was just pressed or just released
    if (bS2 == HIGH) {
      // it was just pressed
      buttonPushCounter = buttonPushCounter + 1;
      Serial.println(buttonPushCounter);
      digitalWrite(grantedLedPin, LOW);
      digitalWrite(correctLedPin, HIGH);
      delay(100);
      digitalWrite(correctLedPin, LOW);
      if (val == 1)
      {
        val = 2;
      }
    }
  }
  lBS2 = bS2;
  ////////////////////////////////
  if (bS3 != lBS3) {
    // either the button was just pressed or just released
    if (bS3 == HIGH) {
      // it was just pressed
      buttonPushCounter = buttonPushCounter + 1;
      Serial.println(buttonPushCounter);
      digitalWrite(grantedLedPin, LOW);
      digitalWrite(correctLedPin, HIGH);
      delay(100);
      digitalWrite(correctLedPin, LOW);
      if (val == 2)
      {
        val = 3;
      }
    }
  }
  lBS3 = bS3;
  ////////////////////////////////
  if (val == 3 && buttonPushCounter == 3)
  {
    delay(100);
    digitalWrite(grantedLedPin, HIGH);
    digitalWrite(correctLedPin, HIGH);
    digitalWrite(wrongLedPin, HIGH);
    val = 0;
    buttonPushCounter = 0;
  }

  else if (val != 3 && buttonPushCounter == 3)
  {
    delay(100);
    digitalWrite(wrongLedPin, HIGH);
    delay(1500);
    digitalWrite(wrongLedPin, HIGH);
    digitalWrite(correctLedPin, HIGH);
    delay(50);
    digitalWrite(wrongLedPin, LOW);
    digitalWrite(correctLedPin, LOW);
    delay(50);
    digitalWrite(wrongLedPin, HIGH);
    digitalWrite(correctLedPin, HIGH);
    delay(50);
    digitalWrite(wrongLedPin, LOW);
    digitalWrite(correctLedPin, LOW);
    delay(50);
    digitalWrite(wrongLedPin, HIGH);
    digitalWrite(correctLedPin, HIGH);
    delay(50);
    digitalWrite(wrongLedPin, LOW);
    digitalWrite(correctLedPin, LOW);
    val = 0;
    buttonPushCounter = 0;
  }
}
void routine_Interrupt_CAP1188()  {
  ++interrupt;
}

Well done :slight_smile: