Code readingHow-to

CHAR array to STRING in a PLC data block: fill the two length bytes

Write the two STRING header bytes, then copy the CHAR array bytes in order behind them: the PLC recipe for CHAR[1..10] to STRING[10].

LumaSpec Vision10 min read Share on LinkedIn

On this page 9 sections
  1. 01A STRING is two length bytes plus your characters
  2. 02What the block needs before you write code
  3. 03Convert the CHAR array, step by step
  4. 04Worked example: scanner read LOT-4711-B into a STRING[10]
  5. 05Check the result online
  6. 06Why a plain byte copy shows garbage
  7. 07Shorter reads and several strings per cycle
  8. 08Before you download the block
  9. 09Questions

A fixed code reader hands the PLC its read one character at a time, and the characters pile up in a data block as an ARRAY[1..10] OF CHAR. The trouble starts at the display: you declare a STRING[10], move the ten bytes across, and the monitoring table stays empty or fills with junk. The characters were never the problem. A STRING carries two length bytes in front of its characters, and a plain byte move never writes them. This guide shows where those two bytes sit, the SCL that fills them on an S7-300/400 in SIMATIC Manager STEP 7 V5.6, and the online check that proves the block works, using the ten-character read a barcode scanner delivers.

A STRING is two length bytes plus your characters

There is nothing to convert. A CHAR and a character stored inside a STRING are the same eight-bit ASCII value; what a STRING adds is a two-byte header in front of them. The first byte holds the maximum length, the number between the brackets of STRING[10]. The second byte holds the current length: how many of those characters are valid right now. The characters follow from the third byte on, in arrival order, one byte each.

Byte Meaning Value for STRING[10]
0 Maximum length from the declaration 10
1 Current length, valid characters 10 for a complete read
2 to 11 Characters 1 to 10 in arrival order ASCII codes, one byte each
string_bytes(n) = n + 2 character_address(i) = string_start + 2 + (i - 1)

A STRING[10] therefore occupies 12 bytes in the data block. That is the whole secret: write the two header bytes, copy your CHAR bytes in behind them in order, and every tool that understands the type - the monitoring table, an HMI, string instructions - reads the result correctly. The byte-level mapping of a CHAR array onto this layout is drawn out in converting a CHAR array to a STRING in S7-300/400 data blocks.

What the block needs before you write code

  • The characters in one field: an ARRAY[1..10] OF CHAR, filled by whatever receive logic brings the reader's bytes in. How they arrive depends on the reader's interface - serial, USB and Ethernet each frame the data differently, a choice barcode scanner input methods to a PLC works through.
  • A target for the result: the STRING[10], 12 bytes. How CHAR and STRING fields sit in PLC memory generally - bytes, words and clears - is laid out in storing ASCII barcode strings in PLC memory.
  • A completion flag from the receive logic: a bit that says a full read has arrived. You will trigger the conversion on it.

On the reader side, any fixed code reader that sends each read out as ASCII characters over Ethernet fits the pattern: the characters arrive in a receive buffer and your logic walks them into the array.

Fixed code readersDual aviation plug fixed industrial barcode reader, 1.2 MP, focal length 12 mm (LS-CRD-0052)LS-CRD-0052
Resolution
Up to 3 MP
Shutter
Global
Interface
Ethernet
$559.00View part

Convert the CHAR array, step by step

The two header bytes cannot be written symbolically on a field of a global data block, so the clean route is a small SCL function block that overlays its own variables with byte views - AT views - and writes the header explicitly.

  1. Declare the storage and the byte views: ten characters, one STRING[10], and a byte view of each so single bytes can be addressed.
  2. Write both header bytes on every execution: maximum first, current second - 10 and 10 for a complete ten-character read.
  3. Copy the characters in order: character i lands at header offset 2 + (i - 1), which the loop does for you.
  4. Publish the result: bind the HMI to the block's STRING, or copy it into the global data block field.
  5. Trigger once per read: call the block on the completion flag, not on every scan.
  6. Compile and download, then run the online check in the next section.

The complete block, with example names you replace with your own:

FUNCTION_BLOCK "CharToString10"
VAR
    scanChars  : ARRAY[1..10] OF CHAR;    // filled by the receive logic
    scanString : STRING[10];              // the result an HMI can read
    charBytes   AT scanChars  : ARRAY[1..10] OF BYTE;   // the same ten bytes
    stringBytes AT scanString : ARRAY[0..11] OF BYTE;   // the same twelve bytes
END_VAR
VAR_TEMP
    i : INT;                              // loop index, 1 to 10
END_VAR
BEGIN
    stringBytes[0] := 10;                 // header byte 0: maximum length
    stringBytes[1] := 10;                 // header byte 1: current length
    FOR i := 1 TO 10 DO
        stringBytes[i + 1] := charBytes[i];
    END_FOR;
END_FUNCTION_BLOCK

If you would rather work in STL straight on the global data block, combining CHAR values into a STRING with STEP 7 STL walks the same twelve writes with load and transfer instructions.

Worked example: scanner read LOT-4711-B into a STRING[10]

The inputs, each with its source:

  • Ten characters in arrival order: L, O, T, -, 4, 7, 1, 1, -, B - an example payload with the same ten-character length the array holds.
  • The STRING[10] begins at byte 100 of its data block - an example offset; any 12 free contiguous bytes serve.
  • The header rule above, taken from the controller's string format: maximum length first, current length second.

The rule in words: reserve 12 bytes, write 10 and 10 into the first two, copy the characters behind them in order.

The arithmetic:

  • Size: 10 + 2 = 12 bytes, so the field runs from byte 100 to byte 111 and the next variable starts at byte 112.
  • Character 1 sits at 100 + 2 + (1 - 1) = byte 102; character 10 sits at 100 + 2 + (10 - 1) = byte 111.
  • ASCII codes: L is 76, O is 79, T is 84, - is 45, 4 is 52, 7 is 55, 1 is 49, the second 1 is 49 again, the second - is 45 again, B is 66.
Byte Value Read as
100 10 maximum length
101 10 current length
102 76 L
103 79 O
104 84 T
105 45 -
106 52 4
107 55 7
108 49 1
109 49 1
110 45 -
111 66 B

Result: the monitoring table shows LOT-4711-B, and an HMI field bound to the STRING shows the same ten characters.

The decision it leads to: with all ten characters valid, both header bytes get 10, and byte 101 is the only one that tracks the read. The day the reader returns eight characters, byte 101 becomes 8 while byte 100 stays 10 for the life of the declaration.

Check the result online

  1. Go online with the CPU and open the data block: the STRING field shows the ten characters as text.
  2. Switch the same field to a byte view: the two header bytes read 10 and 10, hex 0A 0A.
  3. Feed the finished string to the MAX_LEN instruction: it returns the maximum length of the string at its IN input as a number - 10 here.
  4. Bind an HMI text field to the string; the HMI side of that wiring is shown in two barcode scans into separate HMI data entry fields.

If the characters themselves come through wrong - shifted, duplicated or mixed with framing bytes - the fault is in the receive path, not the string. Garbage characters from a barcode scanner diagnoses that layer.

Why a plain byte copy shows garbage

Three ways this fails, and each tells you what happened:

  • Copy the ten bytes onto the STRING start address. The first two characters become the header: for LOT-4711-B a maximum length of 76 (L) and a current length of 79 (O). The current length now exceeds the maximum, and every reader of the type gives up - blank display or junk.
  • Copy into the character area but never write the header. A downloaded data block starts with both length bytes at zero, so the current length is 0 and the display stays empty even though all ten characters sit in memory.
  • Swap the two header bytes. While both read 10 nothing changes, which is why the bug hides. The first short read then declares a maximum of 8 with a current length of 10 - current above maximum again.

Shorter reads and several strings per cycle

Not every read fills the array. When the code length varies, count the characters as they arrive and stop at the frame's end characters - with most scanners a carriage return (13) and a line feed (10) - then write that count into byte 101. A STRING[10] holding eight characters simply reports a current length of 8; the two trailing character bytes are ignored until the next read overwrites them.

One reader delivering several codes per cycle needs several STRING fields - an array of STRING. The copy pattern is the same per element, and moving string data into an array of STRING tags covers the indexing.

Once the string displays, it becomes input for the rest of the program: split barcode string data into fields pulls lot and part numbers out of one read, and PLC ladder logic to compare barcode strings and count three reads qualifies repeated reads before the PLC accepts them.

Before you download the block

  • Both header bytes written on every execution, before the character copy.
  • Current length never above the declared maximum - 10 for STRING[10].
  • 12 bytes reserved for each STRING[10]; the next variable starts 12 bytes later.
  • The copy runs once per completed read, on the completion flag.
  • The online check done once, with a real read, before the HMI is trusted with the value.

Still choosing the reader that will fill the array? A compact Ethernet model of this class delivers its reads the same way: characters into a buffer, buffer into the CHAR array.

Fixed code readersHikrobot MV-ID3013PM-12M-WBN 12mm focal length 1.3 MP Compact Industrial Code ReaderMV-ID3013PM-12M-WBN
Interface
Fast Ethernet
Resolution
Up to 3 MP
Shutter
Global
Lens mount
M12
$1,979.00View part

Browse the fixed code readers finder filtered by interface, add code reader accessories such as lens covers and light boards when the mount is fixed, and bring anything unusual to the contact page for set-up help.

Questions

Why does the STRING stay empty even though the CHAR bytes are in the data block?

Because the current-length byte is still zero. Every tool that displays a STRING shows only as many characters as the second header byte declares; a freshly downloaded data block has both length bytes at zero, so the display stays empty while all ten characters sit in memory. Write 10 into the maximum-length byte and the valid count into the current-length byte, and the characters appear.

Can I copy the ten CHAR bytes straight onto the STRING start address?

No. The first two characters would then be read as the header. With a read starting LO, the maximum length becomes 76 and the current length 79, and a current length above the maximum marks the string as broken. Copy the characters to the character area, two bytes behind the field start, and write the two length bytes separately: maximum first, current second.

What if the scanner sends fewer than ten characters?

Write the valid count into the current-length byte and leave the rest of the character area as it is. A STRING[10] holding eight characters reports 8 as its current length; the two unused character bytes are ignored until the next read. Count characters up to the frame's end characters, with most scanners a carriage return (13) and a line feed (10), and never write a count above 10.

Does the two-byte header change how much space the STRING takes?

Yes. A STRING[n] occupies n + 2 bytes, so STRING[10] needs 12. A STRING declared without a length reserves 256 bytes, because it must be able to hold 254 characters plus the header. Declare the length you actually need: holding ten characters in a 256-byte field wastes data-block space on an S7-300.

Does the same layout apply to S7-1200 and S7-1500 controllers?

Yes. Those controllers store a string the same way: a two-byte header, maximum length then current length, followed by up to 254 character bytes of ASCII. Their instruction set adds string functions such as CONCAT, but CONCAT joins two strings of the STRING type; it does not take a CHAR array, so the byte-level header write remains the direct path there too.

Where can the STRING[10] sit inside the data block?

Anywhere 12 contiguous bytes are free. Declare it symbolically and let the compiler assign the offset, then read that offset before you write any absolute byte addresses against it. Two STRING[10] fields in a row sit 12 bytes apart; mixing symbolic placement with hand-counted offsets is the usual way a neighbouring variable gets overwritten.