Two Slide switches to sequence LEDs

Thanks for the advice really helping.

I've finally got the switch, case working in sequence as intended now.

next steps I need to look at how to get out of the cycle when both switches are low. I imagine the best way will be with an else if within each switch State. or would this be put in the break; statement?

What I've currently got:

int pump_1 = 3;
int pump_2 = 4;
const int alarm = 2;
int waterLow = 8;
int waterHigh = 9;
const unsigned long pumpInterval = 2000;
const unsigned long alarmInterval = 2000; 
unsigned long pumpOnTime;

int lowState = LOW;
int highState = LOW;

int nextState;
int currentState;


//possible states of the state-machine
typedef enum {STATE_IDLE,
              STATE_EMPTY,
              STATE_RUN1,
              STATE_RUN2,
              STATE_ALARM} states;

void setup(){
  Serial.begin(9600);
  
  nextState = STATE_IDLE;
  currentState = nextState;
  
  //set pin modes for each pin:
  pinMode(pump_1, OUTPUT);
  pinMode(pump_2, OUTPUT);
  pinMode(alarm, OUTPUT);
  pinMode(waterLow, INPUT_PULLUP);
  pinMode(waterHigh, INPUT_PULLUP);
}

void loop(){
  const unsigned long currentTime = millis(); // set current time
  int tankFull;
  
  tankFull = lowState += highState;
  lowState = digitalRead(waterLow);
  highState = digitalRead(waterHigh);
  
  switch(currentState){
    case STATE_IDLE:
    if(tankFull == 2){
      Serial.println("tank full");
      nextState = STATE_RUN1;
    }
    break;
    
    case STATE_RUN1:
      digitalWrite(pump_1, HIGH);
      pumpOnTime = currentTime;
    Serial.println("First pump Running");
      Serial.println("pump start time: ");
    Serial.print(currentTime);
    Serial.println(" ");
     // if(currentTime - pumpOnTime >= pumpInterval){
        nextState = STATE_RUN2;
      //}
    break;
    
    case STATE_RUN2:
    if(currentTime - pumpOnTime >= pumpInterval){
      digitalWrite(pump_2, HIGH);
      pumpOnTime = currentTime;
      Serial.println("Second pump running");
      Serial.println("2nd Pump Start Time: ");
      Serial.print(pumpOnTime);
      
      nextState = STATE_ALARM;
    }
    break;
    case STATE_ALARM:
    if(currentTime - pumpOnTime >= alarmInterval){
      digitalWrite(alarm, HIGH);
      Serial.println("Alarm on");
      Serial.println("Alarm start time:");
      Serial.print(currentTime);
      Serial.println("");
      
      nextState = STATE_EMPTY;
    }
    break;
  }
  currentState = nextState;
}
  
 /* Serial.println(" ");
  Serial.print(tankFull);
  
  if(tankFull == 2){
    digitalWrite(pump_1, HIGH);
    pumpOnTime = currentTime;
    
    Serial.println("First Pump Running");
    Serial.println("Pump run time: ");
    Serial.println(pumpOnTime);
  }else{
    digitalWrite(pump_1, LOW);
  }*/

Nice start, beware the addiction that is using Finite State Machinery. :expressionless:

tsnkFull should probably be calculated after you check the lowState and highState sensors.

Also it look odd, perhaps you meant

  tankFull = lowState + highState;

or even

tankFull = lowState && highState;

but logically, tankFull is identical to just highState.

Also at a glance nowhere do you seem to turn off the pumps… yet.

a7

Yeah I'm looking at the switching the pumps off next, wanted to make sure I had the actual sequence working as needed first.

originally I was having issues with everything turning off as soon as this went low. but looking back have a feeling that this was as it wasn't using switch case.

I think it would be more fun if you and your classmates had a real set of tanks and pumps, and were required to run your signal wires from your Arduino over to it, just 4 wires plus ground - the two tank sensors as inputs to your device, and your device supplying two outputs (controlling the pumps). And being solely responsible for creating the alarm audio visual effect.

At the beach we hacked up a simulator design. Less messy than real tanks, and faster. At this time, one cannot add a second Arduino to a wokwi project, so someone, perhaps the teacher or a student who is bored by the real assignment, could build a real version of a simulated simulated tank.

Of course I did - play with it here: EDIT: a program flaw has been corrected. There may be others.

And code

// https://forum.arduino.cc/t/two-slide-switches-to-sequence-leds/1012696

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

# define PIXEL_PIN    6
# define NLAMPS 20  // tank display size

Adafruit_NeoPixel tank(NLAMPS, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

// tank model stuff

# define FULL_TANK  ((NLAMPS - 1) * 32 + 31)  // mixed point tank level

# define TANK_FILL_RATE A0  // analog input for tank fill rate
# define FILL_ON   A1       // switch controls filling of tank

# define UPPER_FLOAT  5   // outputs from level sensors - use as inputs to logic
# define LOWER_FLOAT  4

// pump stuff

# define NPUMPS 2
unsigned char pumpState[NPUMPS] = {0, 0};

const unsigned char pumpRelay[NPUMPS] = {9, 8};   // pump relays
const unsigned char pumpButton[NPUMPS] = {3, 2};   // pump manual controls

void setup() {
  Serial.begin(115200);
  Serial.println("Hello Tank World!\n");

  tank.begin();  // neopixel

  pinMode(FILL_ON, INPUT_PULLUP);

  pinMode(UPPER_FLOAT, OUTPUT);
  pinMode(LOWER_FLOAT, OUTPUT);

  for (unsigned char ix = 0; ix < NPUMPS; ix++) {
    pinMode(pumpButton[ix], INPUT_PULLUP);

    pinMode(pumpRelay[ix], OUTPUT);
    digitalWrite(pumpRelay[ix], LOW);
  }

  tank.show();
}

void loop()
{
// run the model tank and pumps thing
  tankPumpWorld();
  printStatus();

// below here you have full speed loop
// here is just a simple empty/fill example:

// read the model
  unsigned char tankFull = digitalRead(UPPER_FLOAT);    // just read the status lamps!
  unsigned char tankEmpty = !digitalRead(LOWER_FLOAT);

// and use switchPump(pumpNumber, onOrOff) to control the pumps

  if (tankFull)         // if the tank is full
    switchPump(0, 1);   // start pump 0

  if (tankEmpty)        // if the tank is empty
    switchPump(0, 0);   // stop pump 0

}

// handle tank and pump simulation.
int tankLevel;

void tankPumpWorld() {
  static unsigned long lastLoop; 
  unsigned long now = millis(); //grab current time 

  if (now - lastLoop < 50) return;    // 20 Hz all around
  lastLoop = now;

// tank simulation and manual controls
// flawed  checkPumpSwitches();

  tankSimulate();   // update the tank model
  displayTank();
}

// system status report
void printStatus()
{
  static unsigned long lastReport;
  unsigned long now = millis();

  if (now - lastReport < 1333) return;
  lastReport = now;

  unsigned char tankFull = digitalRead(UPPER_FLOAT);    // just read the status lamp!
  unsigned char tankEmpty = !digitalRead(LOWER_FLOAT);    // just read the status lamp!


  if (tankFull) Serial.print("tank is full ");
  if (tankEmpty) Serial.print("tank is empty ");

  if (pumpState[0]) Serial.print("pump one is ON ");
  if (pumpState[1]) Serial.print("pump two is ON ");

  if (!digitalRead(FILL_ON)) {
    Serial.print(" the tank is filling at ");
    Serial.print((analogRead(TANK_FILL_RATE) >> 6) + 1);
    Serial.print("  units per tick.");
  }
  else Serial.print(" the fill valve is closed.");

  Serial.print(" tank level "); Serial.println(tankLevel);
}

// fill and empty the tank.
void tankSimulate()
{
  int rate = (analogRead(TANK_FILL_RATE) >> 6) + 1;

//  Serial.println(rate); 1 to 16 units per tick, fine

  if (digitalRead(FILL_ON) == LOW)
    addToTank(rate);

  runPumps();
}

void displayTank()
{
  int tankI = tankLevel >> 5;

  for (unsigned char ix = 0; ix < NLAMPS; ix++)  tank.setPixelColor(ix, 0);

  if (tankLevel)
    for (unsigned char ix = 0; ix <= tankI; ix++)  tank.setPixelColor(ix, 0x0000ff);

  digitalWrite(UPPER_FLOAT, tankLevel >= FULL_TANK);
  digitalWrite(LOWER_FLOAT, tankLevel > 0 ? HIGH : LOW);
  
  tank.show();
}

// press the button, turn on/leave on pump
// flawed - interferes with another pump on/off logic
void checkPumpSwitches()
{
  for (unsigned char ix = 0; ix < NPUMPS; ix++) {
    if (pumpIsOn(ix)) {
      if (digitalRead(pumpButton[ix]))
        switchPump(ix, 0);
    }
    else {
      if (!digitalRead(pumpButton[ix]))
        switchPump(ix, 1);
    }
  }
}

// OLD: press the button, toggle the coresponding pump on/off
void checkPumpSwitches0()
{
  static unsigned char lastPumpButton[NPUMPS] = {HIGH, HIGH};

  for (unsigned char ix = 0; ix < NPUMPS; ix++) {
    unsigned char thisPumpButton = digitalRead(pumpButton[ix]);
  
    if (lastPumpButton[ix] != thisPumpButton) {
      if (!thisPumpButton) {
        Serial.print("      saw button "); Serial.println(ix);
        switchPump(ix, pumpIsOn(ix) ? 0 : 1);
      }
      lastPumpButton[ix] = thisPumpButton;
    }
  }
}

// turn a pump on or off - logic
void switchPump(unsigned char thePump, unsigned char onOff)
{
  pumpState[thePump] = onOff;
}

// get sgtate of pump running/not running
unsigned char pumpIsOn(unsigned char thePump)
{
  return pumpState[thePump];
}

// turn off or on the pumps - mechanical. subtract from tank.
// heed the pushbutton manual pump control!
void runPumps()
{
for (unsigned char ix = 0; ix < NPUMPS; ix++)
  if (pumpState[ix] || !digitalRead(pumpButton[ix])) {
    digitalWrite(pumpRelay[ix], HIGH);
    addToTank(-5);
  }
  else digitalWrite(pumpRelay[ix], LOW);
}

// add or subtract from the tank. limit 0..full
void addToTank(int units)
{
  tankLevel += units;

  if (tankLevel > FULL_TANK) tankLevel = FULL_TANK;
  if (tankLevel < 0) tankLevel = 0;
}


Just an idea.

a7

Hello retcon

Did you close your project?

Almost I've got a full sketch with everything working as it should. I'm now just finalizing it all and looking to see where it could be tidied up and more compact before I submit it to my tutor.

Code currently:

const int pump_1 = 3;
const int pump_2 = 4;
const int waterLow = 8;
const int waterHigh = 9;
const int alarm = 2;
const unsigned long pumpInterval = 2000;
const unsigned long alarmInterval = 2000; 
unsigned long pumpOnTime;

int lowState = LOW;
int highState = LOW;

int nextState;
int currentState;


//possible states of the state-machine
typedef enum {STATE_IDLE,
              STATE_IDLE_2,              
              STATE_RUN1,
              STATE_RUN2,
              STATE_RUN3,
              STATE_RUN4,
              STATE_ALARM,
              STATE_ALARM2} states;

void setup(){
  Serial.begin(9600); //start serial interface for debugging & monitoring
  
  nextState = STATE_IDLE; // set the initial state of the machine in setup
  currentState = nextState; // sets the state of each case
  
  //set pin modes for each pin:
  pinMode(pump_1, OUTPUT);
  pinMode(pump_2, OUTPUT);
  pinMode(alarm, OUTPUT);
  pinMode(waterLow, INPUT_PULLUP);
  pinMode(waterHigh, INPUT_PULLUP);
}

void loop(){
  const unsigned long currentTime = millis(); // set current time
  int tankFull; //set tank full variable to monitor switches in place of sensors
  
  //read state of each "sensor" and declare states
  lowState = digitalRead(waterLow);
  highState = digitalRead(waterHigh);
  tankFull = lowState + highState; //define tankFull calculation. 
  
 //tank full (when lowState = 1 and highState = 1)
  
  // use switch... case to manage pump sequence
  switch(currentState){
    case STATE_IDLE:
    if(tankFull == 2){ 
      Serial.println("tank full");

      nextState = STATE_RUN1;
    }else if(tankFull == 0){
    digitalWrite(pump_1, LOW);
    digitalWrite(pump_2, LOW);
    digitalWrite(alarm, LOW);
    }
    break;
    
    case STATE_RUN1:
    lowState = digitalRead(waterLow);
    highState = digitalRead(waterHigh);
    tankFull = lowState + highState;
    
    if(tankFull >= 1){
    digitalWrite(pump_1, HIGH);
    pumpOnTime = currentTime;
    
    Serial.println("Pump 1 Running");
    Serial.println("Pump 1 start time: ");
    Serial.print(currentTime);
    Serial.println(" ");
  //  tankCycle++;
    nextState = STATE_RUN2;
    }else if(tankFull == 0){
    digitalWrite(pump_1, LOW);
    digitalWrite(pump_2, LOW);
    digitalWrite(alarm, LOW);
      Serial.println("Tank Empty");
      
      nextState = STATE_IDLE_2;
    }
    break;
    
    case STATE_RUN2:
    lowState = digitalRead(waterLow);
    highState = digitalRead(waterHigh);
    tankFull = lowState + highState;
    
    if(tankFull >=1){
      if(currentTime - pumpOnTime >= pumpInterval){
      digitalWrite(pump_2, HIGH);
      pumpOnTime = currentTime;
      Serial.println("Pump 2 running");
      Serial.println("Pump 2 Start Time: ");
      Serial.print(pumpOnTime);
      Serial.println("");
      nextState = STATE_ALARM;
      }
    }else if(tankFull == 0){
    digitalWrite(pump_1, LOW);
    digitalWrite(pump_2, LOW);
    digitalWrite(alarm, LOW);
      Serial.println("Tank Empty");
      
      nextState = STATE_IDLE_2;
    }
    break;
      
    case STATE_ALARM:
      
      lowState = digitalRead(waterLow);
      highState = digitalRead(waterHigh);
      tankFull = lowState + highState;
      
      if(tankFull >= 1){
        if(currentTime - pumpOnTime >= alarmInterval){
          digitalWrite(alarm, HIGH);
          Serial.println("Alarm on");
          Serial.println("Alarm start time:");
          Serial.print(currentTime);
          Serial.println("");
          
          nextState = STATE_IDLE_2;
        }
      }else if(tankFull == 0){
        digitalWrite(pump_1, LOW);
        digitalWrite(pump_2, LOW);
        digitalWrite(alarm, LOW);
        Serial.println("Tank Empty");
        
        nextState = STATE_IDLE_2;
      }
    break;
    
    case STATE_IDLE_2:
    if(tankFull == 2){
      Serial.println("tank full");

      nextState = STATE_RUN3;
    }
    
    else if(tankFull == 0){
    digitalWrite(pump_1, LOW);
    digitalWrite(pump_2, LOW);
    digitalWrite(alarm, LOW);
    }
    break;
    
    case STATE_RUN3:
    lowState = digitalRead(waterLow);
    highState = digitalRead(waterHigh);
    tankFull = lowState + highState;
    
    if(tankFull >= 1){
    digitalWrite(pump_2, HIGH);
    pumpOnTime = currentTime;
    
    Serial.println("Pump 2 Running");
    Serial.println("Pump 2 start time: ");
    Serial.print(currentTime);
    Serial.println(" ");
  
    nextState = STATE_RUN4;
    }else if(tankFull == 0){
    digitalWrite(pump_1, LOW);
    digitalWrite(pump_2, LOW);
    digitalWrite(alarm, LOW);
      Serial.println("Tank Empty");
      
      nextState = STATE_IDLE;
    }
    break;
    
    case STATE_RUN4:
    lowState = digitalRead(waterLow);
    highState = digitalRead(waterHigh);
    tankFull = lowState + highState;
    
    if(tankFull >=1){
      if(currentTime - pumpOnTime >= pumpInterval){
      digitalWrite(pump_1, HIGH);
      pumpOnTime = currentTime;
      Serial.println("Pump 1 running");
      Serial.println("Pump 1 Start Time: ");
      Serial.print(pumpOnTime);
      Serial.println("");
      nextState = STATE_ALARM2;
      }
    }else if(tankFull == 0){
    digitalWrite(pump_1, LOW);
    digitalWrite(pump_2, LOW);
    digitalWrite(alarm, LOW);
      Serial.println("Tank Empty");
      
      nextState = STATE_IDLE;
    }
    break;
      
    case STATE_ALARM2:
      
      lowState = digitalRead(waterLow);
      highState = digitalRead(waterHigh);
      tankFull = lowState + highState;
      
      if(tankFull >= 1){
        if(currentTime - pumpOnTime >= alarmInterval){
          digitalWrite(alarm, HIGH);
          Serial.println("Alarm on");
          Serial.println("Alarm start time:");
          Serial.print(currentTime);
          Serial.println("");
          
          nextState = STATE_IDLE;
        }
      }else if(tankFull == 0){
        digitalWrite(pump_1, LOW);
        digitalWrite(pump_2, LOW);
        digitalWrite(alarm, LOW);
        Serial.println("Tank Empty");
        
        nextState = STATE_IDLE;
      }
    break;
  }
  currentState = nextState;
}

and Id like to thank everyone for the pointers and input really helped with the references to look at too!

@retcon with only one minor change to my simulator and a remapping of your I/O pins, I was able to graft your current code onto my tank simulator.

I'm off to the beach, where we will probably cower under umbrellas and drink cold beer between "cooling off" in the water, so I didn't test it too much.

But your solution appears to be working.

I'll look closer, but I don't see the logic for "sharing the load" of which pump takes on the primary roll every other time the tank needs emptying.

Wait, it does… I'll look closer at what made me think it didn't - if both pumps get invoilved? If there was an alarm? Later after rest and when sober I will.

This

const unsigned long pumpInterval = 2000;

is going to be 30000 (30 seconds) in the production version of your tank controller... I appreciate that for testing, 2 seconds is still an eternity.

I turned it up to 10 seconds, so there's time to play with turning on and off the flow into the tank as well as monkeying with the flow rate, which can be adjusted with the slide fader between very slow (one pump easily) kinda fast (2nd pump will def be needed) to too fast, two pumps can't keep up with the flow &c.

It was simply a matter of redefining your I/O pin choices and wiring your 4 signals to appropriate pins that are part of the simulation. Less fun than two Arduinos, but effective.

Play with it here:

a7

I have taken a low level flight about your sketch, and have tested it a bit more.

You are achieving a loop rate of 36 kHz. Well done.

I see repetition, as in:

      digitalWrite(pump_1, LOW);
      digitalWrite(pump_2, LOW);
      digitalWrite(alarm, LOW);

Look into the use of functions. You may see the value of writing

void turnOffPumpsAndAlarm()
{
// some code for the function
}

One nice thing is that changing what it means to do that is all in just one place.

It gives the code in the switch/case a little higher level.

You repeat these lines in many cases:

     lowState = digitalRead(waterLow);
     highState = digitalRead(waterHigh);
     tankFull = lowState + highState;

when in fact they (probably) have not changed, you only need to create and set the values of those variables once at the beginning of your loop() function.

//read state of each "sensor" and declare states
 int lowState = digitalRead(waterLow);
 int highState = digitalRead(waterHigh);
 int tankFull = lowState + highState; //define tankFull calculation. 

I'm almost certain that every test of your tankFull calculated would be identical to testing either lowState or highState as appropriate.

I would lose the STATE_ prefixes for your state names, it's just extra ink. Style choice.

Now I see that you have used eight states to control the load balancing of the pumps. This is an abuse of a relatively heavy weight tool! Think only about adding a third pump (12 states?), then a fourth… and even if you say it always two pumps, changing how the machinery works would still take double edits for any change. I make errors editing code. The fewer times you say the same thing, the easier it is to manage.

So four states should suffice, the means for balancing can be far less involved, and done in such a manner as to support a third (or Nth) pump by adding a pin where a pump relay is supposed to be. An exercise for the reader, haha.

Save this code and revisit it after the dust settles. I should have led with I do not argue with success and good work!

a7

Hello retcon

When is the due date for the project?

The pump control can be simplified by a function call as:

PSEUDOCODE:

constexpr byte PumpPins[] {OutPutPins[PumpOne], OutPutPins[PumpTwo]}; 
enum Pump {Off, On};

void pumps(int goTo)
{
  static bool nextPump;
  switch (goTo)
  {
    case Pump::Off:
      for (auto PumpPin : PumpPins) digitalWrite(PumpPin, LOW);
      break;
    case Pump::On:
      digitalWrite(PumpPins[nextPump], HIGH);
      nextPump = !nextPump;
      break;
  }
}

This function can be simply called as pumps(Pump::Off); or pumps(Pump::On); as needed.

Have a nice day and enjoy programming in C++ and learning.
Errors and omissions excepted.

Deadline is the 29th August,

I was looking to use the control as functions however when I've ran it im missing something with the timing of the pumps and then moving onto the next state.

though ill take a look at what you and @alto777 have provided and see what I've missed.

I think you're right on this one, though when I first started I was wanting to maintain the use of both sensors to trigger the pump control. with the idea that certain combinations would be able to raise error messages. (although it wouldn't be needed for the scope of this assignment).

Definitely I've saved this and gives me a sound basis to work off now to refine it. and if all else fails will suffice to be handed in if I've got nothing else before the deadline

Hello retcon

Exclude the timer handling from the cases handeld by the FSM. The FSM should handle the cases for timer actions, like start/stop, and pump actions, like on/off. The a.m. pump control function handles the multiple pump action itself.
This is one [1] of n defintions for the stages could be used by a FSM.

enum Stages {Empty, Low, Fault, High, Wait} stage = Empty;

Take a glas of a good wine and think about it at the weekend.

Have a nice day and enjoy programming in C++ and learning.
Errors and omissions excepted.

Your function is not quite the specified behaviour. It looks like your function would consistently drain a tank, if it was possible and necessary, by using first pump A, then pump A and B.

Next time it did that, it would be A, then A + B again, when in fact it should be pump B, then B + A.

This below is a bit literal and depends exactly on the way the pumps are used in @retcon's sketch, but it does meet the idea that any time some pump starts up to begin emptying the tank, it will not be the pump that took the lead the last time, no matter if one or both pumps were needed. It just uses the LSB of a variable to mean which pump takes the lead/

turnOnFirstPump() and turnOnSecondPump() can replace the digitalWrite() statements in obvious places in the cases.

unsigned char nextPumpFlag;

void turnOnFirstPump()
{
  turnOnNextPump();
  nextPumpFlag++;
}

void turnOnSecondPump()
{
  turnOnNextPump();
}

void turnOnNextPump()
{
  if (nextPumpFlag & 0x1) {
    digitalWrite(pump_1, HIGH);
    Serial.println("Pump 1 Running");
  }
  else {
    digitalWrite(pump_2, HIGH);
    Serial.println("Pump 2 Running");
  }
}

void turnOffPumpsAndAlarm()
{
  digitalWrite(pump_1, LOW);
  digitalWrite(pump_2, LOW);
  digitalWrite(alarm, LOW);
}

I used the above and cut your switch/case down to four states, still sequencing and controlled like the origianl.

A similar approach could be used for more than two pumps, probably using one function to turn on the "next" pump rather than literally having a function for each first, second, third &c. pump.

I am with @paulpaulson's suggestion that the whole thing be re-written now that you know what you are doing. :expressionless: Maybe he didna say that, but that is the implication.

It would provide an opportunity for fixing something that makes the sketch less beautiful: the state names do not accurately describe what is happening when the machine is in that state.

IDLE may mean pumps are (still) running, ALARM is up and the water is or isn't going away.

RUN1 is just starting the first pump. RUN2 is one pump running. ALARM is both pumps running, but not yet the alarm LED is illuminated.

I have said I do not argue with success - your code works and does the task required, it's just a bit of a jumble which is OK in a small toy sketch but would lead to trouble in a more real device.

I would change the alarm to just be an independent resettable indication that there is (or has been) trouble with the system. What was any detail around how the alarm should be raised and how it should control subsequent behaviour?

a7

Hello alto777

This should be not a problem to extend of modify the pump function finaly as requiered, there are two only.

Have a nice day and enjoy programming in C++ and learning.
Errors and omissions excepted.

No. I would expect you could do it in your sleep!

a7

Thanks For the advice, managed to get the number of states to the 4 with using functions for the pumps and alarm.

one thing I'm a bit uncertain of is, if (nextPumpFlag & 0x1) is this simply working as a pointer and the memory from nextPumpFlag++

I'm assuming it is essentially working as a binary pointer looking at the LSB for which pump to switch on but not 100% certain at the moment.

Almost. Just a programming trick, I should have made it more literal and obvious.

nextPumpFlag is incremented strategically, then when needed its LSB is used to delect one pump or the other.

Only two pumps makes it easy. nextPumpFlag is only being used as a one bit number, 0 or 1. And when turning on a pump, it is either this one or the other one. One bit.

If multiple pumps more than two were in use, the same idea needs a bit of extra help. Here is a test of handling more than two pumps. Now the counting has to go 0 to NPUMPS - 1, so you see a few places where a number is incremented then fixed so it wraps around rather than going to or beyond NPUMPS.

Which was kinda automatic with a one bit counter.

// https://forum.arduino.cc/t/two-slide-switches-to-sequence-leds/1012696

# include "ezButton.h"

ezButton test(3);
ezButton add(5), stop(4);

void setup() {
  Serial.begin(112500);
  Serial.println("test NPUMPS world!\n");

  test.setDebounceTime(12);
  add.setDebounceTime(12);
  stop.setDebounceTime(12);

  setupPumps();
}

void loop() {

  test.loop();
  add.loop();
  stop.loop();

  if (test.isPressed()) {
    Serial.println("I saw that!");
  }

  if (add.isPressed()) {
    Serial.print("I see that add... ");
    if (addAPump()) Serial.println("and cannot");
    else Serial.println("and did.");
  }

  if (stop.isPressed()) {
    Serial.println("I saw that stop!");
    stopAll();
  }
}

# define NPUMPS 4
const unsigned char pumpPin[] = {A0, A1, A2, A3};

unsigned char nOn;

void setupPumps()
{
  for (unsigned char tt = 0; tt < NPUMPS; tt++)
    pinMode(pumpPin[tt], OUTPUT);

  nOn = 0;
  stopAll();
}

void stopAll()
{
  nOn = 0;

  for (unsigned char tt = 0; tt < NPUMPS; tt++)
    digitalWrite(pumpPin[tt], LOW);
}

unsigned char addAPump()
{
/* load sharing */
  static unsigned char nFirst;
  static unsigned char myNext;

  if (nOn == 0) {
    myNext = nFirst;
    nFirst++; if (nFirst >= NPUMPS) nFirst = 0;
  }

  if (nOn == NPUMPS) return 1;    // FAIL no more pumps

  nOn++;

/* here is where a pump might really be turned on, or the process for doing initiated
  Serial.print("pump ");
  Serial.print(nOn);    // number in the work force 1, 2 &c.
  Serial.print(" is ");
  Serial.print(myNext); // pump ID number
  Serial.println("");
*/
  digitalWrite(pumpPin[myNext], HIGH);

  myNext++; if (myNext >= NPUMPS) myNext = 0;

  return 0;   // SUCCEED

/* non load sharing first
  if (nOn < NPUMPS) nOn++;
  else return 1;

  return 0;
*/
}

No matter how many pumps come on, the next time it starts from no pumps, it starts with the next pump after the first one last time.

Play with it here

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.