%%{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
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
IoT systems constantly convert between three number systems: decimal (human-friendly), binary (computer-native), and hexadecimal (compact representation).
{#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
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
- C/Arduino:
0b10011001(prefix0b) - Python:
0b10011001(prefix0b) - Documentation:
10011001₂or just10011001(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
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.
- C/Arduino:
0x99or0xFA(prefix0x) - Python:
0x99or0xFA(prefix0x) - 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
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
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)
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 300Rule 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
{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
- 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:
- Text Encoding for IoT - Learn how ASCII, Unicode, and UTF-8 represent text in IoT systems
- Bitwise Operations and Endianness - Master bit manipulation and byte ordering for hardware programming
Or return to the Data Representation overview for the complete topic map.