Crimson 3.1 C Programming

northwst

Member
Join Date
Feb 2019
Location
Oregon
Posts
11
I am stuck, pretty new at c "like" programming.
Trying to have a program run some comparisons to setpoints and variable data that comes in from a radio network via modbus to a Redlion HMI to run other programs and or trigger tags. The problem is if one set of instructions run it can disrupt the rest of the program. I want my sensors to start and stop a pump based on Temperature and/OR Moisture, Using one D/O on a radio to then trigger a customers controller. I know I am close, I have had it working with just Temps before. or just Moisture. Just cant get my statements right. help

if ((Field_K1.Temp_Low_Mon <= Targets.Low_Frost_SetPoint)||
(Field_K1.Temp_Low_Mon >= Targets.High_Heat_SetPoint))
{PumpsK1_S4.Temp_OnK1();
return;}

else if (Field_K1.Irrometer >= Targets.Irrometer_SetPoint_High)
{PumpsK1_S4.Water_OnK1();
return;}

else if ((Field_K1.Temp_Low_Mon >= Targets.High_Frost_SetPoint)&&
(Field_K1.Temp_Low_Mon <= Targets.Low_Heat_SetPoint))
PumpsK1_S4.Temp_OffK1();

if (Field_K1.Irrometer <= Targets.Irrometer_SetPoint_Low)
PumpsK1_S4.Water_OffK1();

Not sure how to use a switch statement if that would help.

Thank you.
 
You didn't mention where you're calling this program from--I'm guessing something cyclical like "On Tick." It generally isn't necessary to include a "return" command, unless your program is set up to return a value. The return terminates the program at that point, which would prevent the rest of the statements from evaluating. Same goes for "else"... its logic won't run if the preceding "if" evaluates as true.

Assuming you want all four of the checks to run all the time:
Code:
if ((Field_K1.Temp_Low_Mon <= Targets.Low_Frost_SetPoint) || (Field_K1.Temp_Low_Mon >= Targets.High_Heat_SetPoint))
    PumpsK1_S4.Temp_OnK1();
 
if (Field_K1.Irrometer >= Targets.Irrometer_SetPoint_High)
    PumpsK1_S4.Water_OnK1();
     
if ((Field_K1.Temp_Low_Mon >= Targets.High_Frost_SetPoint)&& (Field_K1.Temp_Low_Mon <= Targets.Low_Heat_SetPoint))
    PumpsK1_S4.Temp_OffK1();
            
if (Field_K1.Irrometer <= Targets.Irrometer_SetPoint_Low)
    PumpsK1_S4.Water_OffK1();
 
Yes I have an HOA that calls the program if in Auto or just calls the Tag if in Hand,
I can provide the File if necessary.
 
Looks like two separate temperature tests, both with hysteresis,

  • frost (below low=>on, above high=>turn off,
  • heat (below low=>off , above high=>turn on,
Logically the high frost setpoint has to be below the low heat setpoint (off). (Update: whoops, this is close but not quite true; however, the high frost setpoint (off) does need to be below the high heat setpoint (on), and the low heat setpoint (off) needs to be below the low frost setpoint (on)).



Also one moisture test also with hysteresis

  • Irrometer above high setpoint=>turn on
  • below low setpoint=>turn off.
Presumably measurements between setpoints have no effect i.e. neither turn on nor off.


My first though is to do a logical AND (C: &&) all the off setpoint checks, temperature and moisture together, in one if statement, and turn pump off if ANDed result is true.


Then do a logical OR (C: ||) of all the on setpoint checks in another if statement (or else off the if above), and turn pump on if ORed result is true.


The problem there is that say the temperature turns the pump on by going below the low frost setpoint. And before the temperature comes back above the high frost setpoint, the moisture drifts into the hysteresis band i.e. above the low moisture setpoint but below the high moisture setpoint, and after that the temperature goes above the high frost setpoint. The intended result would be to turn off the pump because, because the temperature below frost pump-on trigger is canceled and there never was any moisture pump-on trigger, but because the moisture trigger is not in the off region, and the pump will not turn off until it gets there.


What is needed is a way to know which test triggered the on state, and there are three possibilities: temperature below low frost; temperature above high heat; moisture above high setpoint. Can this C dialect use static or global variables i.e. persistent? That way the code can keep track of which tests triggered the pump-on, and cancel them individually when their respective off-test covers the hysteresis spread.


What I am saying is that this cannot be solved with knowledge of the measurements and setopots of temperature and moisture alone.


Code:
void routine() {
 

/* Static variables should maintain persistent values */
/* on subsequent calls to the same routine */
 

static int frost_pump_on;  

static int heat_pump_on;
static int moist_pump_on;


  /* Temp(erature) between frost limits does not change frost_pump_on value */
  /* This is equivalent to Latch/Unlatch or Set/Reset in PLCs */

  if (temp <= low_frost) frost_pump_on = 1;
  else if (temp >= high_frost) frost_pump_on = 0;


  /* More concise, possibly less clear, ternary operator alternate syntax:


  frost_pump_on = (temp <= low_frost) ? 1 : ((temp >= high_frost) ? 0 : frost_pump_on);


  */



  /* Temp(erature) between heat limits does not change heat_pump_on value */

  if (temp >= high_heat) heat_pump_on = 1;
  else if (temp <= low_heat) heat_pump_on;


  /* Moist(ure) between moist limits does not change moist_pump_on value */

  if (moist >= high_moist) moist_pump_on = 1;
  else if (temp <= low_moist) moist_pump_on = 0;


  if (frost_pump_on || heat_pump_on || moist_pump_on) PumpsK1_S4.Water_OnK1();
  else PumpsK1_S4.OffK1();
 
Last edited:
You didn't mention where you're calling this program from--I'm guessing something cyclical like "On Tick." It generally isn't necessary to include a "return" command, unless your program is set up to return a value. The return terminates the program at that point, which would prevent the rest of the statements from evaluating. Same goes for "else"... its logic won't run if the preceding "if" evaluates as true.

Assuming you want all four of the checks to run all the time:
Code:
if ((Field_K1.Temp_Low_Mon <= Targets.Low_Frost_SetPoint) || (Field_K1.Temp_Low_Mon >= Targets.High_Heat_SetPoint))
    PumpsK1_S4.Temp_OnK1();
 
if (Field_K1.Irrometer >= Targets.Irrometer_SetPoint_High)
    PumpsK1_S4.Water_OnK1();
     
if ((Field_K1.Temp_Low_Mon >= Targets.High_Frost_SetPoint)&& (Field_K1.Temp_Low_Mon <= Targets.Low_Heat_SetPoint))
    PumpsK1_S4.Temp_OffK1();
            
if (Field_K1.Irrometer <= Targets.Irrometer_SetPoint_Low)
    PumpsK1_S4.Water_OffK1();


To elaborate on what happens if I dont use a return; is the program continues as you say, but my relays click on and off since the program can provide both true and false outcomes. I am not sure if I can run the program up to either temp or water, and then stop until the statement is false and then continue to the rest of the statements. ??? thank you both for the input, it gets me thinking differently.
 
So, if I understand correctly, once one of the 'if' statements becomes true, it should only execute once until the logic goes from false to true again? If this is the case you might be better served by using tag triggers instead of programming. The "Absolute High" and "Absolute Low" trigger modes are >= and <= the Value, respectively (poorly named). The Action will execute once each time the comparison becomes true. You can also set a Hysteresis which will prevent chattering if the tag value is hovering around the trigger point.

trigger.PNG
 
So, if I understand correctly, once one of the 'if' statements becomes true, it should only execute once until the logic goes from false to true again? If this is the case you might be better served by using tag triggers instead of programming. The "Absolute High" and "Absolute Low" trigger modes are >= and <= the Value, respectively (poorly named). The Action will execute once each time the comparison becomes true. You can also set a Hysteresis which will prevent chattering if the tag value is hovering around the trigger point.
I will try this out thank you.
 
So after trying this I realized the tag will start the water program but then the Temp program overwrites the D/O back to off since I am still only using one D/O that is common to both issues, I may have to provide a second output for the water to solve this. ??
 
I’m a bit confused as to your outputs. You have four programs like PumpsK1_S4.Water_OnK1(). What are these programs doing?
 
So after trying this I realized the tag will start the water program but then the Temp program overwrites the D/O back to off since I am still only using one D/O that is common to both issues, I may have to provide a second output for the water to solve this. ??


Not quite, but you are almost there:


87537937_2915163278505968_7516268986489634816_n.jpg


"The penny drops."


That is the essence of what I was getting at with the static variable: the program needs to keep track of the temperature-driven and moisture-driven states independently, because those states are independent and therefore cannot be represented with a single bit.

The 64,000 dollar question is whether that/those persistent bit/s can be other than one of the physical D/Os of the PLC. Because you only need one D/O to turn on the pump, the logic to set that bit is entirely up to you.

So there will be one Crimson-internal, non-physical bit that tracks the temperature-driven pump state*, and another Crimson-internal bit that track the moisture-driven pump state**.


And the D/O is the logical OR of those two internal bits.



* persistent bit assigned a 1 outside low frost or high heat; bit assigned a 0 inside high frost and low heat; bit is not changed when temperature is within either hight/low band.

** persistent bit assigned a 1 above high moisture; bit assigned a 0 below low moisture; bit is not changed when the moisture is within the high/low band
 
Not quite, but you are almost there:


87537937_2915163278505968_7516268986489634816_n.jpg


"The penny drops."


That is the essence of what I was getting at with the static variable: the program needs to keep track of the temperature-driven and moisture-driven states independently, because those states are independent and therefore cannot be represented with a single bit.

The 64,000 dollar question is whether that/those persistent bit/s can be other than one of the physical D/Os of the PLC. Because you only need one D/O to turn on the pump, the logic to set that bit is entirely up to you.

So there will be one Crimson-internal, non-physical bit that tracks the temperature-driven pump state*, and another Crimson-internal bit that track the moisture-driven pump state**.


And the D/O is the logical OR of those two internal bits.



* persistent bit assigned a 1 outside low frost or high heat; bit assigned a 0 inside high frost and low heat; bit is not changed when temperature is within either hight/low band.

** persistent bit assigned a 1 above high moisture; bit assigned a 0 below low moisture; bit is not changed when the moisture is within the high/low band


Yes I believe you have it.... just dont know how to do it. I have since rewrote all of my code to have a separate output for Moisture, I can combined the output of the relays to turn on one pump. 24vac trigger on controller. Just more parts to fail. I will continue to work on this, since I believe there is an answer, just need to get the customer running now. I can provide the CD31 file if needed, nothing to hide.
 
One thing first, you are using both <= and >= for a comparison of the same two values, so you will always have a conflict when A = B. You should use either 'Less than or Equal' with a 'Greater than', or you can have 'Less than' with a 'Greater than or Equal'.


Then can I try putting the problem in plain language:

If the Temperature is lower than the Frost set point, OR if the Temperature is higher than the heat set point, run the pump.

If the Moisture is greater than the high set point, run the pump

If the Temperature is higher than the Frost set point AND Temperature is lower than the heat set point, stop the pump

If the Moisture is lower than the low set point, stop the pump



So where in that do you get a conflict that is both trying to run and stop the pump at the same time? Other posts suggest a conflict between Temperature and Moisture, if that is correct then you have to decide which takes priority. If they both take priority then you have a problem with your question, not in getting to the answer.
 
One thing first, you are using both <= and >= for a comparison of the same two values, so you will always have a conflict when A = B. You should use either 'Less than or Equal' with a 'Greater than', or you can have 'Less than' with a 'Greater than or Equal'.


Good point.
Then can I try putting the problem in plain language:

[1] If the Temperature is lower than the Frost set point, OR if the Temperature is higher than the heat set point, run the pump.

[2] If the Moisture is greater than the high set point, run the pump

[3] If the Temperature is higher than the Frost set point AND Temperature is lower than the heat set point, stop the pump

[4] If the Moisture is lower than the low set point, stop the pump



[Edit: added numbering above for reference]


So where in that do you get a conflict that is both trying to run and stop the pump at the same time? ...


If the temperature measurement is below the low Frost setpoint, then case [1] applies i.e. start the pump.


If at the same time the moisture measurement is below the Low Moisture setpoint, then case [4] applies i.e. stop the pump.


[Update: fix typo; add epmhasis]
 
Last edited:
You put start but I know you meant stop for case 4. :)
If the temperature measurement is below the low Frost setpoin, then case [1] applies i.e. start the pump.
If at the same time the moisture measurement is below the Low Moisture setpoint, then case [4] applies i.e. start the pump.
Other posts suggest a conflict between Temperature and Moisture, if that is correct then you have to decide which takes priority. If they both take priority then you have a problem with your question, not in getting to the answer.
That is what I meant, if both can't be right at the same time then it isn't a problem with how to code it, the problem is in the control definition. You either have to give Case [1] or Case [4] priority, or you have to redefine the problem.
 

Similar Topics

Hey everyone! Need a little help with some scripting in Crimson 3.0. With this first script I am just trying set a local variable string based...
Replies
8
Views
2,342
Hi, I have a Red Lion E3 io counting output from weld cells, connected to a PTV station for the visuals. Our number of weld cells is set to...
Replies
2
Views
1,534
Good day I'm looking for a way to let crimson 3 monitor 3 temperatures from modbus then i want crimson to "GotoPage" when these 3 temps have...
Replies
3
Views
1,610
Hello all, First time here, So I want to take an analog input and total it over time. For example, the input would be in ml/s and I would like...
Replies
1
Views
1,459
I am trying to program a G3 through Crimson 3 if (Part_1_Online) GotoPage(MAIN_369); else if (Part_2_Online) GotoPage(MAIN_369CR); else if...
Replies
11
Views
2,545
Back
Top Bottom