46  Number Systems and Data Units

46.1 Learning Objectives

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

  • Convert between number systems: Translate numbers between binary, decimal, and hexadecimal
  • Understand data sizing: Explain bits, bytes, and word sizes in computing
  • Read protocol specifications: Interpret hexadecimal values in datasheets and protocol docs
  • Choose appropriate data types: Select correct integer sizes for IoT sensor values

Foundation Topics: - Data Representation Fundamentals - Overview and index - Text Encoding for IoT - ASCII, Unicode, and UTF-8 - Bitwise Operations and Endianness - Bit manipulation and byte ordering - Packet Structure and Framing - How data is packaged - Data Formats for IoT - JSON, CBOR, and binary formats

Apply These Concepts: - Networking Basics - Network fundamentals - Sensor Circuits and Signals - Signal processing - Prototyping Hardware - Microcontroller programming

Learning Hubs: - Quiz Navigator - Test your understanding - Simulation Playground - Interactive tools

46.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

46.3 Number Systems for IoT

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

IoT systems constantly convert between three number systems: decimal (human-friendly), binary (computer-native), and hexadecimal (compact representation).

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor':'#2C3E50','primaryTextColor':'#fff','primaryBorderColor':'#16A085','lineColor':'#16A085','secondaryColor':'#E67E22','tertiaryColor':'#7F8C8D','background':'#ffffff','mainBkg':'#2C3E50','secondBkg':'#16A085','tertiaryBkg':'#E67E22','textColor':'#2C3E50'}}}%%
graph TD
    Value["Same Value<br/><b>153</b>"]

    subgraph Decimal["Decimal (Base 10)"]
        D["<b>153</b><br/>Human-friendly<br/>Uses: 0-9"]
    end

    subgraph Binary["Binary (Base 2)"]
        B["<b>10011001</b><br/>Computer-native<br/>Uses: 0, 1"]
    end

    subgraph Hex["Hexadecimal (Base 16)"]
        H["<b>0x99</b><br/>Compact binary<br/>Uses: 0-9, A-F"]
    end

    Value --> D
    Value --> B
    Value --> H

    D <-->|"Convert"| B
    B <-->|"Group by 4"| H
    D <-->|"Lookup"| H

    style Value fill:#E67E22,stroke:#2C3E50,stroke-width:3px,color:#fff
    style D fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style B fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style H fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff

{#fig-number-systems}

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
graph TB
    subgraph "Analogy: Measuring Distance"
        MILES["<b>Miles</b><br/>Human-friendly<br/>Easy to estimate<br/>Like DECIMAL"]
        FEET["<b>Feet</b><br/>More precise<br/>Smaller units<br/>Like BINARY"]
        YARDS["<b>Yards</b><br/>Convenient grouping<br/>3 feet = 1 yard<br/>Like HEX (4 bits = 1 digit)"]
    end

    subgraph "Real Example"
        DISTANCE["<b>Same distance:</b><br/>0.5 miles<br/>= 2,640 feet<br/>= 880 yards"]
    end

    subgraph "Number System Parallel"
        PARALLEL["<b>Same value: 15</b><br/>Decimal: 15<br/>Binary: 1111<br/>Hex: F"]
    end

    MILES -.->|"Similar to"| PARALLEL
    FEET -.->|"Similar to"| PARALLEL
    YARDS -.->|"Similar to"| PARALLEL

    style MILES fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#000
    style FEET fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style YARDS fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style DISTANCE fill:#ECF0F1,stroke:#7F8C8D,stroke-width:1px,color:#000
    style PARALLEL fill:#ECF0F1,stroke:#7F8C8D,stroke-width:1px,color:#000

Figure 46.1: 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. {fig-alt=“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.”}

46.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

46.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
NoteBinary Notation in Code
  • C/Arduino: 0b10011001 (prefix 0b)
  • Python: 0b10011001 (prefix 0b)
  • Documentation: 10011001₂ or just 10011001 (context)

46.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
NoteReal-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" (characters: 1, 2, 3, 4, ., 5, 6, null terminator) - 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.

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

46.3.4 Conversion Practice

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

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

WarningCommon 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!


46.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.

46.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

46.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)

WarningCommon 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:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor':'#2C3E50','primaryTextColor':'#fff','primaryBorderColor':'#16A085','lineColor':'#16A085','secondaryColor':'#E67E22','tertiaryColor':'#7F8C8D','background':'#ffffff','mainBkg':'#2C3E50','secondBkg':'#16A085','tertiaryBkg':'#E67E22','textColor':'#2C3E50'}}}%%
graph LR
    subgraph Byte["One Byte = 8 Bits"]
        B7["Bit 7<br/>MSB<br/>(128)"]
        B6["Bit 6<br/>(64)"]
        B5["Bit 5<br/>(32)"]
        B4["Bit 4<br/>(16)"]
        B3["Bit 3<br/>(8)"]
        B2["Bit 2<br/>(4)"]
        B1["Bit 1<br/>(2)"]
        B0["Bit 0<br/>LSB<br/>(1)"]
    end
    B7 -.-> B6 -.-> B5 -.-> B4 -.-> B3 -.-> B2 -.-> B1 -.-> B0

    style B7 fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
    style B0 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style B6 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style B5 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style B4 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style B3 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style B2 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style B1 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff

Figure 46.2: Binary Byte Structure with MSB and LSB Bit Positions

{fig-alt=“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.”} {#fig-byte-structure}

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

NoteMemory Terms in IoT
  • Kilobyte (KB): 1,024 bytes (2¹⁰)
  • Megabyte (MB): 1,048,576 bytes (2²⁰)
  • Typical IoT device: 32-512 KB RAM, 256 KB-4 MB flash
  • Why 1024? Powers of 2 align with binary addressing

46.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.


46.5 Knowledge Check

Knowledge Check: Binary and Hexadecimal Quick Check

Concept: Converting between number systems and understanding bit operations.

Question: What is the hexadecimal representation of the binary value 11001010?

Explanation: C is correct. Split into nibbles: 1100 = C (12) and 1010 = A (10). So 11001010 = 0xCA. Remember: each hex digit represents exactly 4 binary bits.

Question: An IoT sensor register at address 0x2F contains 0b10110100. What is bit 5 (counting from 0)?

Explanation: B is correct. Numbering from right (LSB=0): 10110100 → bit 5 is the 6th position from right = 1. The sequence is: bit0=0, bit1=0, bit2=1, bit3=0, bit4=1, bit5=1, bit6=0, bit7=1.

Question: A 12-bit ADC returns the value 0x7FF. What is this in decimal?

Explanation: D is correct. 0x7FF = 7×256 + 15×16 + 15 = 1792 + 240 + 15 = 2047. This is also 2^11 - 1, which is exactly half the range of a 12-bit ADC (0-4095). 0x7FF represents about 50% of full scale.


46.6 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

46.7 What’s Next

Continue learning about data representation:

Or return to the Data Representation overview for the complete topic map.