ATtiny45 ADC Pin Mapping
| ADC Channel | Physical Pin | Port Pin |
| ADC0 | Pin 1 | PB5 (Also the Reset Pin*) |
| ADC1 | Pin 7 | PB2 |
| ADC2 | Pin 3 | PB4 |
| ADC3 | Pin 2 | PB3 |
#include <avr/io.h>
#include <util/delay.h>
void adc_setup() {
// 1. Set Voltage Reference to VCC (leave REFS0 at 0)
// 2. Select Input Channel ADC2 (PB4) by setting MUX1 bit
ADMUX |= (1 << MUX1);
// 3. Set ADC Prescaler to 128 (ADPS0, ADPS1, ADPS2 = 1)
// This scales the 9.6MHz or 1.2MHz clock down to a usable range (50-200kHz)
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
// 4. Enable the ADC
ADCSRA |= (1 << ADEN);
}
uint16_t adc_read() {
// Start the conversion
ADCSRA |= (1 << ADSC);
// Wait for conversion to finish (ADSC bit returns to 0)
while (ADCSRA & (1 << ADSC));
// Return the 10-bit result (ADCL + ADCH)
return ADC;
}
int main(void) {
// Set PB0 as an output (for an LED)
DDRB |= (1 << DDB0);
adc_setup();
while (1) {
uint16_t val = adc_read();
// If input > ~2.5V (assuming 5V VCC, 512 is half of 1024)
if (val > 512) {
PORTB |= (1 << PB0); // LED ON
} else {
PORTB &= ~(1 << PB0); // LED OFF
}
_delay_ms(50);
}
}
This code is a classic "Threshold Switch." It translates an analog voltage into a digital action (turning an LED on or off). Because the ATtiny45 and ATtiny13 share very similar register structures for the ADC, this specific code works almost identically on both.
Here is the breakdown of what each section is doing:
1. The Configuration (adc_setup)
This function wakes up the ADC and tells it how to behave.
ADMUX |= (1 << MUX1);The ADMUX register (ADC Multiplexer Selection) acts like a rotary switch. SettingMUX1to1connects the ADC hardware to PB4 (Pin 3). Note: By leaving theREFSbits at0, you are telling the chip to use VCC as the "yardstick" for measurement.ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);The ADC needs a clock speed between 50kHz and 200kHz to be accurate.ADPS (Prescaler bits): Setting all three to
1creates a division factor of 128.If your chip is at 9.6MHz, the ADC runs at 75kHz.
If your chip is at 1.2MHz, the ADC runs at 9.3kHz (which is actually a bit slow for the ATtiny45, but it will still function).
ADCSRA |= (1 << ADEN);This is the "Power Button" for the ADC. Without setting the ADC Enable bit, the converter stays off to save power.
2. The Measurement (adc_read)
This function handles the "Sample and Hold" process.
ADCSRA |= (1 << ADSC);The Start Conversion bit tells the ADC to take a "snapshot" of the voltage on the pin right now.while (ADCSRA & (1 << ADSC));This is a "blocking" loop. TheADSCbit stays1as long as the chip is busy calculating. As soon as it finishes, the hardware flips the bit back to0and the code moves on.return ADC;This returns a 10-bit number (0 to 1023). Even though the result is split into two 8-bit registers (ADCLandADCH), the compiler allows you to just readADCto get the full 10-bit value at once.
3. The Logic (main)
DDRB |= (1 << DDB0);Configures PB0 (Pin 5) as an Output so it can drive the LED.if (val > 512)Since the maximum value is 1023, 512 is the halfway point.If the pin sees more than half of the supply voltage (> 2.5V on a 5V system), the LED turns on.
If it sees less, the LED turns off.
_delay_ms(50);This prevents the chip from running at full speed, which saves power and reduces "jitter" if the voltage is hovering right at 2.5V.
ADMUX to use the Internal 1.1V or 2.56V reference, which stays steady even if your power supply fluctuates.
