Trying to setup an automatic alternating function to alternate outputs

Hello everyone

I'm trying to alternate between two digital outputs. The first digital output is setup to switch on at a certain value, lets call it 60% and to switch off at 20%. The second digital output is setup to switch on at 65% and to switch off also at 20%.

The active range will then be between 20% and 60%. For instance, when a reading of 60% is reached, then digital output 2 switches on. It then stays on until the reading drops to 20% or below that value. The reading then automatically increases again. Once it reaches 60% again, it must switch on digital output 3 instead of 2.

Lets say this happens but the reading is still increasing and not decreasing. Say it then reaches 65% then it much switch on digital output 2 as well. This means that digital output 2 and 3 is on at this stage. Now the reading is decreasing again. Once it reaches 20% both digital outputs switch off. Once the reading reaches 65% again, digital 2 switches on again. so it is still alternating between the two outputs. The setup of the second digital output is a fail safe value, i.e. when digital output one is switched on and the reading doesn't decrease but still increases, once it reaches the fail safe value the second digital output also switches on.

The functionality is called alternating pump control. I've come up with the following code and as I look at it, it should be working but it only keeps switching digital output 2 and never switches digital output 3.

I'm using a GLCD and have setup a simple count up count down program to test my code. I'm displaying the counted value i.e. the measured value and also the alternating trigger which acts as to switch between digital output 2 and 3.

Thanks in advance
Dirk

void loop() 
{
  GLCD.SelectFont(System5x7);
  GLCD.CursorToXY(30, 19);
  GLCD.print(Measured_Value);
  GLCD.CursorToXY(30, 29);
  GLCD.print(Alternating_Trigger);
  
  if ( Switch_trigger == 1 && ( Measured_Value <= Relay1_On_Val ) )
  {
    Measured_Value +=5;
    delay(1000);
    
    if ( Measured_Value > Relay1_On_Val )
    {
      Switch_trigger = 2;
    }      
  } 

  if ( Switch_trigger == 2 && ( Measured_Value >= Relay1_Off_Val ) )
  {
    Measured_Value -= 5;
    delay(1000);    
    
    if ( Measured_Value < Relay1_Off_Val )
    {
      Switch_trigger = 1;
    }  
  }
  
  Alternating_Pump_Control_trigger_function();
  
}

void Alternating_Pump_Control_trigger_function()
{ 
  if ( Alternating_Pump_Control_Selector == 1 )     // Only execute code if the alternating pump control is activated.
  {
    if ( Alternating_Trigger == 1 && ( Measured_Value >= Relay1_On_Val ) )
    {
      digitalWrite(Relay1, HIGH);
      
      if ( Measured_Value >= Relay2_On_Val )        // Trigger Relay 2 on as well if the value is still rising. This indicates that the first pump is not able to pull the level down i.e.
      {                                             // pump requires maintenance or pump is broken.
        digitalWrite(Relay2, HIGH); 
      }                 
    }

  //******************************************************************************************************************************************************************************         
  
    if ( Alternating_Trigger == 1 )
    {    
      if ( Measured_Value <= Relay1_Off_Val )       // When the off setpoint is reached, switch off the relay to switch off the pump
      {
        Alternating_Trigger = 2;                      // Set Alternating Trigger to 2 so that the pumps will be alternated with the next cycle.  
        digitalWrite(Relay1, LOW);             
      }      
        
      if ( Measured_Value <= Relay2_Off_Val )       // When the off setpoint is reached, switch off the relay to switch off the pump
      {
        digitalWrite(Relay2, LOW); 
      }     
    }

  //******************************************************************************************************************************************************************************             
    
    if ( Alternating_Trigger == 2 && ( Measured_Value >= Relay1_On_Val ) )      //Relay 1 on limit is your level trigger.
    {
      digitalWrite(Relay2, HIGH);
      
      if ( Measured_Value >= Relay2_On_Val )        // Trigger Relay 2 on as well if the value is still rising. This indicates that the first pump is not able to pull the level down i.e.
      {                                             // pump requires maintenance or pump is broken.
        digitalWrite(Relay1, HIGH); 
      }                
    }  

  //******************************************************************************************************************************************************************************         
  
    if ( Alternating_Trigger == 2 )
    {  
      if ( Measured_Value <= Relay1_Off_Val )       // When the off setpoint is reached, switch off the relay to switch off the pump
      {
        Alternating_Trigger = 1;                      // Set Alternating Trigger to 2 so that the pumps will be alternated with the next cycle. Only do this once the relay off limit have been reached otherwise it the following alternating sequence starts anyways.        
        digitalWrite(Relay2, LOW); 
      }      
        
      if ( Measured_Value <= Relay2_Off_Val )       // When the off setpoint is reached, switch off the relay to switch off the pump
      {
        digitalWrite(Relay1, LOW); 
      }
    }
    
  //******************************************************************************************************************************************************************************             
  }
}

The first digital output is setup to switch on at a certain value, lets call it 60% and to switch off at 20%.

Are you talking values or percentages? Where is the value coming from? No one is going to steal your idea. Quit with handwaving, and tell us what you are talking about.

      if ( Measured_Value >= Relay2_On_Val )        // Trigger Relay 2 on as well if the value is still rising. This indicates that the first pump is not able to pull the level down i.e.

There is no excuse for such a long comment. You aren't writing a novel. You ARE allowed to use more than one line.

Hey PaulS

The comments explains the functionality as well. Apologies if I didn't get straight to the point. I've got a 23" display so my comments all fit in the the screen. Apologies if it's too long but it helps me understand everything as well. Will use a new line next time.

Back to the question.

I'm measuring distance by means of a ping sensor. The application is a sump that fills constantly with water. The measurement might be in percentages or values depending on the user. I've got a conversion function that already takes care of that part. You want to prevent the sump from over flowing so once it reaches a set setpoint one of the pumps switches on to start pumping the water from the sump to another location. If the 1st pump that switches on fails to pump the water away and the level increases to the second setpoint, i.e. the fail-safe setpoint then the second pump must switch on to drain the sump as this is an indication that the initial pump is blocked up or is broken.

You also want to alternate between the two pumps so as to increase the lifespan of the pumps itself and to increase the time between maintenance appointments. Let me know if it still isn't clear enough or if there are any questions.

Dirk

OK, I have some questions.

  GLCD.print(Measured_Value);

You have not measured anything. Why are you printing something you haven't measured?

    Measured_Value +=5;

So, it isn't a measured value. Why is the variable called Measured_Value?

then it much switch on digital output 2 as well. This means that digital output 2 and 3 is on at this stage. Now the reading is decreasing again. Once it reaches 20% both digital outputs switch off. Once the reading reaches 65% again, digital 2 switches on again. so it is still alternating between the two outputs.

Using names in the code makes it much easier to understand the problem/follow the description when reading the code.

Especially when you didn't post all of the code, so we can't see the relationship between variables in the code and numbers in the post.

I always find it useful to separate the collection of data from its display. Until you get the data collection, interpretation and control part working don't bother with the LCD stuff as it just confuses the code. Just use Serial.println() to display values in the early stages of developing a project.

I am also a great believer in putting each different activity in its own function rather than in loop(). That way each function is short and clear and easy to understand and debug separately from other problems. As fas as possible I like just to have a series of calls to functions in loop() but no other code.

...R

Hello PaulS and Robin2

I've created a separate sketch which I've posted in my previous post. I kept the sketch separate from my main body of code so that I can simulate test and make sure that the code is functioning correctly before I'm going to implement it into my main sketch.

From the code that I've posted:

Here I'm just printing the simulated measured value and the alternating trigger. The alternating trigger variable is responsible for selecting either relay1 (ditial output 2) or relay2 ( digital output 3) and to switch it on or off. This part of the code can obviously be changed to serial print but since I have everything hooked up already I was using the GLCD for testing the functionality of the code.

  GLCD.SelectFont(System5x7);
  GLCD.CursorToXY(30, 19);
  GLCD.print(Measured_Value);
  GLCD.CursorToXY(30, 29);
  GLCD.print(Alternating_Trigger);

This part of the code that is in my main loop is used to simulate a rising and falling measured value. Once the setpoint is reached then the value must start to decrease again as it would should a pump start pumping the level down:

 if ( Switch_trigger == 1 && ( Measured_Value <= Relay1_On_Val ) )
  {
    Measured_Value +=5;
    delay(1000);
    
    if ( Measured_Value > Relay1_On_Val )
    {
      Switch_trigger = 2;
    }      
  } 

  if ( Switch_trigger == 2 && ( Measured_Value >= Relay1_Off_Val ) )
  {
    Measured_Value -= 5;
    delay(1000);    
    
    if ( Measured_Value < Relay1_Off_Val )
    {
      Switch_trigger = 1;
    }  
  }
  
  Alternating_Pump_Control_trigger_function();

At the end of my void loop() you'll see that I'm calling my alternating pump control function.

The function starts of with a if which validates that Alternating_Pump_Control_Selector == 1. If not the whole function is bypassed. This is to check whether the user is implementing alternating pump control or just normal limits in the unit.

If the user is implementing alternating pump control then I check if the measured value is above relay 1 on setpoint, declared as Relay1_On_Val. If it is I switch Relay 1 on.

    if ( Alternating_Trigger == 1 && ( Measured_Value >= Relay1_On_Val ) )
    {
      digitalWrite(Relay1, HIGH);

You'll notice that there is a second if within this if. This is used to test if the level is still increasing and to switch on the second relay should the level increase above the fail safe setpoint.

      if ( Measured_Value >= Relay2_On_Val )        // Trigger Relay 2 on as well if the value is still rising. This indicates that the first pump is not able to pull the level down i.e.
      {                                             // pump requires maintenance or pump is broken.
        digitalWrite(Relay2, HIGH); 
      }

I then go and test whether the alternating trigger is set to 1 in a seperate if statement. This if statement is then used to test whether the lower setpoint have been reached as yet or not. If the measured value is below the lower setpoint, Relay1_Off_Val, switch the relay off by making digital output 2 low. Before this is done I set the Alternating_Trigger to value 2 so that the inverse of the above code can be executed.

After the this if statement I have another one to test whether the measured value is below Relay2_Off_Val as well to switch of this relay as well.

So now the measured value should increase again and the alternating trigger is set to a value of 2. Once the level reaches Relay1_On_Val again, then we should enter the inverse setup if statement which is the following code:

if ( Alternating_Trigger == 2 && ( Measured_Value >= Relay1_On_Val ) )      //Relay 1 on limit is your level trigger.
    {
      digitalWrite(Relay2, HIGH);

and here we test the fail safe again but you'll notice that I'm switching the relays in reverse order or alternate order:

      if ( Measured_Value >= Relay2_On_Val )        // Trigger Relay 2 on as well if the value is still rising. This indicates that the first pump is not able to pull the level down i.e.
      {                                             // pump requires maintenance or pump is broken.
        digitalWrite(Relay1, HIGH); 
      }

Lastly I test in a new if statement again if the alternating trigger is set to a value of 2 and if so I test to see when the level drops below the lower setpoints to switch off the relays and to switch the alternating trigger back to a value of 1 so that the top part of the code can be executed:

    if ( Alternating_Trigger == 2 )
    {  
      if ( Measured_Value <= Relay1_Off_Val )       // When the off setpoint is reached, switch off the relay to switch off the pump
      {
        Alternating_Trigger = 1;                      // Set Alternating Trigger to 2 so that the pumps will be alternated with the next cycle. Only do this once the relay off limit have been reached otherwise it the following alternating sequence starts anyways.        
        digitalWrite(Relay2, LOW); 
      }      
        
      if ( Measured_Value <= Relay2_Off_Val )       // When the off setpoint is reached, switch off the relay to switch off the pump
      {
        digitalWrite(Relay1, LOW); 
      }
    }

My problem is that Alternating trigger never changes from a value of 1 to a value of 2 so that the alternate part of the code can be executed. It stays stuck on a value of 1 and I can't seem to wrap my head around why it is doing that. I know that this is quite a mouth full so thank you for taking the time to go through it. If something is still unclear please let me know.

Dirk

I think the fact that you have needed to write such a long explanatory post should cause you to pause and rethink. I confess I haven't read it all.

As far as I can see what you want to do is fairly simple and would be much easier to code if you think of it as states (a variable for each output) that are changed by a function that reads and assesses the "measured value". Then a separate function would switch on or off the outputs depending on the save state values.

Perhaps something like this pseudo code

outPinA = 8;  // Arduino pin 
outPinB = 9;

digOut2 = LOW; // low = off
digOut3 = LOW;

lowThresh = 200; // 20% of 1023
medThresh = 610; // 60% of 1023
hiThresh = 660;  // 65% of 1023

void loop() {
  measureInput();
  controlOutput();
}


void (measureInput) {
    valA = analogRead(pinA);

    if (valA < lowThresh) {
      digOut2 = LOW;
      digOut3 = LOW;
        // switch outputs
      x = outPinA;
      outPinA = outPinB;
      outPinB = x;
    }

    if (valA > medThresh) {
       digOut2 = HIGH;
    }

    if (valA > hiThres) {
      digOut3 = HIGH;
    }
}

void (controlOutput) {
  digitalWrite(outPinA, digOut2);
  digitalWrite(outPinB, digOut3);
}

...R

Hello Robin2

Thanks for the input. But if I'm understanding your code correct then you've programmed a low, medium and high setpoint. Where digital output 2 switches on at the medium setpoint and digital output 3 switches on at the high setpoint. I need it to alternate between the two outputs. Maybe I didn't understand your code correct but if I did, then this is just a limit switch configuration and not an alternating switch configuration

Anyways, I got it working using my existing code. I had to implement a second validating variable since the Alternating_Trigger variable was going from value 1 to value 2 back to value 1 because of the way the if statements were setup. I've attached it and reworked it a bit for you to go through if your interested. Thanks again for taking the time to go through my query.

Dirk

Alternating_Pump_Control.ino (11 KB)

I conceptually split the logic between the progression of events and the alternation between outputs. The alternates are swapped in the IF clause that deals with the <20% condition.

Of course I may not have properly understood your project description.

My aim was to see how simply it could be coded, and if I've missed something I suspect a small tweak would solve the problem.

...R