Can I delay just one direction of Pin State?

I'll try to summarize. I have a potentiometer in a foot controller for a guitar wah-wah pedal controller. I normally use a switch to change a GPIO on an XBee. That is then processed on the receiver. I can post that code too if it's a better to accomplish this need there. The receiver pulls a relay pin high for a momentary closure to activate a channel on an external piece of gear. The line passing then shows up on every transceiver in the mesh network.
I am replicating how the wired analog version of the pedal. When I press the pedal forward (toe down), I want the relay to actuate right away. I have all of this working thanks to old posts and tutorials by @UKHeliBob, @Robin2, @Grumpy_Mike GrumpyMike and others.
However, the analog pedal does NOT deactivate the channel quickly. When the pot reaches zero so to speak, it doesn't turn the pedal off until after maybe 500ms. This allows the wah pedal user to rock the pedal back and forth in it's full travel without turning the channel off until it's left in the heel or off position. My system right now turns off and then back on again pretty quickly at this off position which can cause the pedal to become out of sync with the external unit. I've tried different delta's and if I use an above/below threshold, it causes more problems. Please pardon the extra code commenting and so forth due to my experimenting.
Thanks for any creative ideas on how to delay the digitalWrite relayPin going LOW but not HIGH.
Z

/* TRANSMITTER*/

int potPin = A0;  //pot in
int thresh = 0;   // low value = heel position
int relayPin = 2;  //out to relay pin line state pass on XBee
int currVal = 0;    // pot values that do not get inverted or delayed or sent to serial = higher resolution
int prevVal = 0;
int potVal = 0;     //pot values for serial use > XBee
int potValPrev = 0;
int potDelay = 25;   // to alleviate serial buff overrun

bool setPinHigh = false;

unsigned long startTime = 0;    //if (CurrentMillis - StartMillis >= IntervalMillis) is true, you’re done turn it off
unsigned long onTime = 6;       // amount of time the pin is high and the relay contact is closed
unsigned long prevPotMillis = 0;           // will store last time pot read
unsigned long currSloLoMillis = millis();  // for pin hi / lo
unsigned long prevSloLoMillis = 0;
int loDelay = 500;

void setup()  {
  Serial.begin(38400);
  pinMode(relayPin, OUTPUT);
  pinMode(potPin, INPUT);
}
void loop()  {
  unsigned long currentMillis = millis();

  currVal = analogRead(potPin);


  // See if the condition is true to trigger the action is true
  if ((currVal > thresh && prevVal <= thresh) || (currVal <= thresh && prevVal > thresh)) {
    digitalWrite(relayPin, HIGH);
    setPinHigh = true;
    startTime = millis();
  }

  // Delay for length of physical momentary connection
  if (setPinHigh && millis() - startTime < onTime)
  {
    digitalWrite(relayPin, HIGH);
  }
  else  // (currSloLoMillis - prevSloLoMillis >= loDelay) ??
    //should this be an if statement?
  {
    digitalWrite(relayPin, LOW);   // should always be == to pedal off in heel position
    setPinHigh = false;
    prevSloLoMillis = currSloLoMillis;
  }
  prevVal = currVal;

  if (currentMillis - prevPotMillis >= potDelay) {

    //Read the analog value from pot and store it to "value" variable
    potVal = analogRead(potPin);
    //Map the analog value to pwm value
    potVal = map (potVal, 0, 1023, 255, 0);
    if (abs(potVal - potValPrev) > 2)
      if (potVal != potValPrev) {
        Serial.print('<');
        Serial.print(potVal);
        Serial.println('>');
        potValPrev = potVal;
        Serial.flush();
        //delay (25);   now millis
        prevPotMillis = currentMillis;
      }

  }
  delay (1);
}

so, you want a pedal with potentiometer acting like switch, when it goes down - potentiometer rotate to increase value and MCU should convert this in LOW immediately. when pedal is freed - it goes up, potentiometer rotate to decrease value and MCU waiting 0,5 second to set output to HIGH. right?

Hello zaemo
Take some time and describe the desired function of the sketch in simple words and this very simple.
Have a nice day and enjoy coding in C++.

1 Like

draw a timing-diagram.

horizontal axle: the time
verical axle: potentiometer-value and effect on or off

Be the change you want to see in the world
best regards Stefan

Thank you for looking.
So, right now the potentiometer is being read and values are being sent out the serial port for wireless transmission. I'm also taking the pot values to control when a relay is actuated.
When the values ascend from zero, there should be a HIGH signal sent. This is a quick momentary pulse. When the pot values decrease back down to zero, another momentary pulse and LOW state is made.
This works pretty well and fairly quickly. What I want is for the HIGH state to happen quickly as it does but when it goes back to LOW state, I want that to happen slowly. It should go slow enough that when the pot is quickly turned down to zero and back up again, there would NOT be a state change. If the pot was turned down to zero and left there it would go to LOW after a short delay.
Turn pot down and back up quickly = no state change.
Turn pot down and stay at zero for 500 ms = state change to LOW.
Turn pot up from zero = fast state change to HIGH
I wish I could post a video.....
Z

I see your code has a low baud rate serial that prints too often so you added a delay(1) to empty the print buffer.

So your code runs on average in less than 50 micros until it hits that delay that takes over 20x as long as the actual stuff that needs to run.

What you might try is not printing values faster than eyes can follow but rather only printing a line when the pedal changes up/down status. No continuous state reports.
And then get rid of that delay.

If you just had a box with a hole as wide as a nickel that could detect an object within 1/4", would that work? You could put a sprung pedal over the hole and it would detect when the pedal is down or not?

Under the hole to one side, an IR led points diagonally up and an IR detector on the other side points at where reflected UV from a shoe on the hole would come. There are industrial versions of this but the name, all I remember is the word detector is in it.

ah, I see. I take look. might be interesting.

I added the 1 ms delay to help with relay bouncing so to speak, to make the state changes more deliberate. I can remove it but that's not really what I need to tweak. I chose 38.4k because it's near the baud rate of MIDI. Higher baud rates become less stable with the wireless communication.

That 1ms every loop disposes of over 90% of your CPU cycles. Runs slow huh?

Relays should never be quickly cycled for long if ever. Can transistors, BJT or FET, or a solid state relay be used to drive the motor(s).

38.4k ... don't print so often != slow the whole thing down
Maybe look and ask around for faster cheap radio?

wait a second. do you mean?

This works pretty well and fairly quickly. What I want is for the LOW/HIGH/LOW pulse to happen at value rising quickly as it does but when value goes back down then LOW/HIGH/LOW pulse should delay,

if it is , then

/* TRANSMITTER*/

const byte potPin = A0;  //pot in
const byte relayPin = 2;  //out to relay pin line state pass on XBee
const int potDelay = 25;  // to alleviate serial buff overrun
const int thresh = 0;   // low value = heel position
#define loDelay  500UL
#define PinHighTime  6UL       // amount of time the pin is high and the relay contact is closed

void setup()  {
  Serial.begin(38400);
  pinMode(relayPin, OUTPUT);
  pinMode(potPin, INPUT);
}

void loop()  {
  static int rawVal = 0;    // pot values that do not get inverted or delayed or sent to serial = higher resolution
  static int prevRawVal = 0;
  static byte potVal = 0;     //pot values for serial use > XBee
  static byte potValPrev = 0;

  static  bool setPinHigh = false;

  static unsigned long startTimeImpulse = 0;    //if (millis() - startTimeImpulse >= IntervalMillis) is true, you’re done turn it off
  static unsigned long prevPotMillis = 0;           // will store last time pot read
  static unsigned long delayMillis = 0;

  rawVal = analogRead(potPin);

  // See if the condition is true to trigger the action is true
  if ((rawVal > thresh && prevRawVal <= thresh && startTimeImpulse != 0) || ( millis() - delayMillis >= loDelay)) {
    digitalWrite(relayPin, HIGH);
    setPinHigh = true;
    startTimeImpulse = millis();
    delayMillis = 0;
    prevRawVal = rawVal;
  }

  // Delay for length of physical momentary connection
  if (setPinHigh && (millis() - startTimeImpulse >= PinHighTime)) {
    digitalWrite(relayPin, LOW);
    setPinHigh = false;
    startTimeImpulse = 0;
  }

  if (rawVal <= thresh && prevRawVal > thresh && delayMillis != 0) delayMillis = millis();

  if (millis() - prevPotMillis >= potDelay) {
    rawVal = analogRead(potPin) >> 4;
    potVal = 255 - rawVal;
    if (abs(potVal - potValPrev) > 2) {
      Serial.print('<');
      Serial.print(potVal);
      Serial.println('>');
      potValPrev = potVal;
      Serial.flush();
      prevPotMillis = millis();
    }
  }
}
1 Like

If you want to delay the action when in the low position then when you detect that set a Boolean variable and make a note of the time.

Then implement a state machine that kicks in after an initial delay, and does the action slowly in the state machine, that is the state machine runs at a certain interval.

The state machine concludes when either the fading action is complete or a read of the analogue input of the foot peddle shows it has risen above the threshold you want to use to stop the action.

I have used a similar method to delay note off messages after the detection of a note off action to allow a note to sound for a bit longer than my physical controls would normally do. Like the physical removal of a touch sensor reading which should turn off the note, but is better if the note lasts a bit longer than the detected touch.

1 Like

Something Iike this?

Work the pot up and down to see the action.  Delay occurs when pot is at bottom.

1 Like

Very Close. The LED should be a momentary single blink. You could move the fader up and down just like the simulator, all the way up and down, but you wouldn't get another momentary until after the fader rests for the "preset" at 256 or (0 in my sketch). So this involves the state changes.

Hmmm. I'm not getting any momentary signals with this. The state is always on.

try this :

/* TRANSMITTER*/
const byte potPin = A0;  //pot in
const byte relayPin = 2;  //out to relay pin line state pass on XBee
const int potDelay = 25;  // to alleviate serial buff overrun
const int thresh = 1;   // low value = heel position
#define loDelay  500UL
#define PinHighTime  6UL       // amount of time the pin is high and the relay contact is closed

void setup()  {
  Serial.begin(38400);
  pinMode(relayPin, OUTPUT);
  pinMode(potPin, INPUT);
}

void loop()  {
  static int rawVal = 0;    // pot values that do not get inverted or delayed or sent to serial = higher resolution
  static int prevRawVal = 0;
  static byte potVal = 0;     //pot values for serial use > XBee
  static byte potValPrev = 0;

  static  bool setPinHigh = false;

  static unsigned long startTimeImpulse = 0;    //if (millis() - startTimeImpulse >= IntervalMillis) is true, you’re done turn it off
  static unsigned long prevPotMillis = 0;           // will store last time pot read
  static unsigned long delayMillis = 0;

  rawVal = analogRead(potPin);

  // See if the condition is true to trigger the action is true
  if ((rawVal > thresh && prevRawVal < thresh && startTimeImpulse != 0) || ( millis() - delayMillis >= loDelay)) {
    digitalWrite(relayPin, HIGH);
    setPinHigh = !setPinHigh;
    startTimeImpulse = millis();
    delayMillis = 0;
    prevRawVal = rawVal;
  }

  // Delay for length of physical momentary connection
  if ( (millis() - startTimeImpulse >= PinHighTime)) {
    digitalWrite(relayPin, LOW);
    startTimeImpulse = 0;
  }

  if (rawVal <= thresh && prevRawVal > thresh && delayMillis != 0) {
    delayMillis = millis();
  }

  if (millis() - prevPotMillis >= potDelay) {
    rawVal = analogRead(potPin) >> 4;
    potVal = 255 - rawVal;
    if (abs(potVal - potValPrev) > 2) {
      Serial.print('<');
      Serial.print(potVal);
      Serial.println('>');
      potValPrev = potVal;
      prevPotMillis = millis();
    }
  }
}

I#m not sure to which code your post refers to.
The post that links to the WOKWI-simulation works as expected if you use a different browser than firefox. It is a known problem that firefox is unable to deal with slider-potentiometers in the WOKWI-simulator.
So as an example for the windows 10 chrome-browser the WOKWI-simulation works exactly as you described it:

When ever th slider is above threshold value (which means pushed upwoards) the LED is on
If you pull the slider down below the threshold or completely down it takes 1 second until the LED is switched off.

You could change the timeperiod for the delayed switch off of the LED with changing the value of

unsigned long preset=1000;

Be the change you want to see in the world
best regards Stefan

Hi Stefan, thank you. I was referring to kolaha's code. I can get the simulator to work on my browser. The slider exhibits the behavior I need as far as the delay goes however it is controlling a momentary relay.

So, when I run the code on my hardware, the pot movement up would connect the relay contacts all the way through the range of motion and then disconnect the contacts when it returns to zero and waits for the delay. This is only half the cycle. One ON/OFF series constitutes one momentary signal. I need one momentary signal to turn the equipment on, and one momentary signal to turn it off.

So, if I moved the fader up in the simulator and the LED blinked one time then blinked again when the delayed off position happened, that would be a full ON/OFF cycle.
SLIDER UP from zero = one blink (Hi-Lo Momentary) Equipment is active.
SLIDER moves 0-255 repeatedly (readings for serial use are later in the code)
SLIDER returns to ZERO and fires another momentary blink to turn the equipment off.

First Video is of the Analog pedal that I am trying to emulate. The yellow light I'm pointing at shows the channel engaging when lit.

Analog Pedal

Here is my wireless pedal. You can see how it engages and disengages too often at the heel position which is why I'm trying to delay this function. The quick disengage/engage is very annoying from the audio standpoint.

RF Pedal

There's an error shown in the compiler with potDelay.

repaired. UPD and again.