Skip to main content

8. ADC Assembly Code Example

8.1 Full Code

Here is an example of AVR Assembly code to read the ADC from the ADC0 pin using the internal 2.56V reference and a CLK/128 prescaler:

#define __SFR_OFFSET 0x00
#include "avr/io.h"
;------------------------
.global main

main:
    LDI R20, 0xFF
    OUT DDRD, R20       ; Set Port D as output (ADC result low byte)
    OUT DDRB, R20       ; Set Port B as output (ADC result high byte)
    SBI DDRC, 0         ; Set pin PC0 as input for ADC0

    ;-- ADC Initialization --
    LDI R20, 0xC0       ; REFS1:REFS0 = 11 → Internal 2.56V
                        ; ADLAR = 0 → Right-justified
                        ; MUX4:MUX0 = 00000 → ADC0
    STS ADMUX, R20

    LDI R20, 0x87       ; ADEN = 1 → Enable ADC
                        ; ADPS2:ADPS0 = 111 → Prescaler CLK/128
    STS ADCSRA, R20

;-- ADC Reading Loop --
read_ADC:
    LDI R20, 0xC7       ; Set ADSC = 1 to start conversion
    STS ADCSRA, R20

wait_ADC:
    LDS R21, ADCSRA     ; Read ADCSRA status register
    SBRS R21, 4         ; Skip jump if ADIF (bit 4) = 1 (conversion complete)
    RJMP wait_ADC       ; Wait loop until ADIF is set

    ;-- Reset ADIF flag --
    LDI R17, 0xD7       ; Set ADIF = 1 so the controller can reset the flag
    STS ADCSRA, R17

    ;-- Read conversion result --
    LDS R18, ADCL       ; Read low-byte from ADCL (MUST read first)
    LDS R19, ADCH       ; Read high-byte from ADCH

    ;-- Output result --
    OUT PORTD, R18      ; Send low-byte to Port D
    OUT PORTB, R19      ; Send high-byte to Port B

    RJMP read_ADC       ; Repeat reading

8.2 Code Explanation

Initialization Section:

LDI R20, 0xC0
STS ADMUX, R20
  • 0xC0 in binary = 1100 0000
  • REFS1=1, REFS0=1 → Internal 2.56V reference voltage
  • ADLAR=0 → Right-justified output
  • MUX4:MUX0 = 00000 → Reading pin ADC0 (A0)
  • This part runs only once during initialization.
LDI R20, 0x87
STS ADCSRA, R20
  • 0x87 in binary = 1000 0111
  • ADEN=1 → ADC is enabled
  • ADPS2:ADPS0 = 111 → Prescaler CLK/128 (125 kHz at 16 MHz)

Reading Section (Loop):

LDI R20, 0xC7
STS ADCSRA, R20
  • 0xC7 in binary = 1100 0111
  • ADEN=1, ADSC=1 → Start one conversion cycle
  • ADPS remains the same (CLK/128)
wait_ADC:
    LDS R21, ADCSRA
    SBRS R21, 4
    RJMP wait_ADC
  • Polling loop: continuously reads ADCSRA and checks bit 4 (ADIF)
  • SBRS = Skip if Bit in Register Set → if ADIF=1 (conversion complete), skip RJMP
  • As long as ADIF=0 (conversion not complete), continue looping
LDI R17, 0xD7
STS ADCSRA, R17
  • Resets the ADIF flag by writing a 1 to the ADIF bit
  • This is necessary so the next conversion can be detected
LDS R18, ADCL
LDS R19, ADCH
OUT PORTD, R18
OUT PORTB, R19
  • Read ADCL first (mandatory), then ADCH
  • Send the results to Port D (low-byte) and Port B (high-byte)
  • Since it is right-justified: ADCH only contains 2 bits (bits 9 and 8)