Introduction
Pulse-Width Modulation (PWM) is a fundamental technique for controlling analog-like outputs from digital pins. In this project, we'll use an ATtiny85 microcontroller to smoothly fade a yellow LED in and out. The LED is driven by analogWrite() on pin PB1, which corresponds to the OC0B output of Timer0. This example is perfect for beginners wanting to explore PWM on the ATtiny85 using the Arduino environment.
Circuit Walkthrough
The circuit is minimal:
- Component: A yellow LED (ID: tiny-fade-led) with its anode connected to PB1.
- Component: A 220 Ω resistor (ID: tiny-fade-r1) to limit current through the LED.
- The LED cathode links to one end of the resistor; the other resistor terminal connects to GND.
Wiring details:
| From | To | Color |
|---|---|---|
| ATtiny85 PB1 | LED anode (A) | Yellow (#ffcc00) |
| LED cathode (C) | Resistor terminal 1 | Gray (#888888) |
| Resistor terminal 2 | ATtiny85 GND | Black (#000000) |
This forms a standard low-side drive: the microcontroller sources current through the LED and resistor to ground. The 220 Ω resistor is calculated for a forward voltage of ~2 V and current ~10 mA.
Code Walkthrough
The firmware is written in Arduino-style C++ and is straight forward. Let's break it down block by block.
// ATtiny85 — PWM LED fade on PB1 (OC0B / Timer0)
// analogWrite() uses Timer0 on the ATtiny85
void setup() {
pinMode(1, OUTPUT); // PB1 = OC0B (PWM capable)
}
void loop() {
// Fade in
for (int brightness = 0; brightness <= 255; brightness++) {
analogWrite(1, brightness);
delay(6);
}
// Fade out
for (int brightness = 255; brightness >= 0; brightness--) {
analogWrite(1, brightness);
delay(6);
}
delay(200);
}
setup(): We set pin 1 (PB1) as an output. This pin is also the OC0B output for Timer0, enabling PWM.
loop(): The fade cycle runs continuously:
- Fade in: A
forloop incrementsbrightnessfrom 0 to 255. Each iteration callsanalogWrite(1, brightness)which sets the PWM duty cycle. Adelay(6)ms controls the speed. - Fade out: Another
forloop decrementsbrightnessfrom 255 down to 0. - After the fade-out, a
delay(200)ms pause before repeating.
The analogWrite() function on the ATtiny85 uses Timer0 hardware to generate a PWM signal at approximately 1 kHz (default). The duty cycle is proportional to the value (0–255): 0 is fully off, 255 is fully on, and intermediate values give varying brightness.
Key Concepts
- PWM (Pulse-Width Modulation): A digital signal that switches on and off at a high frequency. The average voltage (and hence brightness) is controlled by the duty cycle.
- Timer0 on ATtiny85: The microcontroller has one 8-bit timer (Timer0) with two PWM outputs: OC0A (PB0) and OC0B (PB1).
analogWrite()on pin 1 uses OC0B. - Current limiting resistor: LEDs must be used with a resistor to prevent excessive current. The 220 Ω resistor ensures safe operation.
Common Pitfalls & Debugging Tips
- Wrong pin: Only PB1 (pin 1) supports PWM via analogWrite on most ATtiny85 cores. Double-check wiring.
- Weak pull-ups: If the LED stays dim, ensure the resistor value is correct. Too high a resistance reduces brightness.
- Timer conflicts: On ATtiny85, Timer0 is also used for
delay()andmillis(). Changing Timer0 prescaler may affect timing. - LED polarity: The anode (long leg) connects to PB1, cathode to resistor. Reversing polarity will prevent light.
Suggested Extensions
- Add a potentiometer to control fade speed or target brightness.
- Drive an RGB LED using three PWM pins (PB0, PB1, and maybe use software PWM on another pin).
- Implement different fade patterns (e.g., sine wave, sawtooth).
- Use interrupts to generate PWM without blocking the main loop.
Try It Yourself
Ready to see the LED fade? Open the live example on velxio.dev and run the simulation. Experiment with the code and component values to deepen your understanding of PWM on the ATtiny85.