Heidenhain TNC7 Klartext & Q-Parameters
The TNC7 is HEIDENHAIN's flagship control (the smaller TNC7 basic and TNC7 go run the same software platform), and its Klartext language is the closest thing in the CNC world to a real programming language: typed variables, structured IF/ELSE and FOR/WHILE blocks, string handling, and Python-style format strings — alongside the classic FN functions carried over from earlier TNCs. This reference covers what you need to write macros on a TNC7, drawn from the 81762x-20 (10/2025) manuals.
Program Structure
A Klartext program (file extension *.h) is a list of numbered NC blocks. The first and last blocks are BEGIN PGM / END PGM with the program name and unit of measure (MM or INCH) — the control inserts them automatically and you cannot delete them (a program without END PGM is considered incomplete). Between them: blank definition, tool calls, movements, cycles.
0 BEGIN PGM EXAMPLE MM ; Start of program
1 BLK FORM 0.1 Z X-50 Y-50 Z-20
2 BLK FORM 0.2 X+50 Y+50 Z+0 ; Workpiece blank definition (two NC blocks)
3 TOOL CALL 5 Z S3200 F300 ; Tool call
4 L Z+100 R0 FMAX M3 ; Straight-line traverse
...
11 M30 ; End the NC program
12 END PGM EXAMPLE MM ; End of program
Anatomy of a block: 4 TOOL CALL 5 Z S3200 F300 = block number + NC function; TOOL CALL is the syntax initiator, everything after it (5, Z, S3200, F300) are syntax elements. Always write the program as if the tool were moving — then it doesn't matter whether a head axis or table axis actually performs the motion. If you write programs off the control, spelling and element order must be exact.
Labels, Subprograms & Program Calls
Reusable machining goes into labels. LBL takes a number (0–65535) or a name up to 32 characters; LBL 0 marks the end of a subprogram and is the only label allowed to appear more than once.
| Function | Syntax | Notes |
|---|---|---|
| Within one program | ||
| Define label | LBL "UP1" … LBL 0 | Subprogram body; place it after the block with M2/M30, otherwise it runs once uncalled |
| Subprogram call | CALL LBL "UP1" | Jumps to label, returns at LBL 0; a subprogram cannot call itself; CALL LBL 0 is not permitted |
| Program section repeat | CALL LBL 1 REP2 | Repeats the section between LBL 1 and the call; total executions = REP + 1; up to 65 534 repeats; no LBL 0 |
| Calling other programs | ||
| Direct call | CALL PGM reset.h | Runs the external program in place; it must NOT contain M2/M30 (replace with an unconditional jump to a label before program end) |
| Variable call | SEL PGM "reset.h" … CALL SELECTED PGM | SEL PGM also accepts a QS parameter — this is how you call programs by computed name |
Maximum nesting depth: 19 for subprogram calls and 19 for external program calls (a CYCL CALL counts as one); program-section repeats can be nested without limit. Variables are global across CALL PGM — changes made in the called program come back with you; use QL or named parameters when you want values contained to one program. Guard against a missing called file with FN 18: SYSREAD ID10 NR110/NR111 at program start. A nested example from the manual:
0 BEGIN PGM UPGMS MM
...
11 CALL LBL "UP1" ; Call subprogram "UP1"
...
21 L Z+100 R0 FMAX M30 ; Last block of main program
22 LBL "UP1" ; Start of subprogram "UP1"
...
31 CALL LBL 2 ; Call subprogram 2 (one nesting level down)
...
41 LBL 0 ; End of "UP1"
42 LBL 2 ; Start of subprogram 2
...
51 LBL 0 ; End of subprogram 2
52 END PGM UPGMS MM
Q-Parameter Types & Ranges
Five variable types. Numerical parameters accept −999 999 999 to +999 999 999 (up to nine digits before the decimal point); QS strings hold up to 255 characters. Values are stored IEEE 754 binary — expect rounding at the tenth decimal place, which matters for jump conditions on computed values.
| Type | Scope | Range | Free for the user? |
|---|---|---|---|
| Q — numeric, global to all NC programs | |||
Q | Global (0–99 act locally inside macros/cycles; changes there don't come back) | Q0–Q99 | Yes — if no overlap with HEIDENHAIN SL cycles |
| Q100–Q199 | No — control special functions, readable (probe results, tool data) | ||
| Q200–Q1199 | No — HEIDENHAIN functions (cycles) | ||
| Q1200–Q1599 | No — machine-manufacturer functions | ||
| Q1600–Q1999 | Yes — user-defined | ||
| QL — numeric, local to the NC program | |||
QL | Local | QL0–QL499 | Yes — all user-defined |
| QR — numeric, global AND retained through power-off (backed up) | |||
QR | Global, nonvolatile | QR0–QR99 | Yes — user-defined |
| QR100–QR199 | No — HEIDENHAIN | ||
| QR200–QR499 | No — machine manufacturer | ||
| QS — strings, global | |||
QS | Global (0–99 local in macros/cycles) | QS0–QS99 | Yes — if no overlap with HEIDENHAIN cycles |
| QS100–QS199 | No — control special functions | ||
| QS200–QS1399 | No — HEIDENHAIN / machine manufacturer | ||
| QS1400–QS1999 | Yes — user-defined | ||
| Named parameters — local, like QL | |||
{NAME} | Local | Up to 31 chars, letters/digits/underscore, must start with a letter | Yes — numeric or string, e.g. {DEPTH} = -10 |
Q100–Q199 and Q1200–Q1399 can't even be edited in the Q parameter list window (Q info button). SET UNDEFINED assigns the undefined status — a positioning block using an undefined Q parameter is simply ignored, but using one in arithmetic stops program run with an error. Preassigned parameters worth knowing: Q100–Q107 PLC values, Q108 active tool radius, Q109 tool axis (−1 none, 0=X, 1=Y, 2=Z), Q110 last spindle M function (0=M3, 1=M4, 2=M5 after M3, 3=M5 after M4), Q111 coolant (1=M8, 0=M9), Q113 unit of measure (0=mm, 1=inch), Q114 active tool length, Q120–Q122 calculated A/B/C rotary coordinates.
Assignments & Arithmetic — FN 0–5 and Formulas
| Function | Example | Meaning |
|---|---|---|
| Basic arithmetic | ||
| FN 0: Assignment | FN 0: Q5 = +60 | Assign a value (or SET UNDEFINED) |
| FN 1: Addition | FN 1: Q1 = -Q2 + -5 | Sum of two values |
| FN 2: Subtraction | FN 2: Q1 = +10 - +5 | Difference of two values |
| FN 3: Multiplication | FN 3: Q2 = +3 * +3 | Product of two values |
| FN 4: Division | FN 4: Q4 = +8 DIV +Q2 | Quotient — division by 0 not allowed |
| FN 5: Square root | FN 5: Q20 = SQRT 4 | Root — negative values not allowed |
| Trigonometry & geometry | ||
| FN 6 / FN 7 | FN 6: Q20 = SIN -Q5 | Sine / cosine of an angle in degrees |
| FN 8: Root of sum of squares | FN 8: Q10 = +5 LEN +4 | c = √(a²+b²) — third side of a triangle |
| FN 13: Angle | FN 13: Q20 = +25 ANG -Q1 | arctan from opposite/adjacent side (0–360°) |
| FN 23 / FN 24: Circle data | FN 23: Q20 = CDATA Q30 | Circle center + radius from 3 (FN 23) or 4 (FN 24) points stored in consecutive parameters from Q30; results land in Q20/Q21/Q22 |
The Formula NC function packs several operations into one block with normal precedence (parentheses → sign → functions → ^ → * / → + −; chained powers evaluate right-to-left: 2^3^2 = 512). Available operators: + - * / ( ) SQ SQRT SIN COS TAN ASIN ACOS ATAN ^ PI LN LOG EXP NEG INT ABS FRAC SGN % (modulo). Note INT truncates — it does not round.
11 Q1 = 5 * 3 + 2 * 10 ; Result = 35
12 Q2 = SQ 10 - 3^3 ; Result = 73
13 Q4 = SIN 30 ^ 2 ; Result = 0.25 (function before power)
14 Q12 = 400 % 360 ; Result = 40 (modulo)
Part-family idiom straight from the manual — dimensions as variables, one value change per workpiece:
11 LBL "Z1"
12 FN 0: Q50 = +30 ; Cylinder radius
13 FN 0: Q51 = +10 ; Cylinder height
...
21 L X +Q50 ; Behaves like L X +30
Jumps & Conditions — FN 9–12 and Structured Control
| Function | Example | Jump when… |
|---|---|---|
| FN 9: IF EQU | FN 9: IF +Q1 EQU +Q3 GOTO LBL "UPCAN25" | values equal |
| FN 9: IS UNDEFINED / IS DEFINED | FN 9: IF +Q1 IS UNDEFINED GOTO LBL "UPCAN25" | variable undefined / defined |
| FN 10: NE | FN 10: IF +10 NE -Q5 GOTO LBL 10 | values not equal |
| FN 11: GT | FN 11: IF +Q1 GT +10 GOTO LBL QS5 | first value greater |
| FN 12: LT | FN 12: IF +Q5 LT +0 GOTO LBL "ANYNAME" | first value less |
The classic unconditional-jump trick — FN 9: IF+0 EQU+0 GOTO LBL1 — is how you skip over subprograms in a called program that isn't allowed to contain M30. But on the TNC7 you usually don't need FN jumps at all: the control has real structured control, and it indents the contained blocks for you. Conditions support ==, !=, <, >, <=, >= for numbers, and ==, !=, IN (substring, case-sensitive) for strings. One caveat: FN 9–12 jump commands are not allowed inside IF blocks or loops — the control errors out.
11 IF Q50 < Q60 ; Case analysis
...
21 ELSE IF Q50 > Q60
...
31 END IF
11 FOR Q50 = 4 TO 10 STEP 2 ; Counted loop (integers only)
...
21 END FOR
13 WHILE Q50 <= Q60 ; Conditional loop
14 Q50 = Q50 + +1
...
21 END WHILE
BREAK aborts the enclosing FOR/WHILE loop; CONTINUE skips to the next repetition — e.g. IF Q182 == +1 (probing says scrap) BREAK END IF. Program BREAK only inside a case analysis so the abort happens only in the intended case.
String Processing — QS Parameters
| Syntax element | Purpose | Example |
|---|---|---|
| Assignment | Assign text (also DECLARE STRING) | QS10 = "workpiece" |
|| | Concatenate strings | QS10 = QS12 || QS13 |
TONUMB | String → number | Q82 = TONUMB ( SRC_QS11 ) |
TOCHAR | Number → string | QS11 = TOCHAR ( DAT+Q50 DECIMALS3 ) |
SUBSTR | Copy substring | QS13 = SUBSTR ( SRC_QS10 BEG2 LEN4 ) |
INSTR | Find substring (returns char position, counting from 0; returns total length if not found) | Q50 = INSTR ( SRC_QS10 SEA_QS13 BEG2 ) |
STRLEN | String length (−1 if undefined) | Q52 = STRLEN ( SRC_QS15 ) |
STRCOMP | Lexical compare (0 identical, ±1 order) | Q52 = STRCOMP ( SRC_QS12 SEA_QS14 ) |
SYSSTR | Read alphanumeric system data (string twin of FN 18) | QS25 = SYSSTR( ID 10950 NR1 ) |
CFGREAD | Read a machine parameter via key/entity/attribute QS parameters | Q50 = CFGREAD( KEY_QS11 TAG_QS12 ATR_QS13 ) |
Format strings (requires code number 555343): the FMT syntax element embeds variables Python-f-string-style, killing most TOCHAR/concatenation chains: QS2 = FMT"ENJOY {QS1}{Q1}" → ENJOY TNC7. Formatting after a colon — {Q1:+.2f} gives a signed fixed-point number with two decimals; alignment/fill like {QS1:X>10}; types d e E f g G.
Error Output with FN 14
FN 14: ERROR interrupts program run (also in simulation) and shows a predefined message; the program must be restarted. 11 FN 14: ERROR=1000 displays “Spindle must be turning”. Number ranges:
| Error number | Dialog |
|---|---|
| 0–999 | Machine-dependent (defined by machine manufacturer) |
| 1000–2999 | Control-dependent, preassigned by HEIDENHAIN (e.g. 1000 “Spindle must be turning”, 1004 “Range exceeded”, 1014 “Touch point inaccessible”) |
| 3000–9999 | Machine-dependent |
| 10 000+ | Control-dependent |
The full preassigned list lives in the separate Overview of the Machine Parameters, Error Numbers and System Data document (ID 1445456-xx). Related: FN 38: SEND writes fixed/variable values to the log or an external app such as StateMonitor (FN 38: SEND /"Q1: %F" / +Q1, up to seven placeholders).
Worked Example — Part Counter Loop
From the manual: FUNCTION COUNT drives the control's built-in workpiece counter (shown on the PGM tab of the Status workspace, survives a restart, readable via FN 18: SYSREAD ID920 NR1). One shared counter serves Program Run and MDI — check before machining whether another program's counter is active.
11 FUNCTION COUNT RESET ; Reset counter value
12 FUNCTION COUNT TARGET10 ; Target count = 10 parts
13 LBL 11 ; Jump label
... ; Machining
21 FUNCTION COUNT INC ; Count this part
22 FUNCTION COUNT REPEAT LBL 11 ; Repeat until target reached
References
- HEIDENHAIN, TNC7 User's Manual — Programming and Testing, NC software 81762x-20, 10/2025, ID 1358773-24.
- HEIDENHAIN, TNC7 series — Overview of the Machine Parameters, Error Numbers and System Data, 10/2025, ID 1445456-xx.
Have a question or want to contribute?
Contact us with corrections, additions, or topics you'd like covered.
Get in Touch