TIA Portal Β· Deep Dive Β· The Reusable Blocks

Functions & Function Blocks

Every line of logic you write β€” and most of Siemens' β€” lives inside an FC or an FB. Learn the difference, where the built-ins live, and how to read every pin on the interface.

🧠 β€œDoes it need to remember anything?” β†’ FC if no, FB if yes.
FC
stateless
FB
has memory
7
interface sections
βž—
FC
Function Β· no instance
🧠
FB
Function Block Β· instance DB
01 Β· The cast

Two reusable blocks, one dividing line

TIA Portal gives you exactly two block types for writing reusable logic. They look identical in the editor β€” the difference is memory. A Function computes and forgets; a Function Block computes and remembers, because it owns a private instance DB. Everything else follows from that one fact.

βž—
FC
Function Β· German: Funktion

Inputs in, result out β€” like sqrt(x). It runs, returns a value, and keeps nothing. Call it a thousand times; each call starts from a clean slate.

βœ— no instance DB β€” forgets on return
  • Use forstateless maths, scaling, conversions, a CRC β€” anything that depends only on its inputs.
  • Has aReturn value (Ret_Val) β€” its single result.
  • NoStatic section. Nowhere to keep state.
  • Costsnothing in memory β€” no DB is generated, and its Temp vars are only borrowed from the call stack.
  • Watchif you find yourself wanting β€œlast scan’s value”, you have outgrown the FC. Promote it.
🧠
FB
Function Block Β· German: Funktionsbaustein

Behaviour plus a private instance DB. Its Static variables survive scan-to-scan, so it can hold a timer, a counter, a step number, a whole state machine.

βœ“ instance DB β€” remembers across scans
  • Use foranything stateful β€” motors, valves, sequences, timers, PID.
  • Has aStatic section that lives in the instance DB.
  • NoReturn value β€” it reports through Output pins instead.
  • Costsone instance DB per call site β€” 30 valves means 30 instances of the same one block.
  • Bonusan FB can hold other FBs in its Static section (multi-instance) β€” that is how whole machines get built.

Same idea you'll meet again as OB / FC / FB / DB in Blocks & Reuse β€” here we zoom all the way in on the two you actually write code in.

02 Β· Where blocks come from

Built-in instructions vs. blocks you create

Here's the part that confuses everyone: Siemens' built-in instructions are FCs and FBs too. A TON timer is a system FB; MOVE is a function. They sit in the Instructions task card, ready to drag in. The blocks you author live in Program blocks. Two sources β€” same two underlying types. Search by block or pin name, filter to just FBs or just FCs, and click any block to read its description and every pin it brings with it. Arrow keys walk the list.

πŸ“¦ Instructions SIEMENS-SUPPLIED
πŸ“ Program blocks YOU AUTHOR
FB Β· needs an instance DB (it remembers) FC Β· no instance (stateless) built-in your block

The takeaway: β€œbuilt-in vs yours” is about who wrote it; β€œFC vs FB” is about whether it remembers. Those are two independent questions β€” a built-in can be either, and so can your own.

03 Β· The interface β€” every name

Reading the block interface

Open any block and the top pane is its interface: rows of declarations grouped into named sections. These sections are the same in LAD, FBD and SCL β€” and they decide what shows up as a pin when you call the block. Flip between FC and FB and watch which sections appear; click a section to learn exactly what it does.

CALL SIGNATURE Β· SCL

          

Two sections do all the work of telling FC and FB apart: Static (FB only β€” the memory) and Return (FC only β€” the result). The other five are shared.

SectionFCFBWhat it is for
Inputβœ“βœ“Values handed in by the caller, read-only inside. Pins on the left.
Outputβœ“βœ“Results written back out. Pins on the right.
InOutβœ“βœ“By reference β€” edited in place, no copy. A pin on both sides.
Staticβœ—βœ“The memory. Lives in the instance DB and survives every scan.
Tempβœ“βœ“Stack scratchpad. Undefined at block start β€” write before you read.
Constantβœ“βœ“Named literals local to the block. Fixed at compile time.
Returnβœ“βœ—The Function’s single result value, like sqrt() β†’ Real.
04 Β· Structure

What a block actually looks like inside

Every FC and every FB β€” yours or Siemens' β€” is built from the same three layers: a header of properties, an interface of declarations, and a code section. Open a block and the editor splits exactly that way: declarations in the top pane, logic in the bottom. An FB adds a fourth layer an FC can never have β€” a generated instance DB. Here is the same kind of job written both ways.

βž— FC_Scale FC 1 Β· SCL
β‘  INTERFACE Β· the declaration pane
Inputraw : Int
lo, hi : Real
Outputallowed β€” unused here
InOutallowed β€” unused here
Staticdoes not exist in an FC
Tempspan : Real Β· scratch
ConstantRAW_MAX : Int := 27648
ReturnFC_Scale : Real ← the result
β‘‘ CODE SECTION Β· runs top to bottom, then returns
// # = block-local tag, "…" = global
#span := #hi - #lo;
#FC_Scale := #lo + #span
   * INT_TO_REAL(#raw) / #RAW_MAX;
βœ—No instance DB. #span sits on the local stack and is gone the moment the block returns β€” the answer leaves only through Return.
🧠 FB_Valve FB 5 · SCL
β‘  INTERFACE Β· the declaration pane
Inputopen : Bool
tOpen : Time
Outputdone : Bool
pos : Real
InOutrecipe : "UDT_Recipe" Β· by ref
Staticstep : Int ← survives the scan
tmr : TON_TIME ← multi-instance
Tempdt : Real Β· scratch
ConstantPOS_TOL : Real := 0.5
Returndoes not exist in an FB
β‘‘ CODE SECTION Β· resumes from the retained step
CASE #step OF
  0: IF #open THEN #step := 10; END_IF;
 10: #tmr(IN := TRUE, PT := #tOpen);
     IF #tmr.Q THEN #step := 20; END_IF;
 20: #done := TRUE;
END_CASE;
βœ“Instance DB "Valve_1". #step and the whole nested #tmr are stored there, so next scan the CASE picks up exactly where it left off.

β“ͺ Header & properties

Name, number (FC1, FB5), language (LAD / FBD / SCL / STL / GRAPH) and Optimized block access. Language is chosen per block β€” an SCL FB can call a LAD FC without a care.

β‘  Interface

The seven sections. This is the block's public contract β€” change a pin here and every existing call goes inconsistent until you update and recompile the callers.

β‘‘ Code section

One or more networks in LAD/FBD, or plain statements in SCL. Local tags are written #name; global tags and block names go in "quotes".

β‘’ Instance DB (FB only)

Generated for you the first time you call the FB. Its layout is the interface: Input, Output, InOut and Static laid out as real bytes you can watch online.

Read it as one sentence: the interface declares, the code section acts, and only an FB gets somewhere to keep what it learned. That is the whole structural difference.

05 Β· In and out

How the interface becomes pins

When you drop a block into your network, its Input and InOut declarations appear as pins on the left, its Output and InOut pins on the right. Data flows in β†’ the left and β†’ out the right. In SCL the two directions even get different operators: := feeds a value in, => pulls a result out. Here are three real calls β€” note that the two FBs demand an instance name, while the FC does not.

An InOut pin is special: it's passed by reference, so the block reads and writes your variable in place β€” no copy. That's how you hand a big UDT or array to a block efficiently, and it appears on both sides of the box.

06 Β· Going deeper

The nuances that separate a pro

"FC forgets, FB remembers" is the headline. Here's what actually trips people up:

🧠 Single- vs multi-instance

Call an FB and you must name its instance DB. Declare that instance as a Static var inside another FB and it nests β€” multi-instance. One TON living inside your FB needs no separate DB; its memory rides along in your instance DB.

βž— FCs can have outputs too

An FC isn't limited to one Return value β€” it can also have Output and InOut pins. The difference from an FB stays the same: no Static section, so nothing it computes survives the return.

βŒ› Temp is never zero by default

A Temp var starts each call with whatever garbage was on the local stack β€” not 0. Always write before you read it. This is the #1 source of "works sometimes" bugs in FCs.

πŸ” InOut for structures, always

Passing a large UDT or array by Input copies the whole thing every scan. Pass it as InOut (by reference) instead β€” faster, and the block can edit it in place. For FBs this is also how you share one data record between blocks.

πŸ“œ Optimized vs standard access

With Optimized block access on (the default on S7-1200/1500) the compiler decides the byte layout and you address everything symbolically. Turn it off and you get the old fixed offsets β€” needed only for legacy pointer tricks or absolute addressing.

⚠️ Change a pin, break the callers

The interface is a contract. Add or rename a parameter and every existing call goes red as inconsistent β€” and for an FB, its instance DBs need regenerating too. Design the interface before you write 30 calls, not after.

🏷️ One block, many instances

The code of an FB is downloaded once no matter how many times you call it β€” only the instance DBs multiply. Thirty valves cost you thirty small DBs and one block to maintain. That is the whole reason FBs exist.

07 Β· Check yourself

FC or FB?

You're writing a reusable valve controller that holds a TON timer and a step number, and you'll call it for 30 valves. Which block, and what does each call need?