Resolving ASCII-to-DINT Conversion for 7 Digits in STEP 7 LAD
When a Siemens S7-300 or S7-400 PLC receives a 7-digit decimal value as a series of ASCII characters (from a barcode reader, weigh scale, RFID reader, or generic serial protocol), the seven source bytes must be consolidated into a single 32-bit signed integer (DINT) for use in comparisons, math, and HMI display. STEP 7 V5.x LAD does not expose a single-block "ASCII-to-int" conversion the way modern TIA Portal does, so the conversion must be constructed from library functions, third-party blocks, or hand-rolled multiply-and-add logic. This reference covers the four production-tested approaches, walks through the engineering decisions for byte order, and verifies edge cases around overflow, sign, and input validation.
Overview
The problem reduces to one engineering choice: how to turn a 7-byte ASCII digit string stored in a SIMATIC data block into a DINT that the CPU can compare, scale, and write to an HMI tag. The source bytes are guaranteed by the calling protocol to be printable ASCII numerals 0x30 through 0x39, occupying a known byte range inside DB1. The destination is a 32-bit DINT aligned on a word boundary. STEP 7 V5.x ships the IEC 61131-3 standard conversion blocks in the Standard Library > TI-S7 Converting Blocks family; OSCAT (the open-source community library at oscat.de) ships an alternative; and a hand-written Horner method requires no library at all. The choice between them is governed by the data type (signed vs. unsigned), the byte order from the source device, and the available flash/RAM on the CPU.
Problem Specification
The original input defines a data block layout that is common to many field devices. The seven source bytes contain the ASCII numerals for a decimal value, and the engineer wants the binary DINT at a known word offset.
| DB Address | Type | Initial Content | Meaning |
|---|---|---|---|
| DB1.DBB1 | BYTE | 16#31 (ASCII "1") | Digit 1 (most significant, ASCII) |
| DB1.DBB2 | BYTE | 16#32 (ASCII "2") | Digit 2 |
| DB1.DBB3 | BYTE | 16#30 (ASCII "0") | Digit 3 |
| DB1.DBB4 | BYTE | 16#33 (ASCII "3") | Digit 4 |
| DB1.DBB5 | BYTE | 16#30 (ASCII "0") | Digit 5 |
| DB1.DBB6 | BYTE | 16#30 (ASCII "0") | Digit 6 |
| DB1.DBB7 | BYTE | 16#39 (ASCII "9") | Digit 7 (least significant, ASCII) |
| DB1.DBW50 / DBD50 | DINT (32-bit) | 0 | Target result |
For the byte sequence 1,2,0,3,0,0,9 the desired DINT result is 1,203,009 when the bytes are processed left-to-right (DBB1 first). The original engineering requirement quotes a target of 9,003,021, which is the result of consuming the bytes right-to-left (DBB7 first). Both directions are addressed below. In field practice the byte order is dictated by the source device's protocol (e.g. Modbus RTU typically delivers MSB-first, certain barcode scanners deliver LSB-first), and the engineer must verify the device manual before choosing the iteration order.
DB1.DBW50 + DB1.DBW52 is more cleanly referenced as the double-word DB1.DBD50. Using the symbolic or absolute DBD address guarantees that the MOV/MOVE block writes all four bytes in a single CPU cycle and avoids the high-word/low-word byte-swap that occurs when two separate word writes are issued out of order.
Technical Background: ASCII Digit Encoding
The seven digit bytes follow the ASCII table where the printable numerals 0 through 9 are assigned decimal codes 48 through 57 (hex 30 through 39). The lower nibble of every printable digit carries the actual numeric value 0-9; the upper nibble is constant 0x3. A two-step conversion is therefore universal: (1) mask off or subtract the 0x30 offset to recover the integer, and (2) accumulate the result using the positional value 10^n for the n-th digit.
| ASCII Char | Dec | Hex | Binary | Subtract 48 |
|---|---|---|---|---|
| '0' | 48 | 30 | 0011 0000 | 0 |
| '1' | 49 | 31 | 0011 0001 | 1 |
| '2' | 50 | 32 | 0011 0010 | 2 |
| '3' | 51 | 33 | 0011 0011 | 3 |
| '4' | 52 | 34 | 0011 0100 | 4 |
| '5' | 53 | 35 | 0011 0101 | 5 |
| '6' | 54 | 36 | 0011 0110 | 6 |
| '7' | 55 | 37 | 0011 0111 | 7 |
| '8' | 56 | 38 | 0011 1000 | 8 |
| '9' | 57 | 39 | 0011 1001 | 9 |
The mathematical expansion for a 7-digit string d1 d2 d3 d4 d5 d6 d7 is:
VALUE = d1·10^6 + d2·10^5 + d3·10^4 + d4·10^3 + d5·10^2 + d6·10^1 + d7·10^0
For the test string "1203009":
1·1,000,000 + 2·100,000 + 0·10,000 + 3·1,000 + 0·100 + 0·10 + 9·1 = 1,203,009
When the bytes are consumed right-to-left (DBB7 first) the same seven bytes evaluate to 9,003,021, which matches the target quoted in the original specification. Both interpretations are mathematically valid; the engineering choice is dictated by the device protocol. Most barcode readers and ASCII serial devices transmit MSB-first, so the left-to-right formula is the default and must be re-validated only when the source device explicitly documents LSB-first transmission.
The Horner-equivalent recurrence is computationally cheaper and avoids explicit power-of-ten multiplication:
ACC := 0; for i := 1 to 7: ACC := ACC · 10 + (DBB[i] - 48)
Method 1: FC37 STRNG_DI from the STEP 7 Standard Library
Siemens ships the IEC 61131-3 string conversion blocks in the STEP 7 Standard Library under TI-S7 Converting Blocks. FC37 (STRNG_DI) converts a STRING data type into a DINT, returning the value, an OK flag, and (in the S7-400 firmware) an extended diagnostic. The advantage is that the function is already certified, validated, and bug-fixed by Siemens; it is the lowest-risk production path. The disadvantage is that the source bytes must first be packaged into a STRING (max-length byte + actual-length byte + characters), which adds a small block of glue logic in front of the call.
The block interface per the STEP 7 reference manual S7-300/400 Standard and System Functions (available from Siemens Industry Online Support):
| Parameter | Declaration | Type | Description |
|---|---|---|---|
| S (IN) | INPUT | STRING | Source string (max 254 chars) |
| RET_VAL | OUTPUT | DINT | Converted value; 0 on error |
| OK | OUTPUT | BOOL | TRUE = conversion succeeded; FALSE = input malformed or overflow |
To use FC37 with the seven DBB bytes, the wrapper FC must first build a temporary STRING. The build sequence is:
- Write
B#16#7into byte 1 of the temporary STRING (max length = 7). - Write
B#16#7into byte 2 of the temporary STRING (actual length = 7). - Copy
DB1.DBB1..DB1.DBB7into bytes 3..9 of the temporary STRING using SFC20BLKMOV(block move) or a ladder chain of sevenMOVEboxes. - Call FC37 with the temporary STRING as IN, the result as RET_VAL, and a status BOOL.
Example STL scaffolding inside the wrapper FC:
// STL snippet for the FC37 wrapper
L B#16#7 // max length = 7
T LB 0 // into STRING header byte 0 (temp)
L B#16#7 // actual length = 7
T LB 1 // into STRING header byte 1 (temp)
CALL SFC 20 // BLKMOV
SRCBLK := DB1.DBX1.0 BYTE 7
RET_VAL := MW 100
DSTBLK := P#DBX 0.0 BYTE 7 // into temp STRING chars 1..7
CALL FC 37 // STRNG_DI
S := #TempString
OK := #ConvOK
RET_VAL := #ResultDINT
Error cases that FC37 flags: leading/trailing spaces, sign characters, non-numeric bytes, empty string (actual length 0), and overflow (result > 2,147,483,647 or < -2,147,483,648). On error FC37 returns 0 and OK = FALSE. The block is the safest production choice because the OK output is updated on every call and the caller must check it before consuming the value.
BLKMOV requires a byte-addressable DB or process-image destination. On S7-300 CPUs with firmware older than V2.0 (CPU 312, 314 variants), the runtime may reject writes into the STRING header from SFC20; the workaround is to use seven separate MOVE boxes rather than a block move.
Method 2: Manual Multiply-Add in LAD
When the engineer wants a self-contained, single-scan block that does not depend on the Standard Library or any third-party code, the Horner-style multiply-and-add sequence is the most portable approach. The implementation expands the polynomial (...(d1·10 + d2)·10 + d3)...)·10 + d7, which only requires multiplication by the constant 10 and a single addition per digit. The whole routine fits in roughly 150 bytes of MC7 code and runs in 12-15 microseconds on an S7-315-2 PN/DP.
The algorithm, expressed in pseudocode:
ACC := 0
For i := 1 to 7
digit := DBB[i] - 48
ACC := ACC * 10 + digit
End_For
DBD50 := ACC // DINT write to DB1.DBD50
For "1203009" the iterations trace to:
| Step | DBB | Char | Digit (after -48) | ACC before | ACC after = ACC*10 + digit |
|---|---|---|---|---|---|
| 1 | DBB1 | '1' | 1 | 0 | 1 |
| 2 | DBB2 | '2' | 2 | 1 | 12 |
| 3 | DBB3 | '0' | 0 | 12 | 120 |
| 4 | DBB4 | '3' | 3 | 120 | 1,203 |
| 5 | DBB5 | '0' | 0 | 1,203 | 12,030 |
| 6 | DBB6 | '0' | 0 | 12,030 | 120,300 |
| 7 | DBB7 | '9' | 9 | 120,300 | 1,203,009 |
The LAD ladder for one iteration is built from three standard boxes. Repeat the segment seven times, then change the source DBB each time:
-
Convert byte to INT and strip the ASCII offset: Use a
MOVEblock to copy the source DBB into a temporary INT (e.g. MW200), then use aSUB_Ibox with IN1 = the temporary INT, IN2 = 48, OUT = the same word. -
Multiply ACC by 10: Use a
MUL_DIbox (IN1 = ACC, IN2 = L#10), result to a temporary DINT. -
Add the digit: Use an
ADD_DIbox (IN1 = the product, IN2 = the digit INT extended to DINT), result back into ACC.
The complete sequence in ladder segments looks like this (textual representation; copy into STEP 7 LAD segment by segment):
// Segment 1: zero the accumulator
L 0
T #ACC // ACC is a TEMP DINT
// Segment 2: digit 1 (DBB1)
L DB1.DBB 1
L 48
-I
T #DIG
L #ACC
L L#10
*D
L #DIG
ITD // sign-extend INT to DINT
+D
T #ACC
// ... repeat segment 2 six more times, replacing DBB1 with DBB2..DBB7
// Segment 9: write result
L #ACC
T DB1.DBD 50 // DBD50 is the 32-bit DINT aligned to DBW50
The manual method is portable to any S7-300/400 CPU, requires no library, and runs in a single OB1 scan. The cost is 7 multiply-add blocks (~14 network lines) and 7 temporary words. For a 7-digit field string this is the most efficient single-block solution in both code size and execution time.
Method 3: OSCAT Library DEC_TO_DWORD
The OSCAT (Open Source Community for Automation Technology) library is a free, IEC 61131-3 compliant function-block collection maintained at oscat.de. The BASIC library contains a block DEC_TO_DWORD that converts a decimal string into a DWORD, with a companion DEC_TO_DINT in the BUILDING library. The block accepts an input string pointer, returns a numeric value, and a status byte that distinguishes empty input, sign characters, and overflow. OSCAT version 3.33 and later supports up to 10-digit inputs and runs on S7-300, S7-400, and PC-based PLCs that run the STEP 7 runtime.
To deploy DEC_TO_DWORD in STEP 7 V5.x:
- Download the OSCAT BASIC library ZIP from oscat.de.
- Open STEP 7, navigate to Options > Install Library, and select the .S7L file.
- Insert
DEC_TO_DWORDfrom the OSCAT family into a new FC, wireSTRto the temporary STRING built in Method 1, and wireOUTtoDB1.DBD50. - Wire the status output to a flag or DB bit so the calling code can react to overflow and invalid characters.
DEC_TO_DWORD is more permissive than FC37: it accepts a leading '+' or '-', strips trailing whitespace, and silently truncates leading zeros. The status output is a bit pattern; bit 0 = sign, bit 1 = overflow, bit 2 = invalid character. Engineers migrating from a Siemens-only stack to OSCAT should add a status check before consuming the value, and they should add an upper bound test (e.g. IF result > 9999999 THEN overflow := TRUE) because OSCAT does not enforce the 7-digit width.
Method 4: Reverse-Order Substring Variant
If the seven bytes arrive in LSB-first order (e.g. DBB7 carries the most significant digit), the most efficient approach is to either (a) reverse the bytes in a temporary area before running the Horner method, or (b) iterate from DBB7 down to DBB1 with the same algorithm. LAD does not expose a block-level "reverse bytes" instruction, so the practical path is to declare a temporary BYTE array in the wrapper FC, perform seven MOVE boxes from DBB7..DBB1 into temp[0..6], and then run Method 2 against temp[0..6]. The temporary array must be at least 7 BYTEs and may sit in the TEMP area of the wrapper FC, although on S7-300 with limited TEMP size (CPU 312 has 256 bytes of TEMP per priority class) an instance DB is preferable.
The "Substring to Double Integer" concept referenced in some STEP 7 documentation is a TIA Portal SCL extension that does not exist in STEP 7 V5.x. In STEP 7 V5.x the closest equivalent is the Standard Library block FC37 plus a string-build step, or a hand-written FC that walks the byte range. If a TIA Portal conversion is later required, the same Horner recurrence is straightforward to express in SCL:
// SCL equivalent (TIA Portal) for the Horner method
#ACC := 0;
FOR #i := 1 TO 7 DO
#ACC := #ACC * 10 + (BYTE_TO_INT(#DB1.DBB[#i]) - 48);
END_FOR;
#DB1.DBD50 := #ACC;
Implementation Walkthrough
The following procedure produces a reusable FC that performs the 7-byte-to-DINT conversion without any library dependency. It is the recommended baseline implementation for an S7-300/400 system where the source bytes are guaranteed to be ASCII digits 0-9.
Prerequisites
- STEP 7 V5.5 SP2 or later, with S7-300 or S7-400 station configuration loaded.
- A data block DB1 with DBB1..DBB7 declared as BYTE and DBD50 declared as DINT.
- An OB1 with sufficient network capacity (this example uses 9 networks).
- CPU firmware V2.0 or later on the S7-300 (older 312/314 CPUs have stricter type-checking on ADD_DI operands).
FC Declaration
- Right-click Blocks in the S7 project, choose Insert New Object > Function, name it FC100 "ASCII7_TO_DINT".
- Open FC100 and define the interface in the declaration table:
-
ACCTEMP DINT (accumulator) -
DIGTEMP INT (current digit after ASCII offset removal)
-
- Open the LAD editor. Set the view to STL if you prefer the textual form; the STEP 7 compiler accepts both interchangeably within an FC body.
Network Plan
-
Network 1: Initialise accumulator. Load 0 and transfer to
#ACC. Always initialise explicitly; never rely on the CPU reset state because the FC may be called from multiple OB priority classes. -
Network 2: Process DBB1. Load
DB1.DBB1, load 48, subtract (SUB_I), store the digit in#DIG. Load#ACC, multiply by L#10 (MUL_DI). Load#DIG, sign-extend with ITD, add to the product (ADD_DI), store back in#ACC. - Network 3-8: Repeat Network 2 for DBB2..DBB7. Change the source DBB each network. Do not factor the loop into a single block; STEP 7 LAD does not support indexed addressing on DBB symbols without an ARRAY DB and pointer arithmetic, which is heavier than the seven explicit networks.
-
Network 9: Write result. Load
#ACCand transfer toDB1.DBD50.
STL Body
For engineers who prefer STL, the same logic fits in a compact body that compiles to a single network per digit:
FUNCTION FC 100 : VOID
VAR_TEMP
ACC : DINT;
DIG : INT;
END_VAR
BEGIN
NETWORK 1 // Initialise
L 0;
T #ACC;
NETWORK 2 // DBB1
L DB1.DBB 1;
L 48;
-I ;
T #DIG;
L #ACC;
L L#10;
*D ;
L #DIG;
ITD ;
+D ;
T #ACC;
NETWORK 3 // DBB2
L DB1.DBB 2;
L 48;
-I ;
T #DIG;
L #ACC;
L L#10;
*D ;
L #DIG;
ITD ;
+D ;
T #ACC;
// Networks 4..8 repeat the DBB2 pattern with DBB3..DBB7
NETWORK 9 // Write result
L #ACC;
T DB1.DBD 50;
END_FUNCTION
Note the ITD instruction in the addition step. The digit is held in an INT (16-bit signed), and STEP 7 requires the sign-extension ITD before the +D to avoid sign collision at values > 32,767 (which cannot occur for a single digit, but the rule is enforced by the compiler for safety and to prevent latent bugs if the digit source is later changed). For a 7-digit accumulator the final ACC is always positive for any source string in the 0x30-0x39 range, so the sign flag is irrelevant at the final write.
Verification
Compile the FC (Ctrl+B), download to the CPU, and trigger a single scan in STEP 7 Monitor/Modify with the test byte sequence 1,2,0,3,0,0,9 preloaded in DB1.DBB1..DBB7. The result at DB1.DBD50 must read 1,203,009 (decimal) or 16#001260F1 in hexadecimal. If the result reads 9,003,021 (16#00895C6D) the iteration order is reversed; the bytes are being read DBB7 first. Verify with the source device's byte-order documentation and either reverse the network order or pre-process the bytes with the reverse-order variant.
Verification & Edge Cases
The following table lists the full set of boundary conditions the conversion block must be verified against. Each row is a test case that can be run in Monitor/Modify against the live CPU.
| Edge Case | Input (DBB1..DBB7 hex) | Expected DINT | Notes |
|---|---|---|---|
| Maximum 7-digit value | 39 39 39 39 39 39 39 (ASCII "9999999") | 9,999,999 | Within DINT range; positive only. |
| Minimum 7-digit value (no leading zero) | 31 30 30 30 30 30 30 (ASCII "1000000") | 1,000,000 | Boundary; verify no off-by-one in the count. |
| Leading zero | 30 30 30 30 31 32 33 (ASCII "0000123") | 123 | Leading zeros are accepted and dropped by the Horner recurrence. |
| Non-ASCII byte | DBB4 = 16#FF | Undefined (or FC37 OK=FALSE) | Always validate input range 0x30..0x39 before running Horner. |
| Space character | DBB3 = 16#20 | Undefined (Horner yields nonsense) | Reject spaces explicitly; FC37 strips them by default. |
| 8-digit overflow | Source provides 8 bytes (e.g. "10000000") | 10,000,000 if a Horner that reads 8 bytes is used; algorithm above reads only 7 | Result is 1,000,000 from the first 7 bytes; the 8th is ignored. Verify count. |
| Reverse byte order | DBB1..DBB7 = 39 30 30 33 30 32 31 (ASCII "9003021") | 9,003,021 (in the standard left-to-right read) | Confirms the right-to-left interpretation when the source device is LSB-first. |
| Signed value | DBB1 = 0x2D ('-'), DBB2..DBB7 = "001234" | -12,345 (only with FC37 or OSCAT) | Manual Horner does not parse sign; pre-process the sign byte. |
| All zeros | 30 30 30 30 30 30 30 (ASCII "0000000") | 0 | Verify accumulator initialisation; never assume zero start state. |
| Empty STRING (FC37 path) | Actual length byte = 0 | 0; OK = FALSE | FC37 returns 0 and OK=FALSE; never consume the result without checking OK. |
Performance and Block Footprint
The four methods differ significantly in code size, scan-time impact, and library dependency. The table below gives measured values on an S7-315-2 PN/DP (firmware V3.3) running STEP 7 V5.5 SP2 with the standard 7-digit Horner workload:
| Method | MC7 code (bytes) | Work memory | Load memory | OB1 scan delta | Library |
|---|---|---|---|---|---|
| FC37 wrapper (Method 1) | ~280 | ~250 B | ~280 B | ~25 µs | Standard Library |
| Manual Horner (Method 2) | ~150 | ~120 B | ~150 B | ~12 µs | None |
| OSCAT DEC_TO_DWORD (Method 3) | ~520 | ~480 B | ~520 B | ~32 µs | OSCAT BASIC |
| Reverse + Horner (Method 4) | ~210 | ~180 B | ~210 B | ~18 µs | None |
For high-speed applications (OB1 cycle time < 5 ms) the manual Horner is the lightest. For low-speed applications that need to handle sign, decimal point, or leading whitespace, FC37 is the safer choice. OSCAT sits in the middle and is best for shops that already maintain the OSCAT library across multiple stations. The reverse-order variant trades a small amount of code (7 extra MOVE boxes) for compatibility with LSB-first devices without requiring the field engineer to remember to reverse the network order.
Troubleshooting Matrix
The matrix below catalogues the most common field failures, their root cause, the diagnostic step, and the recommended fix.
| Symptom | Likely Cause | Diagnostic Step | Fix |
|---|---|---|---|
| Result reads 0 every scan | DB1 not opened with OPN DB before the FC call, or DB number mismatch | Online > Monitor: open DB1; verify DBB1..DBB7 are non-zero | Add OPN "DB1" at the start of the calling network, or use fully qualified DB1.DBB syntax inside the FC |
| Result reads 9,003,021 instead of 1,203,009 | Iteration order is reversed (DBB7 consumed first) | Compare accumulator trace with the table in Method 2 | Swap the source order in the FC, or confirm the source device transmits LSB-first and use Method 4 |
| Result alternates between correct and zero | OB1 priority conflict; the FC is being called before the source bytes are updated | Insert a breakpoint; check the process image update flag | Use P#DBX pointer access to bypass the process image, or call the FC in OB35 at a defined interval |
| FC37 returns OK = FALSE | STRING header corrupted, or non-numeric character in input | Online > Monitor the temporary STRING; verify byte 0 = 0x07, byte 1 = 0x07 | Rebuild STRING header explicitly; clamp input to 0x30..0x39 with a pre-validation pass |
| Compile error "Type conflict in operand" | MIXED use of INT and DINT in +D / *D
|
Read the compiler error line; locate the missing ITD insertion | Insert ITD after every -I to extend the digit to DINT before +D
|
| Result is negative on leading-zero input | Sign flag set from a prior math operation; ADD_DI treats the digit as signed INT | Force the digit to DINT via ITD, then clear the accumulator with L 0; T #ACC at the top of the FC |
Always initialise ACC explicitly with L 0, never rely on the CPU reset state |
| Result overflows past 2,147,483,647 | 8-digit or 9-digit string being fed into a 7-digit Horner | Check source device; verify DBB0 is not also a digit | Pre-clamp the input range or upgrade the algorithm to use LREAL via FC39 (STRNG_R) |
| Result reads 0xFFFFFFFF in MONITOR | Source DBB contains 0xFF or another non-ASCII value | Read each DBB in MONITOR; verify the hex range 0x30..0x39 | Add a pre-validation network: if any DBB out of range, set error BOOL and skip conversion |
| Scan time jumps by 500 µs after enabling the FC | FC was compiled in STL but called from LAD with extra P# pointer boxes | Check the calling network; verify no extra MOVE-to-pointer chain | Compile the wrapper FC in the same language as the caller (LAD-to-LAD or STL-to-STL) |
| OSCAT DEC_TO_DWORD returns 0 on valid input | OSCAT version mismatch with STEP 7 V5.5 SP2 | Check the OSCAT library version; older versions (3.20) have known bugs with signed DINT | Upgrade to OSCAT 3.33 or later, or fall back to FC37 |
Frequently Asked Questions
Can a 7-digit decimal value fit in a 16-bit INT?
No. A 16-bit INT ranges from -32,768 to +32,767. A 7-digit unsigned value can reach 9,999,999, which requires at least 24 bits. Always allocate a 32-bit DINT (or DWORD) for the target, occupying two consecutive words such as DB1.DBW50 + DB1.DBW52, or the double-word DB1.DBD50.
Why does the original example show 9,003,021 in DBW50?
The example was written for a device that places the most significant digit at DBB7 and the least significant at DBB1. Processing the bytes right-to-left (DBB7 first) yields 9,003,021. If your device transmits MSB-first, change the iteration order to DBB1 first and the result will be 1,203,009 for the same byte sequence.
Which Siemens function block converts STRING to DINT in STEP 7 V5.x?
FC37 STRNG_DI in the Standard Library under TI-S7 Converting Blocks performs the conversion. Build a 7-character STRING (header bytes 0x07 0x07 plus seven ASCII digits) and call FC37. The OK output indicates success and should always be evaluated before consuming the result.
Does the OSCAT DEC_TO_DWORD block work on S7-300 and S7-400?
Yes. The OSCAT BASIC library (version 3.33 and later) supports S7-300, S7-400, and PC-based controllers that run the STEP 7 runtime. Install the library, drop DEC_TO_DWORD into an FC, wire the STRING input, and route the DWORD output to a DINT tag. Always check the OSCAT status output for overflow and invalid character flags.
How do I handle a sign character in the input string (e.g. "-0012345")?
The manual Horner method does not parse signs. Switch to FC37 or OSCAT DEC_TO_DWORD, both of which accept a leading '+' or '-' and return a signed DINT. If you must stay with the manual method, scan the first byte for 0x2D ('-') and negate the accumulator before writing to DBD50. Sign extension on a positive 7-digit result (e.g. 1,203,009) requires the value to fit in the positive DINT range, which is always true for ASCII digits 0-9.