The decimal number 300 in binary is 100101100, a 9-bit sequence that represents a critical threshold in embedded systems where 8-bit registers overflow and 10-bit analog-to-digital conversions operate. When you are writing firmware for microcontrollers like the ATmega328P or ESP32, understanding exactly how 300 is stored in memory dictates whether your circuit behaves as designed or fails silently due to data truncation.

In practical electronics, 300 is not just an arbitrary number. It is a common ADC reading for specific voltage thresholds, a standard DMX512 lighting channel, and a frequent target value for PWM duty cycles. However, because 300 requires nine bits to represent, attempting to force it into standard 8-bit hardware registers or software variables results in the loss of the Most Significant Bit (MSB). This article breaks down the exact binary anatomy of 300, where it appears on the bench, and how to prevent the catastrophic truncation bugs that occur when 9-bit data meets 8-bit hardware.

The Anatomy of 300 in Binary (And Why 9 Bits Matter)

To understand why 300 causes headaches in embedded C/C++, we have to look at its binary composition. Unlike 255 (which perfectly fills an 8-bit byte as 11111111), 300 spills over into a ninth bit.

Here is the exact bitwise breakdown of 300:

Bit Position Weight (Decimal) Binary State Contribution
Bit 8 (MSB)2561256
Bit 712800
Bit 66400
Bit 532132
Bit 41600
Bit 3818
Bit 2414
Bit 1200
Bit 0 (LSB)100

Summing the active bits (256 + 32 + 8 + 4) gives us exactly 300. In hexadecimal, this is represented as 0x12C. The crucial takeaway for hardware designers is that Bit 8 holds a weight of 256. If your microcontroller, shift register, or DAC only accepts 8 bits, that 256 bit is the first thing to get chopped off during compilation or transmission.

What People Commonly Confuse It With

When debugging firmware, makers frequently misinterpret how 300 is handled by the compiler or the hardware. There are two primary confusions:

Confusion 1: The 8-Bit Clamping Assumption
Many hobbyists assume that if they pass 300 to an 8-bit function (like Arduino's analogWrite()), the system will intelligently 'clamp' or cap the value at the 8-bit maximum of 255. In reality, C/C++ compilers typically perform a bitwise truncation, silently dropping the MSB and wrapping the value, which yields a drastically lower number than expected.

Confusion 2: Binary vs. Binary-Coded Decimal (BCD)
Some developers confuse pure binary with BCD. In pure binary, 300 is 100101100. In BCD, each decimal digit is encoded separately into 4 bits. The BCD representation of 300 would be 0011 0000 0000 (3 = 0011, 0 = 0000, 0 = 0000). Sending a BCD-formatted 300 to a register expecting pure binary will result in the hardware reading the value as 768, completely derailing your circuit's behavior.

Where You Meet This In Practice

You will encounter the value 300, and its 9-bit binary requirements, in several common bench scenarios:

  • 10-Bit ADC Readings: On a classic Arduino Uno (ATmega328P), the analogRead() function returns a 10-bit value (0-1023). If you are reading a voltage divider monitoring a 12V battery, a reading of 300 corresponds to roughly 1.46V at the analog pin (assuming a 5V VREF). This is a common threshold for triggering a low-battery warning LED.
  • DMX512 Stage Lighting: The DMX512 protocol uses 9-bit break timings and addresses up to 512 channels. Channel 300 is a standard address for fog machines or secondary color wheels in moving head fixtures. Transmitting this address requires proper 9-bit or 16-bit framing.
  • High-Resolution PWM Timers: While standard AVR Arduinos use 8-bit PWM (0-255), 32-bit boards like the ESP32 or Arduino Due utilize 10-bit, 12-bit, or 16-bit PWM timers. Setting a fan duty cycle to 300 on a 10-bit timer (0-1023) yields a precise ~29.3% duty cycle, requiring the full 9-bit binary string to be written to the timer's compare register.

Real-World Scenario: The 8-Bit Truncation Bug

To understand what 300 in binary changes in a real circuit, let us walk through a classic bench failure involving an 8-bit PWM output and a 10-bit ADC input.

The Setup:
You are building a temperature-controlled heater circuit using an Arduino Uno. You read an NTC thermistor via the 10-bit ADC. Your math dictates that when the ADC reads 300, the temperature has dropped enough that you need to turn on the heater MOSFET. You decide to use a PWM pin to softly ramp up the heater, passing the ADC value directly into the analogWrite() function to scale the heat output.

The Numbers:
The ADC returns 300. In binary, this is 1 0010 1100.
The analogWrite() function on the ATmega328P accepts an int but casts it to an 8-bit unsigned integer (uint8_t) before writing to the hardware timer register. An 8-bit register can only hold 8 bits.

The Outcome:
The compiler drops the 9th bit (the MSB, which holds the value of 256). The binary string 1 0010 1100 is truncated to 0010 1100.
Converting 0010 1100 back to decimal gives us 44 (32 + 8 + 4).

What Went Wrong:
Instead of the heater ramping up to a high duty cycle (or clamping at 255 for 100% heat), the PWM pin outputs a duty cycle of 44 out of 255, which is roughly 17%. The heater barely gets warm, the temperature continues to drop, and your system fails to regulate. The bug is entirely invisible in the serial monitor if you only print the 10-bit ADC value; it only exists in the silent binary truncation at the hardware register level.

How to Fix and Prevent Bit-Width Mismatches

Preventing 9-bit overflow requires explicit data mapping and proper variable typing. Follow these numbered steps to ensure values like 300 are handled correctly across mixed-width architectures:

  1. Map the Data Range: Never pass a 10-bit ADC value directly to an 8-bit PWM pin. Use the Arduino map() function to scale the 0-1023 range down to 0-255. int pwmVal = map(adcVal, 0, 1023, 0, 255); An ADC reading of 300 will correctly map to a PWM value of 74.
  2. Use Explicit Integer Types: Stop using generic int variables for hardware registers. Use uint8_t for 8-bit registers and uint16_t for 10-bit or 16-bit registers. This forces the compiler to warn you if you attempt to assign a 9-bit value to an 8-bit container.
  3. Split Bytes for SPI/I2C: If you are sending the 16-bit hex equivalent of 300 (0x012C) to a digital-to-analog converter (DAC) over SPI, you must split the 9-bit binary sequence into two 8-bit transmissions. Send the MSB first: SPI.transfer(0x01); followed by the LSB: SPI.transfer(0x2C);.
  4. Verify with Bitwise Masks: When debugging, use bitwise AND masks to isolate exactly what the hardware is seeing. Serial.println(val & 0xFF); will show you the exact 8-bit truncated value that the timer register will receive.

FAQ: Binary 300 and Embedded Systems

Can I just use a 16-bit integer to store 300 and avoid the problem?

Yes, storing 300 in a uint16_t (16-bit) variable in your C++ code prevents software-level overflow. However, this does not protect you if the destination hardware register (like an 8-bit timer or an 8-bit shift register like the 74HC595) is physically limited to 8 bits. The hardware will still truncate the MSB upon writing.

What is 300 in binary if I am using a 32-bit ARM Cortex microcontroller?

On a 32-bit system (like an STM32 or Raspberry Pi Pico), 300 is stored as 00000000 00000000 00000001 00101100. The value is padded with leading zeros to fill the 32-bit word. The core binary sequence 100101100 remains identical, but the architecture provides enough headroom that truncation is rarely an issue unless you are interacting with legacy 8-bit peripherals.

Why does my ESP32 ADC read 300 when the pin is grounded?

This is not a binary math issue; it is a hardware noise issue. The ESP32's ADC is notoriously non-linear and susceptible to WiFi/Bluetooth RF interference. A reading of 300 on a grounded pin indicates a floating reference or severe noise coupling. You must implement software oversampling or add a physical 100nF ceramic capacitor between the ADC pin and GND to stabilize the baseline.