5 Number Systems and Data Units
Chapter Scope (Avoiding Duplicate Deep Dives)
This chapter is the number systems and data units foundation.
- Stay here for binary/decimal/hex conversion and integer sizing decisions.
- Use Text Encoding for IoT for ASCII/Unicode/UTF-8 specifics.
- Use Bitwise Operations and Endianness for mask logic and byte-order implementation details.
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
- Convert one value manually across decimal, binary, and hex.
- Tie that value to a real register or packet field.
- Pick a data type and validate min/max range.
- Confirm with one worked example before moving on.
For Beginners: Number Systems
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.
Related Chapters, Products, and Tools
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
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
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
0x9Ais easier to inspect than10011010while preserving exact bit structure. - Byte width sets the range: An 8-bit unsigned value stores
0to255, while a 16-bit signed value stores-32,768to32,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, and1010can 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.
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(prefix0b) - Python:
0b10011001(prefix0b) - Documentation:
10011001₂or just10011001(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
Putting Numbers to It
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:
0x99or0xFA(prefix0x) - Python:
0x99or0xFA(prefix0x) - Documentation:
99h,0x99, or$99
5.3.4 Conversion Practice
Converting between number systems is a fundamental skill for IoT development.
Manual conversion examples:
Binary to Decimal: Add the values where there’s a 1:
1010= 8 + 2 = 1011111111= 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 11110xA5=1010 0101
Binary to Hex: Group into sets of 4 bits, convert each group:
11010110=1101 0110=0xD610111001=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 as13) - 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
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 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:
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.3CDecision 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
1. Dropping Leading Zeros in Fixed-Width Fields
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.
2. Mixing Signed and Unsigned Interpretations
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.
3. Choosing a Type for Today’s Value Instead of the Real Range
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 |
For Kids: Meet the Sensor Squad!
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!