Touch sensors and Fading LEDs

Hi,

Total newbie here.

I've spent the last week programming a Mega 2560 with an MPR121 and 12 electrodes that trigger audio samples in PureData.

Now, I would like the sensors to turn on an LED that will stay on for the length of the clip and fade out.

So far I have managed to have the LED on pin13 turn on and stay of for a set duration, then fade, but this stalls the void loop and no electrode touch sensing is possible until the fade has finished and the loop begins again. So i adapted the code so the touch state (and serial.Write) is inside the LED for() loop.

This is my current code:

#include "mpr121.h"
#include <Wire.h>

int irqpin = 2; // Digital 2
int led1Pin = 13;
int led2Pin = 12;
boolean touchStates[12]; //to keep track of the previous touch states

void setup(){
  pinMode(irqpin, INPUT);
  pinMode(led1Pin, OUTPUT);
  digitalWrite(irqpin, HIGH); //enable pullup resistor
  
  Serial.begin(9600);
  Wire.begin();

  mpr121_setup();
}

void loop(){
  
  Wire.requestFrom(0x5A,2); 
    
    byte LSB = Wire.read();
    byte MSB = Wire.read();
  
  uint16_t touched = ((MSB << 8) | LSB);
  
  for (int i=0; i < 12; i++){  // Check what electrodes were pressed
      if(touched & (1<<i)){
    if(touchStates[i] == 0){
      
         analogWrite(led1Pin, 255);
    }  

    for (int x = 255; x > 0; x--) {  
             delay(5) ;
             analogWrite(led1Pin, (x)); 
    
         if ((x) == 1){
           analogWrite(led1Pin, 0);  
           
              if(touchStates[i] == 0){
          //pin i was just touched
          Serial.write(i + 1);
          Serial.write((byte)0x00);
              }
         }
         
    }
       }
  }
  readTouchInputs();
         
}


void readTouchInputs(){
  if(!checkInterrupt()){
    
    //read the touch state from the MPR121
    Wire.requestFrom(0x5A,2); 
    
    byte LSB = Wire.read();
    byte MSB = Wire.read();
    
    uint16_t touched = ((MSB << 8) | LSB); //16bits that make up the touch states

    
    for (int i=0; i < 12; i++){  // Check what electrodes were pressed
      if(touched & (1<<i)){
      
        if(touchStates[i] == 0){
          //pin i was just touched
          Serial.write(i + 1);
          Serial.write((byte)0x00);
          

       }
        
        touchStates[i] = 0;
      }
    
    }
    
  }
}




void mpr121_setup(void){

  set_register(0x5A, ELE_CFG, 0x00); 
  
  // Section A - Controls filtering when data is > baseline.
  set_register(0x5A, MHD_R, 0x01);
  set_register(0x5A, NHD_R, 0x01);
  set_register(0x5A, NCL_R, 0x00);
  set_register(0x5A, FDL_R, 0x00);

  // Section B - Controls filtering when data is < baseline.
  set_register(0x5A, MHD_F, 0x01);
  set_register(0x5A, NHD_F, 0x01);
  set_register(0x5A, NCL_F, 0xFF);
  set_register(0x5A, FDL_F, 0x02);
  
  // Section C - Sets touch and release thresholds for each electrode
  set_register(0x5A, ELE0_T, TOU_THRESH);
  set_register(0x5A, ELE0_R, REL_THRESH);
 
  set_register(0x5A, ELE1_T, TOU_THRESH);
  set_register(0x5A, ELE1_R, REL_THRESH);
  
  set_register(0x5A, ELE2_T, TOU_THRESH);
  set_register(0x5A, ELE2_R, REL_THRESH);
  
  set_register(0x5A, ELE3_T, TOU_THRESH);
  set_register(0x5A, ELE3_R, REL_THRESH);
  
  set_register(0x5A, ELE4_T, TOU_THRESH);
  set_register(0x5A, ELE4_R, REL_THRESH);
  
  set_register(0x5A, ELE5_T, TOU_THRESH);
  set_register(0x5A, ELE5_R, REL_THRESH);
  
  set_register(0x5A, ELE6_T, TOU_THRESH);
  set_register(0x5A, ELE6_R, REL_THRESH);
  
  set_register(0x5A, ELE7_T, TOU_THRESH);
  set_register(0x5A, ELE7_R, REL_THRESH);
  
  set_register(0x5A, ELE8_T, TOU_THRESH);
  set_register(0x5A, ELE8_R, REL_THRESH);
  
  set_register(0x5A, ELE9_T, TOU_THRESH);
  set_register(0x5A, ELE9_R, REL_THRESH);
  
  set_register(0x5A, ELE10_T, TOU_THRESH);
  set_register(0x5A, ELE10_R, REL_THRESH);
  
  set_register(0x5A, ELE11_T, TOU_THRESH);
  set_register(0x5A, ELE11_R, REL_THRESH);
  
  // Section D
  // Set the Filter Configuration
  // Set ESI2
  set_register(0x5A, FIL_CFG, 0x04);
  
  // Section E
  // Electrode Configuration
  // Set ELE_CFG to 0x00 to return to standby mode
  set_register(0x5A, ELE_CFG, 0x0C);  // Enables all 12 Electrodes
  
  
  // Section F
  // Enable Auto Config and auto Reconfig
  /*set_register(0x5A, ATO_CFG0, 0x0B);
  set_register(0x5A, ATO_CFGU, 0xC9);  // USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V   set_register(0x5A, ATO_CFGL, 0x82);  // LSL = 0.65*USL = 0x82 @3.3V
  set_register(0x5A, ATO_CFGT, 0xB5);*/  // Target = 0.9*USL = 0xB5 @3.3V
  
  set_register(0x5A, ELE_CFG, 0x0C);
  
}


boolean checkInterrupt(void){
  return digitalRead(irqpin);
}


void set_register(int address, unsigned char r, unsigned char v){
    Wire.beginTransmission(address);
    Wire.write(r);
    Wire.write(v);
    Wire.endTransmission();
}

This is working, but i cannot seem to designate an electrode to just one LED.

PS. I know my code is kludgey as all hell, sorry.

There is a sample code included in arduino IDE, called blink without delay. It tells you how to do two things together. Basic concept is to set LED, do other stuff, see if it is time to set LED to a different brightness or not.

Thanks for the reply, but I don't understand how to integrate the nodelay code into mine. since each of the LED will need to stay of for a pre-designated amount of time before fading, also, the blink function is digital (high/low) whereas I need to use PWM to fade the LEDs

Say the LED has the following states: off, fading_in, fading_out.

#define led_off 1
#define fading_in 2
#define fading_out 3
#define update_period 20
#define LEDpin 13

byte status=fading_in;
byte fade=0;
unsigned long last_millis=0;

void setup()
{
}

void loop()
{
//Do your stuff, including turning fading on by setting status to fading_in.
  switch (status)
  {
    case led_off:
    //do nothing
    break;
    case fading_in:
    if (millis()-last_millis>update_period)
    {
      fade+=1;
      analogWrite(LEDpin, fade);
      last_millis=millis();
    }
    if (fade==255) status=fading_out;
    break;
    case fading_out:
    if (millis()-last_millis>update_period)
    {
      fade-=1;
      analogWrite(LEDpin, fade);
      last_millis=millis();
    }
    if (fade==0)
    {
      status=led_off;
      analogWrite(LEDpin, fade);
    }
    break;
  }

}

Thanks, that helps a lot.
The only other thing I need to do is set it so the LED can't be triggered more than once in a set time period, and this time (~1500ms) will be different for each of the sensors/LEDs

Obviously, I can't use a delay function, because it delays the entire script and I can't trigger the other sensors.

Can you shed some light on my options?

EDIT: Also, would there be a way to stall at PWM=255 for a set time for each LED too?

#include "mpr121.h"
#include <Wire.h>

int irqpin = 22; // Digital 22
const int led1Pin = 2;
const int led2Pin = 3;
const int led3Pin = 4;
const int led4Pin = 5;
const int led5Pin = 6;
const int led6Pin = 7;
const int led7Pin = 8;
const int led8Pin = 9;
const int led9Pin = 10;
const int led10Pin = 11;
const int led11Pin = 12;
const int led12Pin = 13;
int led1State = 0;
int led2State = 0;
int led3State = 0;
int led4State = 0;
int led5State = 0;
int led6State = 0;
int led7State = 0;
int led8State = 0;
int led9State = 0;
int led10State = 0;
int led11State = 0;
int led12State = 0;

long previousMillis = 0;
long interval = 6;
boolean touchStates[12]; //to keep track of the previous touch states

void setup(){
  pinMode(irqpin, INPUT);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  digitalWrite(irqpin, HIGH); //enable pullup resistor
  
  Serial.begin(9600);
  Wire.begin();

  mpr121_setup();
}
void loop(){
  readTouchInputs();
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis; 
    
    if (led1State > 0)
      led1State -= 1;
    
    if (led2State > 0)
      led2State -= 1;
      
    if (led3State > 0)
      led3State -= 1;
    
    if (led4State > 0)
      led4State -= 1;
      
    if (led5State > 0)
      led5State -= 1;
    
    if (led6State > 0)
      led6State -= 1;
      
    if (led7State > 0)
      led7State -= 1;
    
    if (led8State > 0)
      led8State -= 1;
      
    if (led9State > 0)
      led9State -= 1;
    
    if (led10State > 0)
      led10State -= 1;
      
    if (led11State > 0)
      led11State -= 1;
    
    if (led12State > 0)
      led12State -= 1;
      
  }     

    // set the LED with the ledState of the variable:
    analogWrite(led1Pin, led1State);
    analogWrite(led2Pin, led2State);
    analogWrite(led3Pin, led3State);
    analogWrite(led4Pin, led4State);
    analogWrite(led5Pin, led5State);
    analogWrite(led6Pin, led6State);
    analogWrite(led7Pin, led7State);
    analogWrite(led8Pin, led8State);
    analogWrite(led9Pin, led9State);
    analogWrite(led10Pin, led10State);
    analogWrite(led11Pin, led11State);
    analogWrite(led12Pin, led12State);
 
}



void readTouchInputs(){
  if(!checkInterrupt()){
    
    //read the touch state from the MPR121
    Wire.requestFrom(0x5A,2); 
    
    byte LSB = Wire.read();
    byte MSB = Wire.read();
    
    uint16_t touched = ((MSB << 8) | LSB); //16bits that make up the touch states

    
    for (int i=0; i < 12; i++){  // Check what electrodes were pressed
      if(touched & (1<<i)){
      
        if(touchStates[i] == 0){
          //pin i was just touched
          Serial.write(i + 1);
          Serial.write((byte)0x00);
          
        }
          
          if(i == 0){
          led1State = 255;
          }

          if(i == 1){
          led2State = 255;      
          }
          if(i == 2){
          led3State = 255;
          }

          if(i == 3){
          led4State = 255;      
          }
          if(i == 4){
          led5State = 255;
          }

          if(i == 5){
          led6State = 255;      
          }
          if(i == 6){
          led7State = 255;
          }

          if(i == 7){
          led8State = 255;      
          }
          if(i == 8){
          led9State = 255;
          }

          if(i == 9){
          led10State = 255;      
          }
          if(i == 10){
          led11State = 255;
          }

          if(i == 11){
          led12State = 255;      
          }
          
        
        touchStates[i] = 0;
      }
    
    }
    
  }
}




void mpr121_setup(void){

  set_register(0x5A, ELE_CFG, 0x00); 
  
  // Section A - Controls filtering when data is > baseline.
  set_register(0x5A, MHD_R, 0x01);
  set_register(0x5A, NHD_R, 0x01);
  set_register(0x5A, NCL_R, 0x00);
  set_register(0x5A, FDL_R, 0x00);

  // Section B - Controls filtering when data is < baseline.
  set_register(0x5A, MHD_F, 0x01);
  set_register(0x5A, NHD_F, 0x01);
  set_register(0x5A, NCL_F, 0xFF);
  set_register(0x5A, FDL_F, 0x02);
  
  // Section C - Sets touch and release thresholds for each electrode
  set_register(0x5A, ELE0_T, TOU_THRESH);
  set_register(0x5A, ELE0_R, REL_THRESH);
 
  set_register(0x5A, ELE1_T, TOU_THRESH);
  set_register(0x5A, ELE1_R, REL_THRESH);
  
  set_register(0x5A, ELE2_T, TOU_THRESH);
  set_register(0x5A, ELE2_R, REL_THRESH);
  
  set_register(0x5A, ELE3_T, TOU_THRESH);
  set_register(0x5A, ELE3_R, REL_THRESH);
  
  set_register(0x5A, ELE4_T, TOU_THRESH);
  set_register(0x5A, ELE4_R, REL_THRESH);
  
  set_register(0x5A, ELE5_T, TOU_THRESH);
  set_register(0x5A, ELE5_R, REL_THRESH);
  
  set_register(0x5A, ELE6_T, TOU_THRESH);
  set_register(0x5A, ELE6_R, REL_THRESH);
  
  set_register(0x5A, ELE7_T, TOU_THRESH);
  set_register(0x5A, ELE7_R, REL_THRESH);
  
  set_register(0x5A, ELE8_T, TOU_THRESH);
  set_register(0x5A, ELE8_R, REL_THRESH);
  
  set_register(0x5A, ELE9_T, TOU_THRESH);
  set_register(0x5A, ELE9_R, REL_THRESH);
  
  set_register(0x5A, ELE10_T, TOU_THRESH);
  set_register(0x5A, ELE10_R, REL_THRESH);
  
  set_register(0x5A, ELE11_T, TOU_THRESH);
  set_register(0x5A, ELE11_R, REL_THRESH);
  
  // Section D
  // Set the Filter Configuration
  // Set ESI2
  set_register(0x5A, FIL_CFG, 0x04);
  
  // Section E
  // Electrode Configuration
  // Set ELE_CFG to 0x00 to return to standby mode
  set_register(0x5A, ELE_CFG, 0x0C);  // Enables all 12 Electrodes
  
  
  // Section F
  // Enable Auto Config and auto Reconfig
  /*set_register(0x5A, ATO_CFG0, 0x0B);
  set_register(0x5A, ATO_CFGU, 0xC9);  // USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V   set_register(0x5A, ATO_CFGL, 0x82);  // LSL = 0.65*USL = 0x82 @3.3V
  set_register(0x5A, ATO_CFGT, 0xB5);*/  // Target = 0.9*USL = 0xB5 @3.3V
  
  set_register(0x5A, ELE_CFG, 0x0C);
  
}


boolean checkInterrupt(void){
  return digitalRead(irqpin);
}


void set_register(int address, unsigned char r, unsigned char v){
    Wire.beginTransmission(address);
    Wire.write(r);
    Wire.write(v);
    Wire.endTransmission();
}

Draw a flow chart first. Everything seems easy once you have it.

ARgghhh... sorry for bumping my dead old thread, but After my last post I managed to make it all work... then the laptop I was working on was formatted without my knowledge...
I know, I should have had one million backups, but I didn't, The code I had pasted here was the most recent version.

Anyway, I can remember making a small change to the order of the loop and all was well.

Again, what i'm trying to do is make sure the sensor has been released and the LED has faded to 0 before it can be triggered again.

Can anyone help?

Maybe instead of this:

          if(i == 0){
          led1State = 255;
          }

          if(i == 1){
          led2State = 255;      
          }
...

try this:

          if(i == 0 && led1State == 0){
          led1State = 255;
          }

          if(i == 1 && led2State == 0){
          led2State = 255;      
          }
...

Thanks for the help.

I realise now that I didn't pose my problem properly.

Here's the flow

Sensor touched
|
Electrode number (+1) written to serial
LED Illuminated
|
PureData Receives Serial data and triggers audio file
LED Fade start
|
Audio Plays until file is complete
|
End LED Fade

at this point the sensor may be triggered again, but only if it has been released at any point while the audio was playing

I should also mention that up to 12 sensors can be triggered at any time, so I can't use any sort of delay.

Current code:

#include "mpr121.h"
#include <Wire.h>

int irqpin = 22;  // Digital 22

const int led1Pin = 3;
const int led2Pin = 1;
const int led3Pin = 4;
const int led4Pin = 5;
const int led5Pin = 6;
const int led6Pin = 7;
const int led7Pin = 8;
const int led8Pin = 9;
const int led9Pin = 10;
const int led10Pin = 11;
const int led11Pin = 12;
const int led12Pin = 13;
int led1State = 0;
int led2State = 0;
int led3State = 0;
int led4State = 0;
int led5State = 0;
int led6State = 0;
int led7State = 0;
int led8State = 0;
int led9State = 0;
int led10State = 0;
int led11State = 0;
int led12State = 0;

long previousMillis = 0;
long interval = 2;

boolean touchStates[12]; //to keep track of the previous touch states

void setup(){
  pinMode(irqpin, INPUT);
  digitalWrite(irqpin, HIGH); //enable pullup resistor
  
  Serial.begin(9600);
  Wire.begin();

  mpr121_setup();
}

void loop(){
  
  readTouchInputs();
  unsigned long currentMillis = millis();

 
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis; 
    
    if (led1State > 0)
      led1State -= 1;
    
    if (led2State > 0)
      led2State -= 1;
      
    if (led3State > 0)
      led3State -= 1;
    
    if (led4State > 0)
      led4State -= 1;
      
    if (led5State > 0)
      led5State -= 1;
    
    if (led6State > 0)
      led6State -= 1;
      
    if (led7State > 0)
      led7State -= 1;
    
    if (led8State > 0)
      led8State -= 1;
      
    if (led9State > 0)
      led9State -= 1;
    
    if (led10State > 0)
      led10State -= 1;
      
    if (led11State > 0)
      led11State -= 1;
    
    if (led12State > 0)
      led12State -= 1;
      
  }

    // set the LED with the ledState of the variable:
    analogWrite(led1Pin, led1State);
    analogWrite(led2Pin, led2State);
    analogWrite(led3Pin, led3State);
    analogWrite(led4Pin, led4State);
    analogWrite(led5Pin, led5State);
    analogWrite(led6Pin, led6State);
    analogWrite(led7Pin, led7State);
    analogWrite(led8Pin, led8State);
    analogWrite(led9Pin, led9State);
    analogWrite(led10Pin, led10State);
    analogWrite(led11Pin, led11State);
    analogWrite(led12Pin, led12State);

}

  void readTouchInputs(){
  if(!checkInterrupt()){
    
    //read the touch state from the MPR121
    Wire.requestFrom(0x5A,2); 
    
    byte LSB = Wire.read();
    byte MSB = Wire.read();
    
    uint16_t touched = ((MSB << 8) | LSB); //16bits that make up the touch states

    
    for (int i=0; i < 12; i++){  // Check what electrodes were pressed
      if(touched & (1<<i)){
      
        if(touchStates[i] == 0){
          //pin i was just touched
          Serial.write(i + 1);
          Serial.write((byte)0x00);
          
        }
          
          if(i == 0 && led1State == 0){
          led1State = 255;
          }

          if(i == 1 && led2State == 0){
          led2State = 255;
          }

          if(i == 2 && led3State == 0){
          led3State = 255;
          }

          if(i == 3 && led4State == 0){
          led4State = 255;
          }

          if(i == 4 && led5State == 0){
          led5State = 255;
          }

          if(i == 5 && led6State == 0){
          led6State = 255;
          }

          if(i == 6 && led7State == 0){
          led7State = 255;
          }

          if(i == 7 && led8State == 0){
          led8State = 255;
          }

          if(i == 8 && led9State == 0){
          led9State = 255;
          }

          if(i == 9 && led10State == 0){
          led10State = 255;
          }

          if(i == 10 && led11State == 0){
          led11State = 255;
          }

          if(i == 11 && led12State == 0){
          led12State = 255;
          }

          
        
        }else if(touchStates[i] == 1){
          //pin i is still being touched
        }
        
        touchStates[i] = 0;      
      
       } 
      }
    } 


void mpr121_setup(void){

  set_register(0x5A, ELE_CFG, 0x00); 
  
  // Section A - Controls filtering when data is > baseline.
  set_register(0x5A, MHD_R, 0x01);
  set_register(0x5A, NHD_R, 0x01);
  set_register(0x5A, NCL_R, 0x00);
  set_register(0x5A, FDL_R, 0x00);

  // Section B - Controls filtering when data is < baseline.
  set_register(0x5A, MHD_F, 0x01);
  set_register(0x5A, NHD_F, 0x01);
  set_register(0x5A, NCL_F, 0xFF);
  set_register(0x5A, FDL_F, 0x02);
  
  // Section C - Sets touch and release thresholds for each electrode
  set_register(0x5A, ELE0_T, TOU_THRESH);
  set_register(0x5A, ELE0_R, REL_THRESH);
 
  set_register(0x5A, ELE1_T, TOU_THRESH);
  set_register(0x5A, ELE1_R, REL_THRESH);
  
  set_register(0x5A, ELE2_T, TOU_THRESH);
  set_register(0x5A, ELE2_R, REL_THRESH);
  
  set_register(0x5A, ELE3_T, TOU_THRESH);
  set_register(0x5A, ELE3_R, REL_THRESH);
  
  set_register(0x5A, ELE4_T, TOU_THRESH);
  set_register(0x5A, ELE4_R, REL_THRESH);
  
  set_register(0x5A, ELE5_T, TOU_THRESH);
  set_register(0x5A, ELE5_R, REL_THRESH);
  
  set_register(0x5A, ELE6_T, TOU_THRESH);
  set_register(0x5A, ELE6_R, REL_THRESH);
  
  set_register(0x5A, ELE7_T, TOU_THRESH);
  set_register(0x5A, ELE7_R, REL_THRESH);
  
  set_register(0x5A, ELE8_T, TOU_THRESH);
  set_register(0x5A, ELE8_R, REL_THRESH);
  
  set_register(0x5A, ELE9_T, TOU_THRESH);
  set_register(0x5A, ELE9_R, REL_THRESH);
  
  set_register(0x5A, ELE10_T, TOU_THRESH);
  set_register(0x5A, ELE10_R, REL_THRESH);
  
  set_register(0x5A, ELE11_T, TOU_THRESH);
  set_register(0x5A, ELE11_R, REL_THRESH);
  
  // Section D
  // Set the Filter Configuration
  // Set ESI2
  set_register(0x5A, FIL_CFG, 0x04);
  
  // Section E
  // Electrode Configuration
  // Set ELE_CFG to 0x00 to return to standby mode
  set_register(0x5A, ELE_CFG, 0x0C);  // Enables all 12 Electrodes
  
  
  // Section F
  // Enable Auto Config and auto Reconfig
  /*set_register(0x5A, ATO_CFG0, 0x0B);
  set_register(0x5A, ATO_CFGU, 0xC9);  // USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V   set_register(0x5A, ATO_CFGL, 0x82);  // LSL = 0.65*USL = 0x82 @3.3V
  set_register(0x5A, ATO_CFGT, 0xB5);*/  // Target = 0.9*USL = 0xB5 @3.3V
  
  set_register(0x5A, ELE_CFG, 0x0C);
  
}


boolean checkInterrupt(void){
  return digitalRead(irqpin);
}


void set_register(int address, unsigned char r, unsigned char v){
    Wire.beginTransmission(address);
    Wire.write(r);
    Wire.write(v);
    Wire.endTransmission();
}

Possibly if you extend the if(touchStates[\i] == 0). That is the case where the sensor has been released, and is being triggered the first time. So extend the code that triggers the ledStates to be inside that if block.

    for (int i=0; i < 12; i++){  // Check what electrodes were pressed
      if(touched & (1<<i)){
        if(touchStates[i] == 0){
          //pin i was just touched
          touchStates[i] = 1;
          Serial.write(i + 1);
          Serial.write((byte)0x00);
          
          if(i == 0 && led1State == 0){
            led1State = 255;
          }
...
          if(i == 11 && led12State == 0){
            led12State = 255;
          }
        }
      }
      else
        touchStates[i] = 0;      
    }

Awesome! Works much better, Thanks.

Now all I need to learn is how to get pure data to send a bang over serial when the audio file finishes to make it the LED triggerable rather than it being a timing thing...

I really appreciate the help. Thanks again.