ASCII recipe values and how a PLC sees an integer

7 min read · Published November 11, 2026

The text 125 reaches the PLC as the bytes 0x31, 0x32 and 0x35. Those are character codes, not the number. Convert the string with the controller's documented string-to-number instruction, validate characters and range first, and hold the last accepted value when a check fails.

A recipe column set to text does not send your controller a number. The characters that spell 125 travel as character codes, one byte per character. The controller holds exactly those bytes until your program converts them. That is why a recipe value typed as text can sit in an integer tag as a large unrelated number. The fix is not a tag type change but an explicit, validated conversion. This page walks through the byte values, a full conversion with the arithmetic shown, the checks that keep a mistyped entry out of the machine logic, and the boundary tests to run before the line uses the value.

Why does the PLC not see an ASCII recipe value as an integer?

Because ASCII stores characters, not numbers: the text 125 arrives at the PLC as three separate bytes, 0x31, 0x32 and 0x35 (decimal 49, 50 and 53), and those bytes do not become the integer 125 until a conversion instruction does the work on purpose.

The recipe transfer follows the data type configured for the column. A text column ships one character code per character; a numeric column ships a binary value. The receiving tag simply holds whatever bytes arrive. If the text 125 lands in a 16-bit integer tag unchanged, two characters can pack into one word: 0x3132 reads 12,594 and 0x3231 reads 12,849, depending on which end of the word the platform fills first. Neither is your setpoint.

If the tag reads blank or the characters arrive shuffled, byte order between panel and controller is a common cause, and the byte swap check for a blank string from a CompactLogix PLC shows how to pin it down.

What bytes does the text 125 arrive as?

The digits 0 through 9 occupy the ASCII codes 0x30 through 0x39, decimal 48 through 57, so each byte of the text 125 carries its digit in the last hex position, and one subtraction per character, code minus 0x30, recovers the digit.

ASCII gives each character its own code, and the decimal digits form one tidy block:

Character Code Decimal
1 0x31 49
2 0x32 50
5 0x35 53

The digit sits in the low nibble of every code in the block, which is why the subtraction works and why any code outside 0x30 to 0x39 fails the character check later. For how those bytes sit in 16-bit memory words at the controller, the walkthrough on packing an ASCII string into V-memory words shows a worked layout.

What does a worked example of the conversion look like?

A recipe field holding the text 125 converts to the integer 125 in five steps: read the field, check the characters, subtract 0x30 from each digit byte, assemble the place values, then range-check the result before anything writes it.

Scenario: the setpoint accepts 0 to 500, the panel sends a fixed 4-character field, and the operator types 125. The bytes arrive in the buffer as 0x31, 0x32, 0x35 and 0x20, the last byte being the space that pads the unused fourth character.

  1. Length check. The field is 4 bytes; the recipe allows 1 to 4 digits, and shorter entries pad with spaces. Pass.
  2. Character check. 0x31, 0x32 and 0x35 sit inside 0x30 to 0x39, and the trailing 0x20 is an allowed pad. Pass.
  3. Digit extraction. 0x31 - 0x30 = 1 (49 - 48 = 1); 0x32 - 0x30 = 2 (50 - 48 = 2); 0x35 - 0x30 = 5 (53 - 48 = 5).
  4. Place values. 1 x 100 + 2 x 10 + 5 x 1 = 100 + 20 + 5 = 125.
  5. Range check and write. 125 sits inside 0 to 500, so the program writes 125 to the active setpoint tag.

Three failures show the checks working:

  • The operator types 12A. The bytes are 0x31, 0x32, 0x41 and 0x20. 0x41, the letter A at decimal 65, fails the character check at position 3, so the entry is rejected, the fault bit is set, and the last accepted setpoint stays.
  • The field arrives empty. The length check rejects it before any character is examined.
  • The program reads the first two bytes as one 16-bit word and skips the conversion. It gets 12,594 or 12,849, never 125, which is why the cast step never appears in this path.

A value such as 1250 needs all four characters, and one lost character there would read 125, off by a factor of 10. That is the case the length check is for.

Which instruction converts the string to an integer in the PLC?

The conversion instruction is documented by your controller's maker, and you take it from that manual: Siemens documents S_CONV, STRG_VAL and VAL_STRG for the S7-1200, and Mitsubishi's MELSEC-F documentation lists its string control instructions.

Names and behavior change from one platform to the next, so use the status result the instruction reports and treat a failed parse the same as a failed check. The buffer length comes from the panel and controller documentation for the field, and a copy or move sized to the field puts the characters where the instruction expects them.

The reverse trip, showing characters held in integer words as text on the panel, is a separate problem; the article on mapping the PLC string file to display ASCII from integer words covers it.

How do you validate the string before the machine uses it?

Three checks gate the value: length, so a zero-length or truncated field is rejected; characters, so every byte is a digit code plus the sign character if negatives are allowed; and range, so the converted integer lands inside the recipe's process limits.

The length check matters most where truncation changes the value: a 4-digit entry of 1250 that loses its last character reads 125, off by a factor of 10, and nothing else in the buffer would tell you. The character check rejects letters and stray punctuation inside the number. The range check catches a valid number that is still wrong for the process, the kind of entry the character check happily passes.

Gate the write so the active setpoint updates only after all three checks pass and the conversion status is clean. On any failure, hold the last accepted value and raise a fault bit or a message the operator can see. To time that update against the panel's own write, the pattern in the article on catching an HMI recipe load with a PLC handshake tag does the timing cleanly.

How do you test the recipe transfer before trusting it?

Test with the machine in a safe state and walk five boundary cases: a known good value such as 125, the lowest permitted value, the highest permitted value, a blank entry, and an entry with one disallowed character, watching the PLC buffer and converted tag at each step.

For each case, watch both ends: the raw bytes in the buffer and the converted tag.

  • Known good 125: the buffer holds the digit codes and the converted tag reads 125.
  • Lowest permitted value: converts cleanly and passes the range check.
  • Highest permitted value: confirms the field is long enough for every digit the limit needs.
  • Blank entry: rejected by the length check, and the last setpoint stays.
  • Disallowed character: rejected by the character check, and the fault bit or message appears.

Save the project revision that passes every boundary case and write down the field format, the buffer mapping and the rejection behavior, so the next engineer does not rediscover the byte order by experiment. The safe state matters for the whole sequence: a rejected or unexpected value must not reach motion or heat while you watch the tags.

When should the recipe value be numeric instead of text?

If the recipe editor offers a numeric field type and its documented transfer type matches the PLC destination, use it: the panel then sends a number, and no conversion or validation code is needed on the controller side.

Field types are a property of the panel model and the editor version in the project, so open the recipe editor you actually have and look at the column's type list. If a numeric type exists, compare its documented transfer format with the destination tag before switching; a type or length mismatch can produce garbage or a failed transfer. Back up both projects before you edit the recipe definition or the conversion logic.

Recommendation: if the recipe column must stay text, keep the string in the controller, convert it with the controller's documented string-to-number instruction, and gate the result with length, character and range checks that hold the last accepted value on any failure. If the editor offers a numeric field whose documented transfer type matches the destination tag, switch to it and remove the conversion code.

Questions

What are the ASCII codes for the punctuation around a recipe number?

Digits occupy 0x30 to 0x39, decimal 48 to 57. The usual neighbors are the minus sign at 0x2D, the decimal point at 0x2E, the space at 0x20, carriage return at 0x0D and line feed at 0x0A, and the NUL byte 0x00, which often pads a fixed-length field. Decide which of these the field accepts, and make the validation list explicit.

Does changing the PLC destination tag to an integer type convert the text?

No. The tag's declared type does not change the bytes the panel sends. If the recipe column is configured as text, character codes arrive and the integer tag holds them unchanged, so it reads a large unrelated number or an error. Match the panel's documented transfer format to the destination, or add the conversion instruction.

Do string-to-number instructions handle signs and decimal points the same way?

No. Each controller defines its own behavior: some accept a leading sign, some stop at the first non-digit character, and a decimal point may be rejected or truncated to an integer. Read the instruction's entry in your controller's manual and set the field rules to match before you write the validation logic.

Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.

Keep reading

Build your signAsk for a quote