03
Number Systems and Codes
Inside every PLC, every number — every sensor reading, every counter, every error code — is just a pattern of 1s and 0s. Before we can program a PLC, we need to learn the four number systems engineers use to read and write those patterns: decimal, binary, octal, and hexadecimal. Then we’ll meet the special codes (BCD, Gray, ASCII) and finish with the maths PLCs do every scan.
What you’ll be able to do after this chapter
Your goals for this chapter:
- Convert any number between decimal, binary, octal, and hexadecimal — by hand, without a calculator.
- Explain BCD, Gray, and ASCII codes and recognise where each one is used in a real PLC.
- Define bit, byte, word, LSB, and MSB.
- Represent negative numbers using 2’s complement — and understand why it works.
- Add, subtract, and multiply binary numbers, and use 2’s complement to subtract.
- Add a parity bit for simple error detection.
- Read a 32-bit IEEE 754 floating-point number and explain why
0.1 + 0.2 ≠ 0.3on a computer.
Key Concepts & Terms
Figure 3.0 — Four Number SystemsThe same quantity dressed in four different costumes. Once you understand decimal, every other base follows the same rule: digit × position weight, then add.
The Decimal System — Where Everyone Starts
Let me start with something familiar. The decimal system is the one you’ve been using since you learned to count on your fingers. We call it “decimal” because it has ten symbols: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. The number of symbols always equals the base (also called radix) — and the largest symbol is one less than the base. Decimal’s base is 10, and the largest digit is 9.
Why bother going over decimal in a PLC chapter? Because decimal teaches us the rule that every number system follows: each digit’s value depends on its position. Each position carries a weight equal to the base raised to that position’s power, counting from 0 on the right. To find the value of the number, you multiply each digit by its weight and add it all up.
Worked Example 1
Decompose the decimal number 1962
The little subscript ₁₀ after a number is just a label that says “this number is in base 10”. Without the subscript, 1010 could be decimal one thousand and ten, binary ten, octal eight-eighty-eight, or hex four-thousand-one-hundred-sixty-eight — all different! Whenever you write a number in a PLC context, always tell the reader the base.
The same rule — digit × weight, then add — works for every other number system. Only the base changes. Let’s see binary next.
The Binary System — How a PLC Actually Counts
The binary system has the smallest possible base — 2. It uses only two symbols: 0 and 1. That’s it. No 2, no 7, no 9. Just zero and one.
Why electronic devices love binary
An electronic circuit is just a switch — it’s either letting current flow or it’s not. “Off” is 0; “on” is 1. A PLC has thousands of these tiny switches (transistors) inside its chips. Each one represents one binary digit. If we tried to use decimal (10 levels of voltage), the slightest electrical noise would corrupt the signal. With just two levels — clearly off or clearly on — even a noisy factory environment can’t fool the chip. Binary isn’t a choice; it’s a survival mechanism for digital electronics.
Each binary digit is called a bit (short for BInary digiT). Bits are packed into bigger groups:
- 1 byte = 8 bits (e.g.
11010110) - 1 word = 16 bits (in older PLCs) or 32 bits (in modern ones)
- 1 double-word = 32 bits or 64 bits
The rightmost bit is the least-significant bit (LSB) — it has the smallest weight. The leftmost bit is the most-significant bit (MSB) — it has the largest weight. The position weights are powers of 2: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, ...
Binary to Decimal — The “Multiply and Add” Method
To convert a binary number to decimal, write down the position weights, multiply each bit by its weight, and add up the results. Same rule as decimal.
Worked Example 2
Convert binary 10101101₂ to decimal
Notice we just skipped the bits that were 0 (they contribute nothing). Many engineers do this in their head with practice — just add up the weights of the positions where the bit is 1.
Decimal to Binary — The “Divide by 2” Method
Going the other way is a little less obvious but easy once you see the trick. Divide your decimal number by 2; the remainder (either 0 or 1) is the LSB. Divide the quotient by 2 again; the next remainder is the next bit. Keep going until the quotient hits zero, then read the remainders from bottom to top.
Worked Example 3
Convert decimal 173 to binary
And there’s our cross-check: 10101101₂ = 173₁₀, exactly the number we converted in Example 2. Whenever you can, verify a conversion by going both directions — it catches arithmetic mistakes.
Negative Numbers — How a PLC Stores Minus Signs
So far we’ve only worked with positive numbers. But PLCs deal with negative values all the time — temperature deviations, motor reverse direction, errors that overshoot a setpoint. So how do you store a minus sign in binary, when binary only has 0s and 1s?
Three different schemes have been used over the decades. Modern PLCs use the third one (2’s complement) — but you should know all three because they show up in spec sheets.
1. Sign-Magnitude — The Obvious One
Reserve the leftmost bit (the MSB) as the sign bit. 0 = positive, 1 = negative. The remaining bits hold the magnitude. Easy to read but it has two representations of zero (+0 = 00000000 and −0 = 10000000) and the arithmetic is messy.
2. 1’s Complement — The Stepping Stone
To negate a number, just flip every bit (0 → 1, 1 → 0). It still has two zeros, and addition needs a special “end-around carry” step that’s awkward in hardware.
3. 2’s Complement — The Modern Standard
To negate a number: flip every bit, then add 1. That’s it. Just two steps. With this scheme there’s only one zero, and — here’s the magic — the same hardware adder handles both addition and subtraction. Every modern PLC, microprocessor, and computer uses 2’s complement.
Why 2’s complement just works (a clock analogy)
Imagine a clock with only 4 hours instead of 12. The hours go 0, 1, 2, … 14, 15, then wrap back to 0. To go backward 5 hours, you can either subtract 5, or go forward by 16 − 5 = 11. The result is the same! That’s exactly what 2’s complement does for binary numbers — it turns subtraction into addition by going “all the way around” the clock. The only difference is the binary clock has 256 hours (for 8 bits), or 65,536 (for 16 bits).
Worked Example 4
Express −5 as an 8-bit 2’s complement number
Range of an 8-bit 2’s complement number
An 8-bit signed integer covers −128 to +127 — that’s 256 values total. The MSB still tells you the sign (0 = positive, 1 = negative), but the negative range goes one step further than the positive range because there’s only one zero. A 16-bit signed integer covers −32,768 to +32,767; a 32-bit signed integer covers about ±2.1 billion.
The Octal System — Mostly Historical
The octal system has base 8 and uses the symbols 0 through 7. Position weights are powers of 8: 1, 8, 64, 512, ...
You’ll mostly meet octal in older PLC documentation. Why? Because three bits map cleanly to one octal digit (since 2³ = 8). On legacy controllers like the Allen-Bradley SLC 500, I/O terminal numbers are octal — which means terminal “10” on an octal-addressed module is actually the 9th terminal, not the 10th, because 10₈ = 8₁₀. (This trips up beginners every time.) Modern PLCs have largely abandoned octal in favour of decimal addressing or named tags.
Worked Example 5
Convert octal 173₈ to decimal
Notice that 173₈ = 123₁₀, which is not the same as 173₁₀. Always read the subscript carefully — the same digits in different bases are completely different numbers.
The Hexadecimal System — Engineer’s Best Friend
The hexadecimal system (“hex” for short) has base 16. We have ten ordinary digits (0–9), but we need sixteen symbols. So hex borrows the letters A through F for the values 10 through 15:
| Hex | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Dec | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Hex is the binary shorthand of choice in modern PLCs — and you’ll see why in a moment. Four bits map cleanly to one hex digit (since 2⁴ = 16). A 16-bit word becomes just four hex digits, much easier to read than sixteen 1s and 0s. PLC error codes, status registers, Modbus addresses, and memory addresses are nearly always shown in hex, often with a 0x or $ prefix to mark the base.
Worked Example 6
Convert hexadecimal 2AF₁₆ to decimal and binary
Going from hex to binary is just a lookup — no arithmetic. Just replace each hex digit with its 4-bit binary group. That’s why engineers love hex: it’s binary they can actually read out loud.
Side-by-Side Comparison Table
Memorise this table — at least the first few rows. It will save you time on every conversion you ever do:
| Decimal | Binary | Octal | Hexadecimal |
|---|---|---|---|
| 0 | 0000 | 0 | 0 |
| 1 | 0001 | 1 | 1 |
| 2 | 0010 | 2 | 2 |
| 3 | 0011 | 3 | 3 |
| 4 | 0100 | 4 | 4 |
| 5 | 0101 | 5 | 5 |
| 6 | 0110 | 6 | 6 |
| 7 | 0111 | 7 | 7 |
| 8 | 1000 | 10 | 8 |
| 9 | 1001 | 11 | 9 |
| 10 | 1010 | 12 | A |
| 11 | 1011 | 13 | B |
| 12 | 1100 | 14 | C |
| 13 | 1101 | 15 | D |
| 14 | 1110 | 16 | E |
| 15 | 1111 | 17 | F |
Binary Coded Decimal (BCD) — Decimal Disguised as Binary
Sometimes industry needs to display decimal numbers directly — on a thumbwheel switch, on a seven-segment display, on a digital readout. Pure binary is awkward for this, because the binary representation of a decimal number has nothing to do with its decimal digit pattern.
The fix is Binary Coded Decimal (BCD): encode each decimal digit independently using its own 4-bit binary group. The 4-bit groups never go above 1001 (which is 9), so BCD wastes the codes 1010–1111 — they’re illegal in BCD.
Worked Example 7
Encode decimal 9527 as BCD
BCD is wasteful but practical. Thumbwheel switches and seven-segment displays speak BCD natively, so a PLC reading a thumbwheel just reads each digit’s 4 bits and lights up the corresponding segments. Modern PLCs include dedicated BCD-input and BCD-output instructions to handle the conversion automatically.
Gray Code — Where Only One Bit Changes at a Time
The Gray code (named after Frank Gray, who patented it in 1953) is a non-weighted binary code with one defining property: adjacent values differ by exactly one bit. Going from 5 to 6 in pure binary changes two bits (0101 → 0110). In Gray code, going from 5 to 6 changes only one bit (0111 → 0101). That single property makes Gray code the standard for absolute shaft encoders — the sensors that report the angular position of a rotating shaft.
Figure 3.1 — Why Gray Code Matters in EncodersIf a binary encoder’s reading head straddles the 0111 / 1000 boundary, four bits flip at once and the reading is briefly garbage (could be anything from 0000 to 1111). With Gray code, only one bit ever changes between adjacent positions — so even a misaligned head is at most one count off.
A simple way to remember why Gray code matters
Imagine you’re reading a digital odometer that’s rolling from 9999 to 10000. For a moment, all five digits are spinning at once — you might glimpse 19999, 90000, 80000, anything. With pure binary, the same thing happens at every 0111 → 1000 boundary, every 0011 → 0100 boundary, and so on. With Gray code, only one digit ever moves at a time, so even if you peek mid-transition, the worst you’ll see is the value just before or just after — never garbage.
The 4-Bit Gray Code Sequence
| Decimal | Binary | Gray | Decimal | Binary | Gray |
|---|---|---|---|---|---|
| 0 | 0000 | 0000 | 8 | 1000 | 1100 |
| 1 | 0001 | 0001 | 9 | 1001 | 1101 |
| 2 | 0010 | 0011 | 10 | 1010 | 1111 |
| 3 | 0011 | 0010 | 11 | 1011 | 1110 |
| 4 | 0100 | 0110 | 12 | 1100 | 1010 |
| 5 | 0101 | 0111 | 13 | 1101 | 1011 |
| 6 | 0110 | 0101 | 14 | 1110 | 1001 |
| 7 | 0111 | 0100 | 15 | 1111 | 1000 |
Trace your finger down the Gray column: each row differs from the previous by exactly one bit. That’s the magic of the code.
ASCII Code — How PLCs Read Letters
ASCII (American Standard Code for Information Interchange) is the universal code that maps printable characters and control codes to 7-bit binary numbers (0–127). When a PLC talks to a barcode reader, a printer, a serial display, or any modern industrial network, the text data flows as ASCII.
Each ASCII character occupies one byte in memory. The eighth bit is unused, used as a parity bit (see next section), or used to extend the code to support international characters.
Common ASCII Characters
| Char | Decimal | Hex | Binary | Char | Decimal | Hex | Binary |
|---|---|---|---|---|---|---|---|
| ‘ ‘ (space) | 32 | 0x20 | 0100000 | A | 65 | 0x41 | 1000001 |
| ‘0’ | 48 | 0x30 | 0110000 | B | 66 | 0x42 | 1000010 |
| ‘1’ | 49 | 0x31 | 0110001 | Z | 90 | 0x5A | 1011010 |
| ‘9’ | 57 | 0x39 | 0111001 | a | 97 | 0x61 | 1100001 |
| ‘?’ | 63 | 0x3F | 0111111 | z | 122 | 0x7A | 1111010 |
| CR (return) | 13 | 0x0D | 0001101 | LF (line feed) | 10 | 0x0A | 0001010 |
Useful patterns to memorise
Digits 0–9 are at decimal 48–57 (hex 0x30–0x39). Subtract 48 from any ASCII digit to get its numeric value. Uppercase letters A–Z are at 65–90 (hex 0x41–0x5A). Lowercase letters a–z are at 97–122 (hex 0x61–0x7A). The difference between a lowercase letter and its uppercase counterpart is always exactly 32 — flip bit 5 to switch case.
Parity Bit — Catching Single-Bit Errors
When binary data travels across a noisy channel — a long cable, a serial link, an industrial network — bits sometimes flip from 0 to 1 or vice versa due to electrical noise. The simplest way to detect such errors (note: detect, not correct) is the parity bit.
The idea is simple: append one extra bit to each data byte such that the total number of 1s in the augmented byte is either always even (even parity) or always odd (odd parity). The sender chooses the parity bit accordingly. The receiver counts the 1s and rejects any byte where the count doesn’t match.
Worked Example 8
Append the correct even-parity bit to 1011010
Parity catches any odd number of bit errors (1, 3, 5, …) but misses any even number (2, 4, …). It also tells you a byte is wrong but cannot tell you which bit. For better protection, modern systems use checksums or CRCs (cyclic redundancy checks) — but parity is still common on serial links and inside RAM chips because it’s the simplest and fastest possible error check.
Binary Arithmetic — How the CPU Does Maths
Inside the PLC’s CPU, every calculation — every ADD, SUB, MUL, DIV instruction — happens in binary. Let’s see how the four basic operations work. The good news: they follow exactly the same long-form rules you learned for decimal in primary school. Only the digit set is smaller (just 0 and 1) and the carry happens earlier.
Binary Addition
Four single-bit rules cover everything:
0 + 0 = 00 + 1 = 11 + 0 = 11 + 1 = 10(write 0, carry 1)
Just like decimal addition, you go right to left, propagating carries.
Worked Example 9
Add binary 1011 + 0110
Binary Subtraction by 2’s Complement
Direct subtraction with borrows works, but it’s awkward for the CPU’s hardware. Instead, the processor adds the 2’s complement of the subtrahend. The same adder hardware then handles both addition and subtraction. Here’s the trick in action:
Subtraction Example (Inline)
Compute 1011 − 0110 using 8-bit 2’s complement
Binary Multiplication
Each bit of the multiplier produces either a copy of the multiplicand (if the bit is 1) or all zeros (if the bit is 0), shifted left by the bit’s position. Then add up the partial products.
Multiplication Example (Inline)
Multiply binary 1101 × 101
Binary Division
Long division in binary works exactly like decimal long division, except every comparison is just “does the divisor fit?” — yes (write 1) or no (write 0). PLCs handle this automatically with a DIV instruction; you’ll rarely do it by hand.
Overflow — When the Result Doesn’t Fit
If the result of an addition or multiplication is too big to fit in the available number of bits, the operation produces an overflow. For an 8-bit signed register, 127 + 1 would yield 10000000 — which in 2’s complement is −128, not 128. The number wrapped around! PLCs raise an overflow status bit (often called S:0/0, S:OV, or similar) so your program can detect this and react. Always check overflow when working with counters, timers, and math instructions near their range limits.
Floating-Point Arithmetic — When Integers Aren’t Enough
Integer maths is fine for counting widgets and reading discrete sensors, but it can’t represent fractions like 3.14159 or very small/large numbers like 0.000001 or 1.23 × 10⁹. For those we need floating-point numbers.
Modern PLCs use the IEEE 754 single-precision standard — a 32-bit format with three fields:
Figure 3.2 — IEEE 754 Single-Precision LayoutOne sign bit, eight exponent bits (with bias 127 so the exponent can be both positive and negative), and twenty-three mantissa bits — for about 7 decimal digits of precision.
This format gives roughly 7 decimal digits of precision and a range from about ±1.2 × 10⁻³⁸ to ±3.4 × 10³⁸. That’s more than enough for nearly any industrial calculation — PID setpoints, scaling, engineering-unit conversions, control loop maths. For tasks that need more precision, larger PLCs also support double-precision (64-bit) floats with about 15 decimal digits.
Why 0.1 + 0.2 ≠ 0.3 on a computer
Try this in any language — Python, JavaScript, even your PLC’s Structured Text. Compute 0.1 + 0.2 and you’ll get something like 0.30000000000000004, not 0.3. Why? Because 0.1 in binary is a repeating fraction, just like 1/3 is repeating in decimal (0.3333…). The 23-bit mantissa can only store an approximation. Tiny rounding errors accumulate during arithmetic. This is why you should never compare two floats with = in a PLC program — use a tolerance band like |a − b| < 0.001 instead. Many real-world PLC bugs come from forgetting this rule.
Common Student Mistakes
Pitfalls to watch for in this chapter:
- Confusing BCD with pure binary. The number 9527 in BCD is
1001 0101 0010 0111, but in pure binary it is0010 0101 0011 0111— same bit count, different bit pattern. Always check which encoding you’re reading. - Forgetting the bias when reading IEEE 754. The exponent field stores
actual_exponent + 127. An exponent field of 130 means actual exponent130 − 127 = 3, i.e. multiply by 2³ = 8. - Reading 2’s complement as unsigned. The 8-bit pattern
11111011is 251 if interpreted as unsigned, but −5 if interpreted as 2’s complement. Always know the data type before you do anything with the bits. - Comparing floating-point numbers with
=. Use a tolerance band, not exact equality.0.1 + 0.2is not exactly0.3. - Confusing octal with decimal in legacy addresses. On older SLC 500 PLCs, terminal “10” on an octal-addressed module is actually the 9th terminal (because 10₈ = 8₁₀). Read the manual carefully.
- Mixing up MSB and LSB. The convention is leftmost = MSB, rightmost = LSB. Always confirm before doing manual conversions.
- Forgetting the subscript. Writing just
1010is ambiguous — could be decimal one thousand and ten, binary ten, octal eight-eighty-eight, or hex four-thousand-one-hundred-sixty-eight. Always add a subscript or prefix (0x,0b) so the reader knows the base.
Quick Recap
The eight things to remember from Chapter 3:
- The base of a number system fixes its digit set (10 for decimal, 2 for binary, 8 for octal, 16 for hex). Position weights are powers of the base.
- Binary is the PLC’s native language; hex is the human-friendly shorthand for binary in modern controllers.
- Negative numbers in modern PLCs use 2’s complement — invert all bits, then add 1. Same hardware adder handles both addition and subtraction.
- BCD encodes each decimal digit as its own 4-bit binary group — used for thumbwheel switches and seven-segment displays.
- Gray code changes only one bit between adjacent values — essential for absolute shaft encoders.
- ASCII maps printable characters to 7-bit codes; digits are at 48–57, uppercase at 65–90, lowercase at 97–122.
- A parity bit detects (but cannot correct) an odd number of bit errors during transmission.
- IEEE 754 single-precision stores a real number as 1 sign bit + 8 exponent bits + 23 mantissa bits — about 7 decimal digits of precision. Never compare floats with
=.
Review & Self-Assessment
Chapter 3 Review Questions
Try answering each question on your own before tapping to reveal the model answer. Several questions involve quick conversions — keep paper and pen handy.
Q1What is meant by the base of a number system, and what are the bases of decimal, binary, octal, and hexadecimal?+
Q2Convert binary 11010110 to decimal.+
1·128 + 1·64 + 0·32 + 1·16 + 0·8 + 1·4 + 1·2 + 0·1 = 128 + 64 + 16 + 4 + 2 = 214₁₀.Q3Convert decimal 200 to binary.+
11001000₂.Q4Convert hexadecimal 0xB7 to decimal and binary.+
B·16 + 7 = 11·16 + 7 = 176 + 7 = 183₁₀. Binary: B = 1011, 7 = 0111, so 1011 0111₂.Q5Why is hexadecimal preferred over octal for representing modern PLC data?+
Q6Express −9 as an 8-bit 2’s complement number.+
00001001. Invert: 11110110. Add 1: 11110111. Verify: 9 + (−9) should give 0. 00001001 + 11110111 = 100000000 — discard the 9th bit, leaving 00000000 = 0 ✓.Q7What is the BCD representation of decimal 4750?+
0100 0111 0101 0000.Q8Why is Gray code used in absolute shaft encoders rather than pure binary?+
Q9What ASCII character corresponds to decimal 65? And what is the ASCII code for the digit ‘7’?+
0x37 in hex).Q10Add the correct even-parity bit to the byte 11010010.+
11010010 = 4. The count is already even, so the parity bit is 0. Transmitted byte: 110100100 (9 bits, four 1s — still even).Q11Compute 1110 + 1011 in binary.+
11001₂ = 25₁₀ (which equals 14 + 11 ✓).Q12Why should you not test floating-point equality with = in a PLC program?+
A = B, use |A − B| < 0.001 (or whatever tolerance your application can accept).Stuck on a number-system conversion or PLC data type?
Get one-on-one tutoring or project guidance from Dr Ahsan Rahman — Head of Electrical Engineering, with extensive teaching experience across digital systems, PLCs, and industrial automation.