Help editing code for including speed detection

Hi.

I have a system here that I need to regulate gas flow.
I have a timer which can turn on and off. It sends as a pulsed signal where I have the Arduino control some solenoid valves.

I am hoping I can get some further assistance to configure some additional code, and a posted here in a new thread.

I am wanting to advance the circuit system to be able to:

Detect Input Signal. Pin2

Depend on how slow or quick the pulse goes, to be able to run 3(all) (TwoA, TwoB, TwoC) at the same time. Instead of the cyclic action.

The INPUT pulse rate can vary from (once every 2 seconds), up to 10 times per second.
When the Pulse is SLOW (like every 2 Seconds) I would like all Relays (TwoA, B & C) same time
When the Pulse is faster (every 1 second) to have cycle between TwoA,B then TwoB,C
When the Pulse is Fastest (faster than 1 second) Standard Cycle TwoA, then TwoB, then TwoC.

Thanks again so much for the support you guys have given.

Code as it stands Now..
Credit: Paulpaulson for making this code.

//BLOCK COMMENT
//https://forum.arduino.cc/t/cyclic-relay2a-2b/889080/10
#define ProjectName "Cyclic Relay2A & 2B"
// CONSTANT DEFINITION
// you need to change these constants to your hardware
const byte Relays[] {3, 7, 8, 4};
const byte Buttons[] {2};
// VARIABLE DECLARATION
enum {One, TwoA, TwoB, TwoC};
struct BUTTON {
  byte pin;
  bool state;
  int counter;
  unsigned long stamp;
  unsigned long duration;
} button {Buttons[One], 1, 0, 0, 20};
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);
  for (auto Relay : Relays) pinMode ( Relay, OUTPUT);
  for (auto Button : Buttons) pinMode ( Button, INPUT_PULLUP);
}
void loop () {
  unsigned long currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  if (currentTime - button.stamp >= button.duration) {
    button.stamp = currentTime;
    bool stateNew = digitalRead(button.pin);
    if (button.state != stateNew) {
      button.state = stateNew;
      for (auto Relay : Relays) digitalWrite ( Relay, LOW);
      switch (button.counter) {
        case 0: digitalWrite ( Relays[One] , HIGH); break;
        case 1: digitalWrite ( Relays[TwoA] , HIGH); break;
        case 2: digitalWrite ( Relays[One] , HIGH); break;
        case 3: digitalWrite ( Relays[TwoB] , HIGH); break;
        case 4: digitalWrite ( Relays[One] , HIGH); break;
        case 5: digitalWrite ( Relays[TwoC] , HIGH); break;
      }
      button.counter++;
      button.counter = button.counter % 6;
    }
  }
}

Hi paulpaulson,

have quite some years of programming experience with delphi and I'm coding for microcontrollers 1,5 years in C++ and I'm quite familiar with the standard things in C++.
But I don't know all the specialties you can code in C++.

So can you please explain how this for-loop with variable-type "auto" works?

for (auto Relay : Relays) pinMode ( Relay, OUTPUT);

What exactly does it mean to write "auto" here?
Relays is an array of byte

Does this mean a for-loop written as

for (auto Relay : Relays) pinMode ( Relay, OUTPUT);

start with array-element zero and iterate through all array-elements of array Relais
executing the command pinMode where variable Relay is holding the value of each array-element. So in the given example with

const byte Relays[] {3, 7, 8, 4};

the for-loop

for (auto Relay : Relays) pinMode ( Relay, OUTPUT);

does the same as

pinMode(3,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(4,OUTPUT);

?

best regards Stefan

Yes.

Can you please clarify what you mean by assistance? Are you wanting guidance in order to make the changes yourself, or would you prefer someone to update the code for you?

Hello

Take a search engine your choise and search for " range-based "for" loop"

I did googling
google came up with the usual non-didactic too short & too spohisticated to understand hits
https://en.cppreference.com/w/cpp/language/range-for

https://www.cprogramming.com/c++11/c++11-ranged-for-loop.html

https://www.cprogramming.com/c++11/c++11-ranged-for-loop.html

https://www.codegrepper.com/code-examples/cpp/use+range+based+for+loop+for+array+c%2B%2B

https://www.programmersought.com/article/47135401626/

So I repeat my question. Would you mind to answer with a simple "Yes" or "no" if my assumption / attempt to interpretate your example is correct?

the for-loop

for (auto Relay : Relays) pinMode ( Relay, OUTPUT);

does the same as

pinMode(3,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(4,OUTPUT);

best regards Stefan

You didn't like like my answer?

Hi Paul, I'm sorry I overlooked your answer. I clicked on the blue little symbol to see the latest answer.
best regards Stefan

yes

Design a small sketch to lern how it works.

This is where you know the button state has changed. (You are acting on both the press and the release for some reason.) If you record the time (millis()) here you can subtract the previous value to calculate how many milliseconds have passed since the last button press/release. Compare that value to 1000 (one second) and 2000 (two seconds) to determine which of the patterns you are following.

Hello
Thanks you for your relpys
It looks like the code is already using millis, but I dont know what for?

If the code starts doing complex calculations, a set of calculations for under 1 Second, 1 second and 2 seconds,

wont the code be too large and complex and not be responsive enough to detect multiple presses per second?sketch

Here is sketch as request

thanksyou

what about something like this that determines the number of relays turned on based on the time between changes at the input?

//BLOCK COMMENT
//https://forum.arduino.cc/t/cyclic-relay2a-2b/889080/10
#define ProjectName "Cyclic Relay2A & 2B"

// CONSTANT DEFINITION
#undef MyHW
#ifdef MyHW
const byte Relays[]  { 10, 11, 12, 13 };
const byte Buttons[] { A1};
enum { RelayOn = LOW, RelayOff = HIGH };

#else
const byte Relays[]  { 3, 7, 8, 4};
const byte Buttons[] { 2};
enum { RelayOn = HIGH, RelayOff = LOW };
#endif

// VARIABLE DECLARATION
enum {One, TwoA, TwoB, TwoC};

char s [80];


struct BUTTON {
    byte pin;
    bool state;
    int counter;
    unsigned long stamp;
    unsigned long duration;
} button {Buttons[One], 1, 0, 0, 20};


void setup () {
    Serial.begin (9600);
    Serial.println (F ("."));
    Serial.print (F ("File   : ")), Serial.println (__FILE__);
    Serial.print (F ("Date   : ")), Serial.println (__DATE__);
    Serial.print (F ("Project: ")), Serial.println (ProjectName);

    pinMode (LED_BUILTIN, OUTPUT);

    for (auto Relay : Relays)  {
        digitalWrite (Relay, RelayOff);
        pinMode      (Relay, OUTPUT);
    }

    for (auto Button : Buttons)
        pinMode ( Button, INPUT_PULLUP);
}

void
setRelays (
    int    rly0,
    int    rly1,
    int    rly2,
    int    rly3 )
{
    sprintf (s, "  %s: %d %d %d %d", __func__, rly0, rly1, rly2, rly3);
    Serial.println (s);

    digitalWrite (Relays [0], rly0);
    digitalWrite (Relays [1], rly1);
    digitalWrite (Relays [2], rly2);
    digitalWrite (Relays [3], rly3);
}

#define MAX_TIME    2000

void
pump (
    unsigned delta )
{
    Serial.println (__func__);

    if (MAX_TIME < delta)
        setRelays (RelayOff, RelayOff, RelayOff, RelayOff); 
    else if (1000 < delta)
        setRelays (RelayOn,  RelayOff, RelayOff, RelayOff); 
    else if (500  < delta)
        setRelays (RelayOn,  RelayOn,  RelayOff, RelayOff); 
    else if (250  < delta)
        setRelays (RelayOn,  RelayOn,  RelayOn,  RelayOff); 
    else
        setRelays (RelayOn,  RelayOn,  RelayOn,  RelayOn ); 
}

unsigned long lastTime;

void loop () {
    unsigned long currentTime = millis ();

#ifndef MyHW
    digitalWrite (LED_BUILTIN, (currentTime / 500) % 2);
#endif

    bool but = digitalRead (button.pin);
    if (button.state != but)  {
        button.state = but;

        if (LOW == but)  {
            pump (currentTime - button.stamp);
        }

        button.stamp = currentTime;

        lastTime = currentTime;
    }
    else if ( (currentTime - lastTime) > MAX_TIME)  {
        setRelays (RelayOff, RelayOff, RelayOff, RelayOff); 

        lastTime = currentTime;
    }
}

by the way, the problem with printing the date indicates when the code was built, not when it was last modified.

and during development, i've found it necessary to know if it was built 5 mins ago or 10. (did the last compile fail).

i typically use a date code -- 211012c

The code is using millis() only for 'button.stamp'. With that and button.duration it decides how often to look at the button. In your case, every 20 milliseconds. I'm guessing that the intent is to 'debounce' the button. I would do the debounce as part of the state change detection and have a separate timer for the time between presses.

//BLOCK COMMENT
//https://forum.arduino.cc/t/cyclic-relay2a-2b/889080/10
#define ProjectName "Cyclic Relay2A & 2B"
// CONSTANT DEFINITION
// you need to change these constants to your hardware
const byte Relays[] {3, 7, 8, 4};
const byte Buttons[] {2};
// VARIABLE DECLARATION
enum {One, TwoA, TwoB, TwoC};
struct BUTTON
{
  byte pin;
  int pressedState;  // LOW for Active Low
  bool wasPressed;
  int counter;
  unsigned long lastStateChangeTime;
  unsigned long debounceInterval;
} button {Buttons[One], LOW, false, 0, 0UL, 20UL};

void setup()
{
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);
  for (auto Relay : Relays) pinMode ( Relay, OUTPUT);
  for (auto Button : Buttons) pinMode ( Button, INPUT_PULLUP);
}

void loop ()
{
  unsigned long currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);

  bool buttonIsPressed = digitalRead(button.pin) == button.pressedState;
  if (buttonIsPressed != button.wasPressed &&
      currentTime - button.lastStateChangeTime >= button.debounceInterval)
  {
    // State Change Detected
    button.wasPressed = buttonIsPressed;
    button.lastStateChangeTime = currentTime;

    if (buttonIsPressed)
    {
      // Button was just pressed
      button.counter = (button.counter + 1) % 6;

      static unsigned long TimeOfLastButtonPress = 0;

      unsigned long timeBetweenButtonPresses = currentTime - TimeOfLastButtonPress;
      TimeOfLastButtonPress = currentTime;

      for (auto Relay : Relays)
        digitalWrite ( Relay, LOW);

      if (timeBetweenButtonPresses > 1500) // longer than a second and a half
        SlowPressCycle(button.counter);
      else if (timeBetweenButtonPresses > 500) // Longer than half a second
        MediumPressCycle(button.counter);
      else
        StandardCycle(button.counter);
    }
  }
}

// When the Pulse is SLOW (like every 2 Seconds)
// I would like all Relays (TwoA, B & C) same time
void SlowPressCycle(int count)
{
  digitalWrite ( Relays[One], HIGH);
  digitalWrite ( Relays[TwoA], HIGH);
  digitalWrite ( Relays[TwoB], HIGH);
  digitalWrite ( Relays[TwoC], HIGH);
}

// When the Pulse is faster (every 1 second)
// to have cycle between TwoA,B then TwoB,C
void MediumPressCycle(int count)
{
  switch (count)
  {
    case 0:
      digitalWrite ( Relays[One] , HIGH);
      break;

    case 1:
      digitalWrite ( Relays[TwoA] , HIGH);
      digitalWrite ( Relays[TwoB] , HIGH);
      break;

    case 2:
      digitalWrite ( Relays[One] , HIGH);
      break;

    case 3:
      digitalWrite ( Relays[TwoB] , HIGH);
      digitalWrite ( Relays[TwoC] , HIGH);
      break;

    case 4:
      digitalWrite ( Relays[One] , HIGH);
      break;

    case 5:
      digitalWrite ( Relays[TwoC] , HIGH);
      digitalWrite ( Relays[TwoA] , HIGH);
      break;
  }
}

// When the Pulse is Fastest (faster than 1 second)
// Standard Cycle TwoA, then TwoB, then TwoC.
void StandardCycle(int count)
{
  switch (count)
  {
    case 0: digitalWrite ( Relays[One] , HIGH); break;
    case 1: digitalWrite ( Relays[TwoA] , HIGH); break;
    case 2: digitalWrite ( Relays[One] , HIGH); break;
    case 3: digitalWrite ( Relays[TwoB] , HIGH); break;
    case 4: digitalWrite ( Relays[One] , HIGH); break;
    case 5: digitalWrite ( Relays[TwoC] , HIGH); break;
  }
}