3

I'm having some trouble wrapping my head around timers in Arduino. I've got a FSR Pressure Sensor and I want it to turn on my NeoPixel LED after pressing on it for 5 seconds. Any help is much appreciated!

My goal: FSRReading > 1022 then wait 5 seconds, turn on NeoPixel FSRReading < 1022, then reset timer, turn off NeoPixel

This is what I currently have for my code, I can detect and act on sensor readings, but no timer:

#include <Adafruit_NeoPixel.h>
#define PIN 6
#define NUMPIXELS 16
#include "Timer.h"


Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int fsrPin = 9; // FSR is connected to analog 0
int fsrReading; // the analog reading from the FSR resistor divider int LEDbrightness;
int LEDbrightness;
Timer t;


void setup(void) {
 Serial.begin(9600);
 pixels.begin();
}

void loop(void) {
fsrReading = analogRead(fsrPin); 
Serial.println(fsrReading);
Serial.print("Analog reading = "); 

// we'll need to change the range from the analog reading (0-1023) down to the range // used by analogWrite (0-255) with map!
LEDbrightness = map(fsrReading, 0, 1023, 0, 255);

if (fsrReading < 10) {
Serial.println(" - No pressure"); } else if (fsrReading < 200) {
Serial.println(" - Light touch"); } else if (fsrReading < 500) {
Serial.println(" - Light squeeze"); } else if (fsrReading < 800) {
Serial.println(" - Medium squeeze"); } else {
Serial.println(" - Big squeeze"); }
delay(50);

for(int i=0;i<NUMPIXELS;i++){

  // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
  if (fsrReading>1022){
  pixels.setPixelColor(i, pixels.Color(0,255,0)); 
  } else if (fsrReading<1022) {
  pixels.setPixelColor(i, pixels.Color(0,0,0));
  }

  pixels.show(); // This sends the updated pixel color to the hardware.
 }
 }

2 Answers 2

3

The basic concept for tracking timing in the loop() is as follows:

1) when your event occurs, you store the current time in a variable:

unsigned long lastReading = 0;
uint8_t waiting = false;

if ( !waiting && fsrReading > 1022 ) {
  lastReading = millis();
  waiting = true;
}

2) you compare the lastReading variable against the current time and when enough time has passed, you can perform you timed action. ie:

int timeToWait = 5000; // 5 seconds

// are we waiting? and has enough time passed?
if ( waiting && millis() - lastReading > timeToWait ) {
   waiting = false; // reset

   // Light up lights
   ...
}

Note: this specific implementation only requires the sensor to rise above 1022 once, then wait 5 seconds before executing the timed action. If you want the sensor reading to be maintained above 1022 for the entire duration then you would add a check for a release with something like:

if ( fsrReading < 1022 ) {
  waiting = false; // reset because reading fell below 1022
}
5
  • hey thanks for your answer! could you explain a bit more about the purpose of the lastReading boolean? In what case would it become true? or is it suppose to stay false?
    – jmswng
    Apr 1, 2017 at 23:16
  • Error in the above: long lastReading should be unsigned long lastReading. Also, 0 is an ok value for millis() so lastReading should not be used as a flag as well as a value. Apr 1, 2017 at 23:44
  • @jwpat7. Right updated. And yes, 0 is a valid value for millis(), so if this sketch is expected to run ~50 days or more then a separate flag would be a good idea.
    – Mazaryk
    Apr 2, 2017 at 1:56
  • @jmswng lastReading is used to store the time of the last sensor reading. It is set to false to indicate we are not counting. When we are counting, it's value is the time when counting started. This 'trick' takes advantage of the fact that any non-zero number evaluates to true. However, jwpat7 pointed out that doing it this way could introduce unintended side effects. I'll update the code to use a dedicated flag. That should make it more clear.
    – Mazaryk
    Apr 2, 2017 at 2:04
  • @Mazaryk, ok, +1 Apr 2, 2017 at 2:45
1

My goal: FSRReading > 1022 then wait 5 seconds, turn on NeoPixel FSRReading < 1022, then reset timer, turn off NeoPixel

something like this will do.

  static uint32_t pressed_time; //last time the pressure sensor is pressed
  static uint8_t pressed_state=0; //the previous state. '1'->pressed, '0'->not pressed

  if (pressed()) {
    if (!pressed_state)) { //first time the pressure sensor is pressed
      pressed_state = 1;  //pressure sensor has been pressed
      pressed_time = millis(); //take time now
    } 
  } else {                //no longer pressed
    pressed_state = 0;  //reset pressed state
    turnOffled();       //turn the led off
  }

  if ((millis() > pressed_time + LED_DLY) && pressed_state) turnOnled();

untested code, use at your own risk

edit:

the above code in action, with a minor modification to return the desired led state (active high):

    //turn on / off the led pins
    if (led_ctrl()) digitalWrite(LED_PIN, HIGH);    //turn on the led, active high
    else digitalWrite(LED_PIN, LOW);        //turn off the led
}

enter image description here

Note: 1. pressed() is active low; 2. the led is programmed to turn on 100ms after the button goes low.

hope it helps.

2
  • You should edit this to clarify relation of fsrReading to pressed() Apr 1, 2017 at 23:47
  • Thanks for the answer, but what's 'LED_DLY'?
    – jmswng
    Apr 2, 2017 at 0:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.