Embedded

8051 ADC Interfacing

By CourseTron Team ·  8 min read ·  Updated Oct 2026 💬 𝕏 in f
Table of Contents
    ? Print / Save as PDF

    In short: To read an ADC0804 with an 8051 you wire it as a memory-mapped or port-mapped peripheral, pulse WR̄ low to start a conversion, poll (or interrupt on) INTR̄ going low, then pulse RD̄ low to latch the 8-bit result onto the data port.

    Why the 8051 needs an external ADC at all

    The classic 8051 core (and most of its derivatives such as the AT89C51 or AT89S52) has no on-chip analog-to-digital converter. Its I/O is strictly digital: every pin reads back a logic 0 or 1. The moment your embedded project has to measure something continuous — a temperature from an LM35, a potentiometer wiper, a light-dependent resistor, or a 4–20 mA sensor loop — you need a device that turns a voltage into a binary number. The ADC0804 is the textbook choice because it is a single-channel, 8-bit successive-approximation converter in a friendly 20-pin DIP, it runs from a single +5 V rail, and its control bus (CS̄, RD̄, WR̄, INTR̄) maps cleanly onto 8051 port pins.

    Eight bits gives you 256 quantization steps. With the default reference, full scale is 5 V, so one LSB equals 5 V / 256 ≈ 19.53 mV. That resolution is the first number every interview will ask you to derive, so commit the formula to memory: V_LSB = V_ref(full-scale) / 2^n.

    ⚡ Key fact: The ADC0804 includes its own internal clock. Tie an R (≈10 kΩ) from CLK R to CLK IN and a C (≈150 pF) from CLK IN to ground, giving f ≈ 1/(1.1·R·C) ≈ 606 kHz and a conversion time of roughly 100 µs — about 64–73 clock cycles.

    The four control signals, and what each actually does

    Every ADC0804 transaction is a small handshake. Understanding the direction and active level of each line is what separates working code from the "my ADC always reads 255" forum posts.

    PinDir (from MCU)ActiveRole
    CS̄ (Chip Select)OutputLowEnables the chip; often tied permanently to GND in single-ADC designs.
    WR̄ (Write / Start)OutputLow→HighA low-going pulse begins a new conversion on the rising edge.
    RD̄ (Read / Output Enable)OutputLowDrives the converted byte onto DB0–DB7 while held low.
    INTR̄ (Interrupt)InputLowGoes low when a conversion completes — your "data ready" flag.

    Note the bars: all four are active-low, a detail that trips up newcomers. The WR̄ line is the start-of-conversion trigger — contrary to its name it does not write data into the ADC; it writes a command ("go convert now"). The INTR̄ line is the heartbeat of the whole design: it falls low only after the successive-approximation register has settled all 8 bits, so your firmware should never read the data bus until it sees that edge.

    8051 to ADC0804 wiring 8051 Port 1 + Port 3 ADC0804 8-bit SAR ADC P1.0-P1.7 ◀ DB0-DB7 (data) P3.7 ▶ WR̄ (start) P3.6 ▶ RD̄ (read) P3.5 ◀ INTR̄ (done) CS̄ tied to GND Vin+ from sensor CourseTron · coursetron.com
    Block diagram: the data bus moves the result into the 8051, while three handshake lines sequence each conversion.

    The conversion handshake, step by step

    A single reading follows a fixed choreography. The animation below shows the WR̄ pulse launching the conversion, the SAR settling, and INTR̄ dropping to announce "data ready".

    ADC0804 conversion handshake WR̄ SAR INTR̄ start on rising edge 8 bits settling (~100 µs) data ready CourseTron · coursetron.com
    Animated handshake: a WR̄ pulse starts conversion; ~100 µs later INTR̄ falls low to signal the byte is valid.

    In plain sequence: (1) ensure CS̄ is low, (2) send WR̄ high→low→high to latch the start command, (3) wait for INTR̄ to go low, (4) pull RD̄ low, (5) read the 8-bit port, (6) return RD̄ high. Steps 4–6 together are often under a microsecond, so the dominant cost is the ~100 µs conversion itself — meaning a polled design comfortably samples at roughly 8–9 kSa/s, more than enough for temperature or audio-envelope work but nowhere near enough for raw audio.

    ⚙ Key fact: Prefer the interrupt path over busy-polling in production. Route INTR̄ to the 8051's external interrupt pin INT0̄ (P3.2), configure it edge-triggered (IT0 = 1), and your main loop is freed to do real work while conversions run in the background.

    Sample driver code (C51 / Keil)

    The listing below targets a standard 8051 compiled with Keil C51. Data sits on Port 1; the three handshake lines sit on Port 3. Note that before reading an input port on the 8051 you must write 0xFF to it so the internal pull-ups present a high impedance — a quasi-bidirectional-port quirk that bites almost everyone once.

    #include 
    
    sfr  ADC_DATA = 0x90;   /* Port 1 = DB0..DB7 */
    sbit WR   = P3^7;       /* start-of-conversion, active low */
    sbit RD   = P3^6;       /* output enable,       active low */
    sbit INTR = P3^5;       /* end-of-conversion,   active low */
    /* CS tied to GND in hardware */
    
    unsigned char adc_read(void)
    {
        unsigned char value;
    
        WR = 1; WR = 0; WR = 1;      /* latch start on rising edge */
    
        while (INTR == 1);           /* wait until conversion done */
    
        ADC_DATA = 0xFF;             /* release port for input    */
        RD = 0;                      /* enable ADC output drivers */
        value = ADC_DATA;            /* latch the 8-bit result    */
        RD = 1;                      /* release the bus           */
    
        return value;
    }
    
    void main(void)
    {
        unsigned char raw;
        unsigned int  mv;
    
        while (1) {
            raw = adc_read();
            mv  = (unsigned int)raw * 1953UL / 100;  /* millivolts */
            /* display mv on an LCD, send over UART, etc. */
        }
    }

    The raw * 1953 / 100 trick converts the 0–255 code into millivolts (19.53 mV/LSB scaled to integer math) without dragging in floating point, which on an 8-bit core is expensive. For a cleaner display you would hand mv to a character LCD — see our companion walk-through on 8051 LCD interfacing for the HD44780 routines that pair perfectly with this driver, and the broader treatment of the quasi-bidirectional ports in 8051 GPIO and port structure.

    Common pitfalls and how the pros debug them

    When an ADC misbehaves, experienced engineers reach for a logic analyzer or a mixed-signal oscilloscope before touching the code. Capturing WR̄, INTR̄ and the data bus together tells you instantly whether the chip is even converting. The usual culprits:

    • Stuck at 0xFF: you forgot to write 0xFF to the port before reading, or RD̄ never actually went low.
    • Noisy least-significant bits: the analog ground and digital ground meet at more than one point. Use a single star ground and a 0.1 µF decoupling cap right at the chip's VCC.
    • Wrong full-scale: leaving V_ref/2 (pin 9) floating ties full scale to 5 V; drive it to 1.28 V and full scale becomes 2.56 V, doubling your effective resolution over a smaller range.
    • Reading too early: skipping the INTR̄ wait latches a half-converted value — the single most common bug.
    Vref/2 sets full scale and step size Vref/2 floating: 0 to 5 V 256 steps x 19.53 mV Vref/2 = 1.28 V: 0 to 2.56 V 256 x 10 mV unused range 0 V 5 V CourseTron · coursetron.com
    Halving the step size: driving pin 9 to 1.28 V gives a 2.56 V full scale and about 10 mV per step.

    For production-grade mixed-signal boards, teams validate the layout and timing margins in tools like Cadence Allegro or Siemens EDA (Mentor) HyperLynx before fabrication, and verify firmware timing against the datasheet's tWR and tACC specs. If you are moving from hobby breadboards toward real hardware design, the professional design-services team at Avecas handles exactly this kind of analog-digital integration.

    Ready to build real embedded systems end-to-end? Explore the hands-on microcontroller track in our CourseTron course catalogue and go from blinking an LED to a sensor-fused data logger.

    Frequently asked questions

    Can I interface multiple sensors to one ADC0804?

    Yes — the ADC0804 is single-channel, so you place an analog multiplexer such as a CD4051 in front of Vin+ and switch channels with spare 8051 port pins. Allow a few microseconds of settling after switching before you pulse WR̄.

    Why is my reading always 255?

    Almost always one of three things: the input voltage exceeds Vref full scale, RD̄ never went low so you are reading idle pull-ups, or you did not write 0xFF to the input port first. Probe RD̄ and the data bus with a scope to confirm.

    Should I poll INTR̄ or use an interrupt?

    Polling is fine for a learning project or a loop that does nothing else. For anything that must stay responsive — servicing a UART, running a control loop — wire INTR̄ to INT0̄ and read the result inside the ISR so the CPU is never blocked for 100 µs per sample.

    What resolution does the ADC0804 give?

    8 bits, i.e. 256 steps. At a 5 V reference that is 19.53 mV per step. If your signal only swings 0–2.5 V, halving Vref/2 to 1.28 V rescales full scale to 2.56 V and roughly doubles your usable resolution.

    Advertisement