If I pass a pointer to a function and in the function, I changed the content that the pointer points to, should this change be make at the caller function since I tried that and doesn't change as expected?
How do you typically go about Retain/Persistent variables while using FBs? Do you save the vars as Retain/Persist inside the FB itself, or inside a GVL and map it to the FB using a VAR_IN_OUT, or similar? I would like to store my retain/persistent vars inside the FB so each instantiation comes with the memory space required, however the outside program loses Write access when performed inside the FB. Thanks in advance for advising, and for the excellent tutorials!
I got somewhat burned long ago with the built in persistent Variable system and I wrote my own storage to a "binary blob". It worked but didn't handle restore to a data type that changed size, so we replaced it using the xml functionality from beckhoff. It was so much nicer to deal with. If you want you could use the database supplement but that is often overkill, a bit complicated, and like xml also costs extra money. These days, my main code base has a higher level HMI built in open source software, so we wrote a basic api with a key/value store, which writes to an sqlite database. Really depends on the budget and flexibility, etc, but I'd recommend the xml approach. I wish beckhoff didn't charge for it but it's worth it in your time vs the persistent/retain junk (imo)
Hello, There was an issue i was facing, it seems that when you commented bLoadPizza and bRemovePizza after adding the trigger in the function block the bLoadPizza and bRemovePizza variables in MAIN were not getting reset at all. Due to this i was not able to remove pizza after being baked. I then uncommented the two lines and then the visualization is working pretty fine. Would like others' opinion whether the way i did is correct or is there any other way that i am missing. Regards.
How do you assign a function block variable to use it in main? If i simply do MyVariable := fbMyFunctionBlock(some_inputs); I get "cannot convert unknown type to .......etc" Edit: I understand how they work now, but maybe this will help someone else. This is for built in function block DRAND: fbDRAND(Seed :=1); r_Num := fbDRAND.Num ; //To store output of function block DRAND to r_Num in Main program. //. Thanks for the great videos.
bharath Find the references manager in the tree and add them using the browse button (going from memory)... You can install supplements from beckhoff which are often in the form of libraries, you can create your own, or you can use public ones like oscat.
bharath Here is a better guide.... Open your PLC Project, then find the references folder. Right click it and go to "Add Library". From that window, click "Library Repository". There is probably another way to get there, but that works. On the library repository window, click "Install..." It will accept a compiled library, or a .lib file, etc. I belive behind the scenes, it just copies it to your system location (Twincat\3.1\components\plc\managed libraries\), so you could also just add a location or alternatively add your library to that folder manually and restart the project. I think any method works. Then it'll show up in the "Add library" browser window and you can click it and hit okay and it'll go into the references folder and you can use it.
You can't pick an array type when you create the POU, but you can just change it after the POU is made. I just tried this, and it to works: FUNCTION Word_To_BCD : ARRAY [0..7] OF BOOL VAR_INPUT MyInput : WORD; // Note: max 8 bits :) END_VAR VAR END_VAR Word_to_BCD[0] := MyInput.0; Word_to_BCD[1] := MyInput.1; Word_to_BCD[2] := MyInput.2; Word_to_BCD[3] := MyInput.3; Word_to_BCD[4] := MyInput.4; Word_to_BCD[5] := MyInput.5; Word_to_BCD[6] := MyInput.6; Word_to_BCD[7] := MyInput.7; RETURN; You could always return a pointer to an array as well, but no need to get into that complexity if you are just getting started with this stuff. At least watch the video on pointers first.
Sure... When you "clock" the r_trig funciton block, the first time it has a 'true' signal on the clock, it will set its .Q output to true, but only for one execution. After that one execution, it sets .Q back to 0 even if the clock bit is still set true. It won't turn .Q back on until it has been run with clock = false at least one scan. Here is an example... If you want to count parts going down a conveyor, and you have a sensor looking across. If your code said "If Part_On_Belt Then parts_made = parts_made + 1". That seems like it would work, but you'd be counting up "parts_made" the whole time that Part_On_Belt was true. That could be hundreds of times it was evaluated while that part was covering the sensor, which would not be accurate. So, to count just the "rising edge" of the part, you'd do: "my_rtrig(clk:=part_on_belt); if my_rtrig.Q then parts_made := parts_made + 1" That way, you count the part when you see it, but you won't count the next part until the clock signal has gone low, which means you saw the part exiting the sensor, and the r_trig got ready for the next part. Not to be confusing, but if you want'ed for some reason to count on the falling edge of a part, you could use an f_trig.
SquishyBrained Thank you i got it . So it is used for only counting the rising edge right? and i need the example in this video if you do the same way (9.42) how it run ? Sorry for my question i just start to learn it.
I don't understand the question. In the example, I just use it to make the button push only start a single pizza. The code is linked in the description if you want it.
+Ruben Gonzalez You can run the function like this: MyFunction(); Then FunctionResult := MyFunction.outputvalue; You can also do a more shorthand version: MyFunction(outputvalue=>FunctionResult); That will run the fuction and dump the value of outputvariable into the variable "FunctionResult".
13.53 I was genuinely excited. ✌️👌
I love your videos, thanks 😊
Really enjoyed it ! Learning by examples....great works.
It is very nice and useful. I really enjoyed.
If I pass a pointer to a function and in the function, I changed the content that the pointer points to, should this change be make at the caller function since I tried that and doesn't change as expected?
Excelent job
How do you typically go about Retain/Persistent variables while using FBs? Do you save the vars as Retain/Persist inside the FB itself, or inside a GVL and map it to the FB using a VAR_IN_OUT, or similar? I would like to store my retain/persistent vars inside the FB so each instantiation comes with the memory space required, however the outside program loses Write access when performed inside the FB. Thanks in advance for advising, and for the excellent tutorials!
I got somewhat burned long ago with the built in persistent Variable system and I wrote my own storage to a "binary blob". It worked but didn't handle restore to a data type that changed size, so we replaced it using the xml functionality from beckhoff. It was so much nicer to deal with. If you want you could use the database supplement but that is often overkill, a bit complicated, and like xml also costs extra money. These days, my main code base has a higher level HMI built in open source software, so we wrote a basic api with a key/value store, which writes to an sqlite database. Really depends on the budget and flexibility, etc, but I'd recommend the xml approach. I wish beckhoff didn't charge for it but it's worth it in your time vs the persistent/retain junk (imo)
thanks for your effort : )
Hello,
There was an issue i was facing, it seems that when you commented bLoadPizza and bRemovePizza after adding the trigger in the function block the bLoadPizza and bRemovePizza variables in MAIN were not getting reset at all. Due to this i was not able to remove pizza after being baked. I then uncommented the two lines and then the visualization is working pretty fine.
Would like others' opinion whether the way i did is correct or is there any other way that i am missing.
Regards.
How do you assign a function block variable to use it in main? If i simply do MyVariable := fbMyFunctionBlock(some_inputs); I get "cannot convert unknown type to .......etc"
Edit: I understand how they work now, but maybe this will help someone else. This is for built in function block DRAND:
fbDRAND(Seed :=1);
r_Num := fbDRAND.Num ; //To store output of function block DRAND to r_Num in Main program. //.
Thanks for the great videos.
twincat 3 creating issue on windows 10...please advise..
Arshad Khan whats your issue. Please describe. I will try to help
Hello,
Why don't I have as many libraries in the references structure? How can I include some non-existing library?
bharath Find the references manager in the tree and add them using the browse button (going from memory)... You can install supplements from beckhoff which are often in the form of libraries, you can create your own, or you can use public ones like oscat.
I don't see 'browse' feature in the list of functions of right click activity. Do you mean there is another way to bring in the libraries?
bharath Here is a better guide....
Open your PLC Project, then find the references folder. Right click it and go to "Add Library". From that window, click "Library Repository". There is probably another way to get there, but that works.
On the library repository window, click "Install..." It will accept a compiled library, or a .lib file, etc.
I belive behind the scenes, it just copies it to your system location (Twincat\3.1\components\plc\managed libraries\), so you could also just add a location or alternatively add your library to that folder manually and restart the project. I think any method works.
Then it'll show up in the "Add library" browser window and you can click it and hit okay and it'll go into the references folder and you can use it.
Nice tutorial. Just one thing, the camera needs to be refocused. Since EP7, code typed on screen become blurred.
Is it possible to have an array as a return type?
I think so, I'll try it and see.
You can't pick an array type when you create the POU, but you can just change it after the POU is made.
I just tried this, and it to works:
FUNCTION Word_To_BCD : ARRAY [0..7] OF BOOL
VAR_INPUT
MyInput : WORD; // Note: max 8 bits :)
END_VAR
VAR
END_VAR
Word_to_BCD[0] := MyInput.0;
Word_to_BCD[1] := MyInput.1;
Word_to_BCD[2] := MyInput.2;
Word_to_BCD[3] := MyInput.3;
Word_to_BCD[4] := MyInput.4;
Word_to_BCD[5] := MyInput.5;
Word_to_BCD[6] := MyInput.6;
Word_to_BCD[7] := MyInput.7;
RETURN;
You could always return a pointer to an array as well, but no need to get into that complexity if you are just getting started with this stuff. At least watch the video on pointers first.
Thanks man! You're a lifesaver
i don’t get R_trig can you describe it for me please
Sure... When you "clock" the r_trig funciton block, the first time it has a 'true' signal on the clock, it will set its .Q output to true, but only for one execution. After that one execution, it sets .Q back to 0 even if the clock bit is still set true. It won't turn .Q back on until it has been run with clock = false at least one scan.
Here is an example... If you want to count parts going down a conveyor, and you have a sensor looking across. If your code said "If Part_On_Belt Then parts_made = parts_made + 1". That seems like it would work, but you'd be counting up "parts_made" the whole time that Part_On_Belt was true. That could be hundreds of times it was evaluated while that part was covering the sensor, which would not be accurate. So, to count just the "rising edge" of the part, you'd do: "my_rtrig(clk:=part_on_belt); if my_rtrig.Q then parts_made := parts_made + 1"
That way, you count the part when you see it, but you won't count the next part until the clock signal has gone low, which means you saw the part exiting the sensor, and the r_trig got ready for the next part.
Not to be confusing, but if you want'ed for some reason to count on the falling edge of a part, you could use an f_trig.
SquishyBrained Thank you i got it . So it is used for only counting the rising edge right?
and i need the example in this video if you do the same way (9.42) how it run ? Sorry for my question i just start to learn it.
I don't understand the question. In the example, I just use it to make the button push only start a single pizza.
The code is linked in the description if you want it.
SquishyBrained Thamk you so much
Yeah, it sounds like "One Shot Rising" in Allen Bradley
How do you assign function outputs to variables?
+Ruben Gonzalez You can run the function like this:
MyFunction();
Then
FunctionResult := MyFunction.outputvalue;
You can also do a more shorthand version:
MyFunction(outputvalue=>FunctionResult);
That will run the fuction and dump the value of outputvariable into the variable "FunctionResult".
Not sure what I was thinking on this reply... just do this:
MyVariable := MyFunction(some_inputs);