Background
This project will integrate a light-dependent resistor (LDR) with the ATmega328p. This gives us an excuse to explore the Analog-to-Digital (ADC) converter peripheral. We’ll map the full-scale range of the sensor and display it on 8 LED’s, thereby making a crude light detector.
The Theory
An ADC bridges the digital and analog worlds
Anytime an analog sensor is used, an ADC is present. Their ubiquitous !
An ADC allows us to measure analog quantities such as distance, pressure, temperature, sound or brightness.
Part of sensor conditioning is converting this analog quantity into a voltage (many sensors already do this for us). What we need to do is scale it down to Vcc then use the ADC.
Introduction to ADC Hardware
The Atmega328p uses a 10-bit successive approximation register (SAR) ADC. The comparator keeps comparing until the voltage at the input channel is smaller than a step size.
Since the ADC module actually occupies a large chunk of silicon, the Atmega328p only has one ADC. Fear not! Multiple I/O’s can share the ADC via multiplexing.
Hardware Connections
8 LED’s with current-limiting resistors connected on PORTB.
A voltage divider consisting of LDR on upper leg and a 10k on the bottom leg. The halfway point connects to PC0.
NOTE: You can configure R2 in the voltage divider to exploit the full range of the LDR using

The LDR’s resistance drops when exposed to more light, thus the ADC reads a higher voltage. We convert it’s sensor reading into a voltage using a voltage divider.

The Software
main.c reads the voltage on the ADC pin and maps it to the series of LEDs. ADC reading is also transmitted via UART.
The Showcase
Apologies for the potato quality. I was being stingy with the export settings in Premiere Pro.
BONUS: Interrupt-driven light sensor
Let’s convert the light sensor to be interrupt driven. The full file is available in the GitHub repository. This requires we do the following:
- Include
<avr/interrupt.h>. - Enable global interrupts using
sei(). - Enable the ADC Conversion Complete Interrupt bit (
ADIE) inADCSRA. - Implement the
ADC_vectInterrupt Service Routine (ISR) to handle the data when a conversion finishes. - Switch the ADC to Free Running mode (
ADATEinADCSRAand clearingADCSRB), which automatically triggers the next conversion as soon as the current one finishes. This removes the need for a delay or manual triggering inside thewhile(1)loop.

