The maximum decimal value of an 8-bit unsigned binary register is 255. For a 16-bit unsigned register, it is 65,535, and for a 32-bit unsigned register, it is 4,294,967,295. When you are configuring PWM resolution on an ESP32, reading a 12-bit ADC on an Arduino, or parsing I2C sensor data, guessing these boundaries leads to integer overflow, clipped signals, and bricked logic loops. You need exact numbers, not abstract theory.

The Master Binary and Decimal Table (ISO/IEC 9899 C11 Standard)

The following table maps binary bit-widths to their maximum decimal and hexadecimal values, anchored to the exact-width integer types defined in the ISO/IEC 9899 C11 standard (<stdint.h>). This is the native data typing used by the GCC compiler under the hood of both the Arduino IDE and Espressif ESP-IDF.

How to read this table: The Bit Width column defines the physical register size in the microcontroller's silicon. The Binary Max shows the physical 1s and 0s in the register. The Unsigned column applies when you only measure positive values (like PWM duty cycles or light sensor readings). The Signed column applies when the data crosses zero (like accelerometer axes or temperature). The Standard C/C++ Type is the exact variable declaration you should use in your code to guarantee that specific bit-width, regardless of whether you are compiling for an 8-bit ATmega328P or a 32-bit ESP32-S3.
Bit Width Binary Representation (Max) Decimal (Unsigned) Decimal (Signed Range) Hex Max Standard C/C++ Type
4-bit (Nibble) 1111 15 -8 to +7 0x0F No native C type (use bitfields)
7-bit (I2C Addr) 111 1111 127 -64 to +63 0x7F Protocol specific (mask with 0x7F)
8-bit (Byte) 1111 1111 255 -128 to +127 0xFF uint8_t / int8_t
10-bit (PWM/ADC) 11 1111 1111 1,023 -512 to +511 0x3FF uint16_t (masked)
12-bit (ADC) 1111 1111 1111 4,095 -2,048 to +2,047 0xFFF uint16_t (masked)
16-bit (Word) 1111 1111 1111 1111 65,535 -32,768 to +32,767 0xFFFF uint16_t / int16_t
32-bit (DWord) (8 groups of 1111) 4,294,967,295 -2,147,483,648 to +2,147,483,647 0xFFFFFFFF uint32_t / int32_t

Which Column Applies to Your Application (and How Modifiers Shift the Base)

Choosing the correct column depends entirely on the physical reality of the sensor or actuator you are interfacing with, combined with the microcontroller's hardware peripherals.

When to use the Unsigned Column: Use unsigned types (uint8_t, uint16_t) for values that physically cannot drop below zero. This includes ADC raw readings (a photodiode cannot output negative light), PWM duty cycles, I2C bus addresses, and RGB LED hex color codes. Using an unsigned type gives you double the positive headroom.

When to use the Signed Column: Use signed types (int8_t, int16_t) when measuring bipolar physical phenomena. If you are reading the Z-axis of an MPU6050 accelerometer, or a thermocouple measuring sub-zero ambient temperatures, the value must cross zero.

The 'Signedness' Derating Factor: In electrical wiring, ambient temperature derates a conductor's ampacity. In binary logic, allocating the Most Significant Bit (MSB) as a sign flag acts as a derating factor. By switching from an unsigned 16-bit integer to a signed 16-bit integer, you 'derate' your maximum positive decimal payload from 65,535 down to 32,767. You lose exactly 50% of your positive range to accommodate negative numbers. Always size your register to account for this 50% derating if there is any chance the sensor reading dips below zero.

How non-standard bit widths (10-bit, 12-bit, 14-bit) are handled: Microcontrollers rarely have physical 12-bit registers in main memory; they use 16-bit or 32-bit registers and mask the unused bits. For example, the ESP32’s SAR ADC natively outputs a 12-bit value (0 to 4095). However, the C++ variable holding it must be a 16-bit uint16_t. You must apply a bitwise AND mask (value & 0x0FFF) to strip away any stray high-bit noise before doing decimal math, otherwise a stray 1 in the 13th bit position will instantly multiply your decimal reading by 4,096.

What the Table Cannot Tell You: Overflow, Endianness, and Memory Alignment

A binary and decimal table gives you the mathematical boundaries, but it will not save you from the three most common firmware-level hardware bugs:

Hidden Hazard What the Table Misses Real-World Failure Mode The Fix
Integer Overflow The table shows the max value, but not what happens when you add 1 to it. Adding 1 to a uint8_t at 255 does not yield 256. It wraps around to 0. This causes PID control loops to violently reverse direction. Cast to a larger type before math: uint16_t safe_math = (uint16_t)val8 + 1;
Bus Endianness The table assumes a single monolithic number, ignoring byte order over wires. Reading a 16-bit signed temperature over I2C. The table says max is 32,767, but if you read the Low Byte before the High Byte, a reading of 25°C (0x00FA) becomes 64,000 (0xFA00). Check the sensor datasheet. Most I2C sensors are Big-Endian; SPI flash is often Little-Endian. Use Wire.read() << 8 | Wire.read() accordingly.
Memory Alignment The table ignores how 32-bit ARM CPUs fetch memory. Packing four uint8_t variables and one uint32_t into a struct on an ESP32-S3. The CPU inserts 3 bytes of invisible 'padding' to align the 32-bit integer, breaking your raw SPI byte parsing. Use the __attribute__((packed)) directive on your C++ structs when mapping raw binary buffers to variables.

Quick-Jump Bookmark Rows for Common Maker Scenarios

Keep these specific boundary values bookmarked for rapid debugging when your serial monitor outputs garbage data.

  • I2C 7-Bit Addressing: Maximum decimal address is 127 (0x7F). If your scanner outputs an address of 192, you are looking at an 8-bit address that includes the Read/Write bit. Shift it right by one (addr >> 1) to get the true 7-bit decimal value.
  • Arduino Uno analogRead(): 10-bit resolution. Decimal range is 0 to 1023. If you are mapping this to a 5V reference, each decimal step equals exactly 4.88 millivolts (5.0 / 1024).
  • ESP32 Native analogRead(): 12-bit resolution. Decimal range is 0 to 4095. However, the ESP32 ADC is notoriously non-linear at the extremes. Trust the middle 20% to 80% of the decimal range (approx. 800 to 3200) for accurate voltage mapping.
  • ESP32 LEDC PWM (v5.x IDF): The legacy 8-bit (0-255) resolution is deprecated in newer ESP-IDF versions. The hardware timer natively supports up to 14-bit resolution, yielding a decimal range of 0 to 16,383. Use ledc_timer_config_t to explicitly set duty_resolution = LEDC_TIMER_14_BIT for smooth servo control.
  • Unix Epoch Time (32-bit Signed): If you are storing RTC time in a standard int32_t, the maximum decimal value is 2,147,483,647. This translates to the 'Year 2038 Problem' (January 19, 2038, at 03:14:07 UTC). For new projects, always use a 64-bit int64_t for timestamps.

Understanding the strict mathematical boundaries of your registers prevents the silent failures that plague embedded systems. Always declare your variables using the explicit <stdint.h> types, respect the signedness derating factor, and mask your non-standard ADC/PWM bit-widths before passing them into your control logic.