The Core Method: Why Fixed-Point Binary Matters in Embedded Systems
When you move from blinking LEDs to processing real-world sensor data on microcontrollers like the ESP32 or STM32, you inevitably hit the limits of floating-point math. Floating-point operations are computationally expensive and can introduce rounding errors in digital signal processing (DSP). Instead, firmware engineers rely on fixed-point arithmetic. Understanding practical examples of binary in fixed-point formats—specifically Q-format notation—is a mandatory skill for passing embedded systems exams and writing efficient C/C++ firmware.
In the Q-format (e.g., Q8.8), a 16-bit register is split into an 8-bit integer and an 8-bit fractional part. The position of the 'binary point' is implied by the software, not stored in the hardware. According to standard Q-format documentation, this allows a 16-bit ALU to perform fractional math using standard integer multiplication and bitwise shifts, saving thousands of clock cycles per operation.
Exam Problem Walkthrough: Decimal to 16-Bit Fixed-Point Binary
Convert the decimal voltage value
13.625 into a 16-bit fixed-point binary representation using the Q8.8 format (8 integer bits, 8 fractional bits). Show all algebraic steps, identify the final 16-bit binary string, and provide the hexadecimal equivalent used in C-code.
Identifying the Method and the Trap
Which theorem applies? We use the Positional Numeral System Base-2 Expansion. The integer portion is solved via successive division by 2 (modulo arithmetic), while the fractional portion is solved via successive multiplication by 2 (extracting the carry bit).
The Trap: The most common mistake in these examples of binary conversion is reading the fractional bits in reverse order (bottom-up, like the integer part) or failing to pad the result to the exact 16-bit width. If you drop leading or trailing zeros, your bitwise shifts in C will misalign the binary point, resulting in wildly incorrect physical measurements.
Step-by-Step Algebraic Solution
Part 1: The Integer Portion (13)
We divide the integer by 2 and record the remainder. We read the remainders from bottom to top (Last-In-First-Out).
- 13 ÷ 2 = 6, Remainder 1 (Least Significant Bit of integer)
- 6 ÷ 2 = 3, Remainder 0
- 3 ÷ 2 = 1, Remainder 1
- 1 ÷ 2 = 0, Remainder 1 (Most Significant Bit of integer)
Reading bottom-up, the raw binary is 1101. Because Q8.8 requires exactly 8 bits for the integer, we pad with leading zeros: 00001101.
Part 2: The Fractional Portion (0.625)
We multiply the fraction by 2. The integer part of the result (the carry) becomes our binary bit. We read these bits from top to bottom (First-In-First-Out).
- 0.625 × 2 = 1.25 → Bit is 1 (Most Significant Bit of fraction). Carry over 0.25.
- 0.25 × 2 = 0.50 → Bit is 0. Carry over 0.50.
- 0.50 × 2 = 1.00 → Bit is 1. Carry over 0.00 (process terminates).
Reading top-down, the raw binary is 101. Because Q8.8 requires exactly 8 bits for the fraction, we pad with trailing zeros: 10100000.
Part 3: Assembly
Combining the integer and fractional parts around the implied binary point yields:
00001101 . 10100000
Integer:
0000 (0) 1101 (D) → 0x0DFraction:
1010 (A) 0000 (0) → 0xA0Final C-variable assignment:
uint16_t sensor_val = 0x0DA0;
Sanity Check and Independent Verification
Never submit an exam answer or push firmware to production without an independent verification step. We verify by converting the binary string back to decimal using algebraic summation ($\sum b_i 2^i$).
Integer Verification:
00001101 = (0×128) + (0×64) + (0×32) + (0×16) + (1×8) + (1×4) + (0×2) + (1×1)
= 8 + 4 + 1 = 13.
Fractional Verification:
10100000 = (1×2-1) + (0×2-2) + (1×2-3) + (0×2-4) ...
= 0.5 + 0 + 0.125 + 0 = 0.625.
Order of Magnitude Check:
Does this make physical sense? The integer 13 sits between 8 ($2^3$) and 16 ($2^4$), meaning the highest set bit must be in the $2^3$ position (the 4th bit from the right of the binary point). Our binary string has a 1 in exactly that position. The fraction 0.625 is greater than 0.5 but less than 0.75, meaning the first fractional bit ($2^{-1}$) must be 1, and the second ($2^{-2}$) must be 0. Our string (10...) perfectly matches this bounding logic. The answer is verified.
Frequently Asked Questions
What are common examples of binary in microcontroller registers?
In practical embedded systems, examples of binary are most frequently encountered when configuring hardware registers or reading Analog-to-Digital Converters (ADCs). For instance, the ESP32 features a 12-bit ADC. When it reads a voltage, it returns a raw binary value between 000000000000 (0) and 111111111111 (4095). To manipulate specific hardware features, like enabling a pull-up resistor on a GPIO pin, you use bitwise OR operations to flip a specific binary bit to 1 without altering the surrounding configuration bits in the 32-bit register.
How do examples of binary fractions differ from IEEE 754 floating-point?
Fixed-point binary (like the Q8.8 format demonstrated above) uses a static, implied binary point. The hardware treats it as a standard integer, and the software handles the scaling. IEEE 754 floating-point, on the other hand, dedicates specific bits to a sign, an exponent, and a mantissa (e.g., 32-bit single precision uses 1 sign bit, 8 exponent bits, and 23 mantissa bits). While IEEE 754 offers a massive dynamic range, it requires a dedicated Floating Point Unit (FPU). Many low-cost microcontrollers lack an FPU, making fixed-point examples of binary math significantly faster and more memory-efficient for tasks like audio filtering or motor control.
Why do some binary examples use hexadecimal shorthand instead of raw bits?
Raw binary strings are highly prone to human transcription errors. Counting sixteen consecutive 1s and 0s to find a specific bit index is tedious and leads to off-by-one bugs in C code. Hexadecimal acts as a perfect compression layer because every single hex digit maps exactly to a 4-bit binary nibble. As shown in our walkthrough, 1010 is always A, and 1101 is always D. This 1-to-4 mapping allows engineers to visually parse the state of a 32-bit register in just 8 hex characters, which is why digital logic textbooks heavily emphasize hex-to-binary fluency alongside base-2 conversions.






