5  Number Systems and Data Units

In 60 Seconds

IoT systems use three number systems: binary (base-2, what computers use), decimal (base-10, what humans use), and hexadecimal (base-16, compact binary notation where each digit represents 4 bits). Understanding data sizing – bits, bytes, and word sizes (8/16/32/64-bit) – is critical because choosing the wrong data type causes overflow bugs.

Chapter Scope (Avoiding Duplicate Deep Dives)

This chapter is the number systems and data units foundation.

5.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Convert between number systems: Translate values between binary, decimal, and hexadecimal using positional notation
  • Explain data sizing fundamentals: Describe the relationship between bits, bytes, and word sizes in IoT processors
  • Interpret protocol specifications: Identify and decode hexadecimal values in datasheets, registers, and protocol documentation
  • Select appropriate data types: Evaluate sensor value ranges and select correct integer sizes to prevent overflow
  • Calculate number system equivalents: Apply step-by-step conversion methods to verify binary-hex-decimal representations
No-One-Left-Behind Number Loop
  1. Convert one value manually across decimal, binary, and hex.
  2. Tie that value to a real register or packet field.
  3. Pick a data type and validate min/max range.
  4. Confirm with one worked example before moving on.

Computers think in binary – just ones and zeros – while we humans count in decimal (0-9). Hexadecimal (0-F) is a shorthand that makes long binary numbers easier for engineers to read. Understanding these three number systems is like learning to read a map in different languages: the territory is the same, but the representation changes. Once you get comfortable converting between them, reading sensor datasheets and protocol specifications becomes much easier.

Foundation Topics:

Apply These Concepts:

Learning Hubs:

5.2 Prerequisites

This chapter is an early foundation topic. You can read it with:

  • General familiarity with decimal numbers and basic arithmetic
  • No prior IoT, electronics, or programming experience required

5.3 Number Systems for IoT

⏱️ ~10 min | ⭐ Foundational | 📋 P02.C01.U01

Key Concepts

  • Binary is the machine format: Every register, packet field, ADC reading, and GPIO state reduces to bits, even when tools display decimal or hex.
  • Hex is the engineer’s shorthand: One hex digit always maps to 4 bits, so 0x9A is easier to inspect than 10011010 while preserving exact bit structure.
  • Byte width sets the range: An 8-bit unsigned value stores 0 to 255, while a 16-bit signed value stores -32,768 to 32,767; choosing the wrong width causes wrap-around bugs.
  • Signedness matters as much as size: Negative temperatures, motor angles, and altitude offsets need signed types; counters and percentages often do not.
  • Leading zeros carry meaning: 0x0A, 0xA, and 1010 can represent the same value, but fixed-width protocols often require the padded form to preserve field boundaries.
  • Datasheets mix notation constantly: Real hardware documentation jumps between decimal ranges, binary bit positions, and hexadecimal register examples, so fluent conversion is a practical debugging skill.
  • The review workflow is predictable: Read the width, read the base, identify signed vs unsigned, then check whether the value fits the chosen data type and byte order.

IoT systems work natively in binary, but engineers need to read and write values in decimal (human-friendly) and hexadecimal (compact binary representation). Understanding how to interpret the same value across these three number systems is fundamental to IoT development.

Conversion diagram showing the number 153 represented in three number systems: decimal (base 10) showing place values of 100, 10, 1; binary (base 2) showing 10011001 with place values from 128 down to 1; and hexadecimal (base 16) showing 0x99, with bidirectional conversion arrows between all three representations
Figure 5.1: Number system conversions showing the value 153 in decimal (base 10), binary (10011001, base 2), and hexadecimal (0x99, base 16) with conversion paths between them.

Analogy diagram comparing number systems to distance measurements. Top section shows three measurement units: Miles (orange, human-friendly, easy to estimate, like Decimal), Feet (teal, more precise, smaller units, like Binary), Yards (navy, convenient grouping, 3 feet = 1 yard, like Hex where 4 bits = 1 digit). Middle section shows same distance example: 0.5 miles = 2,640 feet = 880 yards. Bottom section shows number system parallel: Same value 15 in Decimal 15, Binary 1111, Hex F. Dotted lines connect each measurement unit to the parallel, illustrating that different representations express the same underlying quantity.

Alternative view: Measurement System Analogy - Just as miles, feet, and yards are different units for the same distance, decimal, binary, and hex are different notations for the same value. Miles are convenient for everyday use (like decimal for humans). Feet give more precision (like binary for computers). Yards group feet conveniently (like hex groups 4 binary bits). The key insight: none is “better” - each serves a purpose.
Figure 5.2

5.3.1 Decimal (Base 10) - What Humans Use

Decimal uses digits 0-9. Each position represents a power of 10:

  1   5   3
  ↓   ↓   ↓
100  10   1   (positions)
10²  10¹  10⁰ (powers of 10)

153 = (1 × 100) + (5 × 10) + (3 × 1) = 153

5.3.2 Binary (Base 2) - What Computers Use

Binary uses only digits 0 and 1. Each position represents a power of 2:

  1   0   0   1   1   0   0   1
  ↓   ↓   ↓   ↓   ↓   ↓   ↓   ↓
128  64  32  16   8   4   2   1   (values)
2⁷   2⁶  2⁵  2⁴  2³  2²  2¹  2⁰  (powers of 2)

10011001 = 128 + 16 + 8 + 1 = 153
Binary Notation in Code
  • C/Arduino: 0b10011001 (prefix 0b)
  • Python: 0b10011001 (prefix 0b)
  • Documentation: 10011001₂ or just 10011001 (context)

5.3.3 Hexadecimal (Base 16) - Human-Friendly Binary

Hexadecimal uses digits 0-9 and letters A-F (representing 10-15):

Decimal Binary Hex
0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F

Why Hex? Each hex digit represents exactly 4 binary bits, making conversion easy:

Binary:  1001 1001
         ↓    ↓
Hex:      9    9   = 0x99

Binary:  1111 1010
         ↓    ↓
Hex:      F    A   = 0xFA

Binary-to-hex conversion for an 8-bit sensor value: Your temperature sensor outputs the binary value 11001010. Convert to hexadecimal:

Step 1: Split into 4-bit groups (nibbles) \[\text{Binary: } 1100 \quad 1010\]

Step 2: Convert each nibble to decimal - Left nibble: \(1100_2 = (1×8) + (1×4) + (0×2) + (0×1) = 12_{10}\) - Right nibble: \(1010_2 = (1×8) + (0×4) + (1×2) + (0×1) = 10_{10}\)

Step 3: Convert decimal to hex - 12 in hex = C - 10 in hex = A

Result: 11001010 binary = 0xCA hexadecimal = 202 decimal

Why this matters: Reading raw sensor registers often shows 0xCA instead of the decimal value 202. Knowing hex lets you quickly verify: “CA is 1100-1010, so bit 7 is HIGH, bit 6 is HIGH, bit 5 is LOW…” for debugging sensor configuration.

Real-World Example: Smart Meter Data Encoding

Scenario: A smart meter measures 1,234.56 kWh and needs to send this reading to the utility company via LoRaWAN (limited to 51 bytes per message).

IEEE 754 Single-Precision Float (32-bit):

  • Decimal value: 1,234.56
  • Binary representation: 01000100 10011010 01000111 10101110
  • Hexadecimal: 0x449A47AE (4 bytes)

Byte breakdown:

  • Byte 0: 0x44 (sign + exponent high bits)
  • Byte 1: 0x9A (exponent low bits + mantissa high bits)
  • Byte 2: 0x47 (mantissa middle bits)
  • Byte 3: 0xAE (mantissa low bits)

Comparison with text:

  • Float binary: 4 bytes → 0x449A47AE
  • Text ASCII: 8 bytes → "1234.56" (7 characters + null terminator in C strings)
  • Savings: 50% bandwidth using binary encoding

Why this matters: With 10,000 meters sending readings every 15 minutes, binary encoding saves 1.92 GB/day compared to text, reducing network congestion and energy consumption.

Important: When transmitting multi-byte values like this float, the byte order (endianness) matters - see Bitwise Operations and Endianness for details.

Hexadecimal Notation in Code
  • C/Arduino: 0x99 or 0xFA (prefix 0x)
  • Python: 0x99 or 0xFA (prefix 0x)
  • Documentation: 99h, 0x99, or $99

5.3.4 Conversion Practice

Converting between number systems is a fundamental skill for IoT development.

Interactive Number System Converter

Manual conversion examples:

Binary to Decimal: Add the values where there’s a 1:

  • 1010 = 8 + 2 = 10
  • 11111111 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255

Decimal to Binary: Find the largest power of 2 that fits, subtract, repeat:

  • 25 = 16 + 8 + 1 = 11001
  • 100 = 64 + 32 + 4 = 1100100

Hex to Binary: Replace each hex digit with 4 binary bits:

  • 0x3F = 0011 1111
  • 0xA5 = 1010 0101

Binary to Hex: Group into sets of 4 bits, convert each group:

  • 11010110 = 1101 0110 = 0xD6
  • 10111001 = 1011 1001 = 0xB9

Quick Check: Test your understanding of binary-to-hexadecimal conversion:

Common Misconception: “Hexadecimal is Just Another Programming Language”

Myth: “I need to write IoT code in hexadecimal”

Reality: Hexadecimal is a notation system for numbers, not a programming language!

What hexadecimal actually is:

  • A way to write numbers more compactly than binary
  • Used in code to represent values: uint8_t led_pin = 0x0D; (same as 13)
  • Common in hardware registers, MAC addresses, memory addresses

You don’t program in hex - you use it to express values:

// All three lines do EXACTLY the same thing:
uint8_t status = 177;        // Decimal notation
uint8_t status = 0xB1;       // Hexadecimal notation
uint8_t status = 0b10110001; // Binary notation

// The CPU doesn't care - it's all binary internally!

When you’ll see hex in IoT:

  • Reading datasheets: “Register 0x1A controls I2C speed”
  • Debugging serial output: Received: 3F A2 01 FF
  • MAC addresses: 00:1A:2B:3C:4D:5E
  • Memory addresses: Flash at 0x08000000

Practical tip: Use hex for hardware values (clearer bit patterns), use decimal for sensor readings (human-friendly). Both are just different ways to write the same numbers!


5.4 Bits, Bytes, and Data Units

⏱️ ~8 min | ⭐ Foundational | 📋 P02.C01.U02

Understanding data sizing is critical for IoT development, where memory is limited and every byte counts.

5.4.1 The Bit - Smallest Unit

A bit (binary digit) is the smallest unit of data in computing: - Can hold only two values: 0 or 1 - Represents electrical states: OFF (0) or ON (1) - Foundation of all digital data

5.4.2 The Byte - Fundamental Building Block

A byte is a group of 8 bits. This is the standard unit for: - Memory addressing (RAM, flash storage) - Data transfer (serial communication, network packets) - File sizes (1 KB = 1,024 bytes)

Common Misconception: “Bigger Numbers Always Need More Bytes”

Myth: “A temperature reading of 2,500°C needs more bytes than 25°C”

Reality: The data type determines byte size, not the value itself!

Data Type Byte Size Min Value Max Value Example
uint8_t 1 byte 0 255 Can’t store 2,500 (overflow!)
uint16_t 2 bytes 0 65,535 Both 25 and 2,500 fit
int16_t 2 bytes -32,768 +32,767 Signed version
float 4 bytes ±1.2E-38 ±3.4E+38 Fractional values

Real consequence: Using uint8_t for a temperature sensor that measures 0-500°C will cause data overflow at 256°C:

uint8_t temp = 300;  // WRONG! Wraps to 44 (300 % 256)
uint16_t temp = 300; // CORRECT! Stores 300

Rule of thumb: Choose data types based on the maximum possible value, not typical values. A $50 sensor replacement due to overflow is expensive!

Byte structure with bit positions:

Byte structure diagram showing eight connected boxes representing individual bits arranged left to right. Bit 7 on the far left is labeled MSB (Most Significant Bit) with positional value 128, followed by bits 6 through 1 with decreasing powers of 2 (64, 32, 16, 8, 4, 2), and bit 0 on the far right labeled LSB (Least Significant Bit) with value 1. Dotted arrows connect each bit sequentially, illustrating how bits combine to form a complete byte with a range of 0-255 for unsigned integers.

Binary Byte Structure with MSB and LSB Bit Positions
Figure 5.3

One byte can represent:

  • Unsigned integers: 0 to 255 (2⁸ = 256 values)
  • Signed integers: -128 to +127 (two’s complement)
  • Single ASCII character: ‘A’ = 65, ‘Z’ = 90
  • Raw sensor reading: Temperature offset, status flags
Memory Terms in IoT
  • Kilobyte (KB/KiB): 1,024 bytes (2¹⁰) - IEC standard uses KiB (kibibyte) for binary units
  • Megabyte (MB/MiB): 1,048,576 bytes (2²⁰) - MiB (mebibyte) for binary
  • Typical IoT device: 32-512 KiB RAM, 256 KiB-4 MiB flash
  • Why 1024? Powers of 2 align with binary addressing

Note: Storage manufacturers often use decimal units (1 KB = 1,000 bytes), while memory/programming contexts use binary units. This explains why a “32 GB” SD card shows ~29.8 GiB in your operating system.

5.4.3 Word Sizes in IoT Processors

A word is the natural data size for a processor:

Processor Word Size Max Single Value Common Use
8-bit MCU 1 byte (8 bits) 255 Arduino Uno, ATmega328
16-bit MCU 2 bytes (16 bits) 65,535 MSP430, older PICs
32-bit MCU 4 bytes (32 bits) 4,294,967,295 ESP32, ARM Cortex-M
64-bit CPU 8 bytes (64 bits) 18 quintillion Raspberry Pi 4, desktop

Practical implication: On an 8-bit Arduino, adding two 32-bit integers requires multiple instructions, but on a 32-bit ESP32, it’s a single instruction. This affects processing speed and energy efficiency.


5.5 Knowledge Check

Knowledge Check: Binary and Hexadecimal Quick Check

Quick Check: Test your understanding of bit positions and hex-to-decimal conversion:

Quick Check: Match each number system concept to its correct definition:

Quick Check: Arrange the steps for converting a decimal number to hexadecimal in the correct order:


Common Mistake: Unsigned vs Signed Integer Overflow

The Problem:

Many IoT developers choose uint8_t (unsigned, 0-255) for temperatures because “temperatures are always positive” – then get nonsensical readings in cold climates.

Real Example:

// WRONG: Using unsigned for temperature
uint8_t temperature = -5;  // Trying to store -5C
Serial.println(temperature);  // Prints: 251 (not -5!)

What Happened?

Unsigned integers can’t store negative values. When you assign -5 to a uint8_t: - Computer stores it as 251 (two’s complement wrap-around: 256 - 5 = 251) - Your cloud dashboard shows “251°C” – clearly wrong!

Why This Matters in IoT:

Scenario Range Correct Type Wrong Type Problem
Outdoor temperature -40°C to +60°C int8_t (-128 to +127) uint8_t shows 216 for -40°C
Battery voltage 2.0V to 4.2V uint16_t (scaled x1000: 2000-4200) Safe (always positive)
Motor position -180° to +180° int16_t uint16_t shows 65356 for -180°
Altitude -500m to +9000m int16_t uint16_t shows 65036 for -500m

The Fix:

// CORRECT: Use signed integers for values that can be negative
int8_t temperature = -5;  // Stores -5C correctly
Serial.println(temperature);  // Prints: -5

// For wider range, use int16_t
int16_t temperature_precise = -423;  // -42.3C (x10 scaling)
float actual_temp = temperature_precise / 10.0;  // -42.3C

Decision Rules:

Data Type Range Use When
uint8_t 0 to 255 Percentages (0-100%), counters, always-positive values
int8_t -128 to +127 Temperatures, small signed values
uint16_t 0 to 65,535 Sensor readings, voltage (scaled), always-positive large values
int16_t -32,768 to +32,767 Position, altitude, signed large values
uint32_t 0 to 4.3 billion Timestamps, counters, uptime
int32_t -2.1B to +2.1B Large signed values

Real-World Debugging Story:

A smart city project deployed 500 outdoor air quality sensors. In winter, they reported “Temperature: 248°C” – buildings were evacuated! The bug: uint8_t couldn’t store -8°C. Cost: $50,000 in emergency response + reputation damage.

Prevention Checklist:


5.6 Concept Relationships: Number Systems and Data Types

Concept Relates To Relationship
Binary Hexadecimal Hexadecimal provides compact representation (each hex digit = 4 binary bits)
Binary Data Types Data types define how many bits store a value (8-bit, 16-bit, 32-bit, 64-bit)
Word Size Processor Performance 32-bit processors handle 32-bit integers in single instruction; 8-bit need multiple cycles
Data Type Range Overflow Bugs Choosing uint8_t for values >255 causes wrap-around (e.g., 300 becomes 44)
Endianness Multi-byte Values Byte order affects how 16/32-bit values transmit over networks - see Bitwise Operations

Cross-module connection: Number systems connect to Packet Structure via protocol header parsing, where fields are defined in hex (e.g., 0x7E delimiters, 0x04C11DB7 CRC polynomial).


Common Pitfalls

Values such as 0x0A, 00001010, and 10 may all describe the same quantity, but they do not communicate the same field width. In packet headers, register maps, and sensor payloads, dropping the leading zeros can hide which bits belong to which field and cause decoding mistakes.

A byte sequence can represent 251 or -5 depending on the chosen data type. If the firmware, gateway, and cloud decoder do not agree on signedness, winter temperatures, motor offsets, and calibration values become nonsensical even when the raw bytes are correct.

Developers often test with a comfortable value like 25 and pick uint8_t, then discover too late that a counter reaches 300, an ADC returns 4095, or a signed temperature dips below zero. Always size the type for the full operating range, not the first demo input.

5.7 Summary

Number systems and data units are the foundation of IoT programming:

  • Three Number Systems: Binary (base 2, computer-native), Decimal (base 10, human-friendly), Hexadecimal (base 16, compact binary notation)
  • Conversion Rule: Each hex digit = exactly 4 binary bits, making hex-to-binary conversion instant
  • Bits and Bytes: 1 bit = single 0 or 1, 1 byte = 8 bits (0-255 unsigned)
  • Word Sizes: 8-bit (Arduino), 16-bit (MSP430), 32-bit (ESP32), 64-bit (Raspberry Pi)
  • Data Type Selection: Choose based on maximum possible value, not typical values

Key Takeaways:

  • Hex is everywhere: MAC addresses, memory addresses, register values, protocol headers
  • Binary is what computers use, but hex makes it human-readable
  • Data overflow occurs when values exceed the data type’s range - a common IoT bug
  • Understanding these fundamentals is essential for reading datasheets and debugging


5.8 What’s Next

Continue building your data representation foundation:

Topic Chapter Description
Text Encoding Text Encoding for IoT Examine how ASCII, Unicode, and UTF-8 represent text characters in constrained IoT devices
Bitwise Operations Bitwise Operations and Endianness Apply bit manipulation techniques and interpret byte ordering in hardware registers
Data Representation Overview Data Representation Fundamentals Review the complete data representation topic map and identify areas to explore
Packet Structure Packet Structure and Framing Analyze how binary and hex values define protocol headers and delimiters
Data Formats Data Formats for IoT Compare JSON, CBOR, and binary encoding formats for efficient IoT data transmission
Sensor Circuits Sensor Circuits and Signals Explore how ADC resolution and data types affect sensor measurement accuracy

Sammy the Sensor holds up his hands. “I can only count to 1! Zero… one… that’s it!”

Max the Microcontroller laughs. “That’s binary! Computers think in zeros and ones – like light switches that are either OFF or ON.”

“But how do I count to 10?” asks Sammy.

Lila the LED shows him: “Stack up the switches! With EIGHT switches, you can count from 0 to 255. Like this:”

  • 00000001 = 1 (just the last switch ON)
  • 00000010 = 2 (second switch ON)
  • 00001010 = 10 (two switches ON: the 8-switch and the 2-switch!)
  • 11111111 = 255 (ALL switches ON!)

“But writing eight digits is SO long,” Sammy groans.

Max introduces hex: “That’s why we use HEXADECIMAL – a shortcut! Instead of writing 11111111, you write FF. Each hex letter stands for four binary switches. It’s like a nickname for binary!”

Bella the Battery adds: “And be careful choosing your number size! If you pick a tiny box (8 bits = 0 to 255) but your temperature is 300 degrees… OVERFLOW! The number wraps around and you get a wrong reading of 44. Always pick a box big enough for your biggest number!”

The Squad’s Rule: Binary is ON/OFF switches. Hex is the shortcut name. Always pick a big enough box for your numbers!