PAC control subrotines passed parameters

May I know whether there is maximum number of passed parameters that allow be added inside subroutines? As when I added until #12 parameters, the ‘add’ button is unable and I not allow to add in more passed parameters

Yes there is a limit.
Its in the manual. I will look it up tomorrow if you like.

EDIT. Welcome to the forums! Glad you could join us.

Any suggestion or alternate if I want to add in more passed parameters into it?

Subs can call subs now, so if possible break your mega 12+ var single sub into smaller bytes.
ie, do some pre-processing on the way to your returned result.

Ok, thx for your suggestion. Hopefully in the future version we can add in more parameters to make it as a template for different projects purpose.

You can assign variables to a pointer table and then pass that as a parameter to a subroutine if you need more than 12 parameters.

2 Likes

I typically pass:

pointer table (for I/O and timers)
float table
integer table

Keeps things organized and covers everything but PID’s. There’s a trick for that.

May you explain more on how to use a timer inside pointer table with subroutines?

@kingsleychoong96: pointer tables can “point” to just about any type of variable, including timers. Assume you create a pointer table called pt_SubroutineParams that is 50 elements long. You want to pass up timer ut_SomeUpTimer and down timer dt_SomeDownTimer into your subroutine. You could do the following:

pt_SubroutineParams[0] = &ut_SomeUpTimer;
pt_SubroutineParams[1] = &dt_SomeDownTimer;
i_SubStatus = NameOfYourSubroutine(pt_SubroutineParams);

Inside your subroutine, you have to dereference the pointer table, meaning you need to know the data type of each index. For the passed parameter to your subroutine, assume you selected a pointer table and you called it pt_Params inside the subroutine. Also inside the subroutine you created two pointer variables: put_PointerToUpTimer and pdt_PointerToDownTimer.

put_PointerToUpTimer = pt_Params[0];
pdt_PointerToDownTimer = pt_Params[1];

Also, I can’t remember, but I think sometimes with pointer tables you have to use the wonky syntax of pointing to the address of the dereferenced object like the following:

put_PointerToUpTimer = &*pt_Params[0];
pdt_PointerToDownTimer = &*pt_Params[1];

Those bits of code should get you close anyway. I’ve created subroutines where I’ve passed in very long pointer tables and I’ve never had a problem. I don’t know that it’s always the best way to code, but it should work.

1 Like

@varland Thank you for the explanation and I had work with it well. As I am first time in using pointer in my program, I know that the benefit of using a pointer table enable me to passed in different type of variable into it used in my subroutines. However, I would like to know more about the benefits of using pointer in our program like using in our charts instead of subroutines, what is the benefits of using a pointer variable/ tables instead of direct create as numeric variable/table in our main program?

@kingsleychoong96:

Based on your reply, I’m not sure you totally understand pointers. You mention using pointers instead of subroutines, but that doesn’t make any sense – they’re two totally different things. Likewise, you don’t use pointers instead of directly created variables. Pointers are only useful in that they point to a memory address where a variable value is stored.

When you create an integer variable, i_Integer, the value of that variable is stored in memory at a specific address. If you create another integer variable, i_Integer2, the value of that variable is stored in memory at a different address. Every variable is stored in memory at a unique address. The actual value of a pointer variable is a memory address. Let’s say you create a pointer variable (pointing to an integer variable) called pi_IntegerPointer. Initially, the value of this pointer is null. null is not an integer value, but an indication that the pointer variable is not pointing to any memory address before it’s assigned. That’s why when you’re using pointer variables, you have to use referencing and dereferencing operators.

To make pi_IntegerPointer point to one of your integer variables, you use the & referencing operator. The referencing operator essentially says “get a reference to the memory address of.”. So the following code:

pi_IntegerPointer = &i_Integer;

essentially says: “set the value of pi_IntegerPointer to the memory address of i_Integer.” pi_IntegerPointer doesn’t contain an integer value, just a memory address. That’s where the dereferencing operator comes in. If you want to find the integer value of whatever integer the pointer variable is pointing to (i_Integer) in this case, you have to use the dereferencing operator. The dereferencing operator essentially says “get the value of the object stored at this memory address.”

// Incorrect - you can't assign a memory address to an integer variable.
i_Integer2 = pi_IntegerPointer;

// Correct - use the dereferencing operator to get the value at the given memory address.
i_Integer2 = *pi_IntegerPointer;

What should be obvious is that if you don’t have real, directly created variables, pointer variables are useless, because they can only point to null.

As to when you might want to use pointers, an old programming teacher of mine always said that if you don’t know, then you don’t need it. You’ll know when the time comes.

Here’s on example where you could potentially use pointers. Assume you have 25 solenoids that you want to open (turn on). You have digital outputs configured for the solenoids named do_Solenoid_1, do_Solenoid_2, etc. Consider the following code:

// Turn on all solenoids without pointers.
TurnOn(do_Solenoid_1);
TurnOn(do_Solenoid_2);
...
TurnOn(do_Solenoid_25);

// Turn on all solenoids with pointers.
for i_Index = 1 to 25 step 1

    // Convert numeric index to string.
    NumberToString(i_Index, s_Index);
    TrimString(s_Index, 3);

    // Create variable containing the name of the solenoid to turn on.
    s_SolenoidName = "do_Solenoid_" + s_Index;

    // Get a pointer to the named solenoid.
    GetPointerFromName(s_SolenoidName, pdo_Solenoid);

    // Turn on the solenoid.
    TurnOn(*pdo_Solenoid);

next

The code there with pointers is a bit cumbersome for this simple example, but consider when you expand your system and you have 200 solenoids instead of 25. Change the range of your for loop with the pointer solution, and you’re done. With the non-pointer solution, you have to add another 175 lines of code. In many real-world cases, you’re not simply going to turn things on like that, but you’re going to check to see if something is enabled, set status indicators, etc. In that case, each of the 25 solenoids requires an entire block of code, so the whole system requires 25 blocks of code without pointers. With pointers, there’s a bit of additional overhead to assign the pointers, but then you have one block of code that works the same way for all units.

3 Likes

@varland This is a great explanation and example provided in using pointer for program! Appreciate it and will take time digest and try with it. Thank you.