I'm trying to dim a light bulb via an ATtiny85, which accepts commands sent over I2C. My problem is that the bulb is barely dimming and is flickering quite a bit.

My circuit can be seen here:

ATtiny85 dimming circuit controlled over I2C

The opto-isolator (and thus the triac) is controlled via pin 2 (AKA PB3, AKA PCINT3) and AC zero cross detection is done on pin 3 (AKA PB4, AKA PCINT4) on the ATtiny85.

The code uses Pin Change Interrupt Enable rather than the single External Interrupt Enable, because the External Interrupt pin is pin 7 (aka PB2), which is used as the SCL for the I2C communication.

The 8MHz internal clock is used and the timer/counter prescaler is 1024, which means that I have an effective input range (see level variable in the code) of roughly 0-65. My AC source is USA (60Hz).

#include <avr/interrupt.h>
#include <avr/io.h>
#include <TinyWireS.h>

#define PULSE 4       //trigger pulse width (counts)
#define I2C_SLAVE_ADDR 0x4 // the 7-bit address (remember to change this when adapting this example)

byte trigger = 3;
byte detector = 4;    
byte level = 50;
byte maxLevel = 65;
byte minLevel = 0;

void setup() {
    TinyWireS.begin(I2C_SLAVE_ADDR); // join i2c network
    TinyWireS.onRequest(requestEvent); //setup i2c requester
    digitalWrite(detector, HIGH);  //enable pull-up resistor
    pinMode(trigger, OUTPUT);// Set AC Load pin as output
    TCCR1 = 0;     //stop timer
    OCR1A = level;    //initialize the comparator
    TIMSK = _BV(OCIE1A) | _BV(TOIE1); //interrupt on Compare Match A and  enable timer overflow interrupt
    GIMSK = 0b00100000; //Enable pin change interrupt
    PCMSK = 0b00010000; //PB4, physical pin 3 PCINT4
    TCCR1 = B00001011; //Prescale the timer
    sei();  // Turn on interrupts

ISR(PCINT0_vect) {
    //interrupt looking for zero crossing
    TCNT1 = 0;   //reset timer - count from zero
    OCR1A = level;
    TCCR1 = B00001011;// prescaler on 1024, see table 12-5 of the tiny85 datasheet
    //comparator match
    digitalWrite(trigger,HIGH); //set triac gate to high
    TCNT1 = 255-PULSE;
    //trigger pulse width for a few cycles for triac to latch on. 255 bc the counter can only count up to 255

ISR(TIMER1_OVF_vect) {
    //timer1 overflow
    digitalWrite(trigger, LOW); //turn off triac gate
    TCCR1 = 0;  //disable timer stop unintended triggers

void loop() {}

void requestEvent() {
    if (TinyWireS.available()) {
        level = TinyWireS.receive();
        if (level > maxLevel) {
            level = maxLevel;
         else if (level < minLevel){
            level = minLevel;

I have tried a variety of bulbs (incandescent and dimmable LED), with none working any better than another.

Here is a video showing the zero cross detection (yellow) and the ATtiny85 trigger (blue) on an oscilloscope as I send it different dimming levels Bad phone video

I've thought about the snubber, I just don't have the parts on hand right now. I think it will help but I don't think it will correct whatever my larger issue is.

I'd appreciate all and any help. Thanks.

(Note: I also posted this here. Apologies if crossposting is frowned upon).

  • Are you able to turn the bulb off? Maybe the signal needs to be inverted. The triac circuit looks very minimal to me, but I'm not that into triacs.
    – Gerben
    Dec 30, 2016 at 15:30
  • Sending the max level does turn it off... But I don't know if it actually doing it the way I want it to. Hmm What do you mean the signal needs to be inverted? I was inspired by this
    – thread9000
    Dec 30, 2016 at 15:34
  • I meant a normally high signal with a short LOW pulse. So the blue trace upside down. But I'm just guessing here.
    – Gerben
    Dec 30, 2016 at 15:37
  • Are you sure about 47k R1 to the optotriac? Trigger current is 15mA for the MOC3021 and you have less than 0.1mA (with 5V power supply)
    – KIIV
    Dec 30, 2016 at 15:55
  • It's 0.47K. Poor picture quality . And using a 330ohm doesn't fix anything.
    – thread9000
    Dec 30, 2016 at 16:23

1 Answer 1


So I think there were (was?) two issues.

1) Pin change interrupts on the Attiny85 are triggered on rising and falling edges which I think was causing the flickering.

I changed the code to rising edge only triggering:

ISR(PCINT0_vect){ //interrupt looking for zero crossing
        if (digitalRead(4) == HIGH){
                TCNT1 = 0;   //reset timer - count from zero
                OCR1A = level;
                TCCR1 = B00001011;// prescaler on 1024, see table 12-5 of the tiny85 datasheet

2) Attiny85 #reset pin. Pulled that guy high with a resistor.

Anyways, here's the oscilloscope and dimming led blub video: youtube

  • Also, I switched to BTB08-600BWRG for the triac which helps with inductance (so far I've got five (65watt eq) LED light bulbs running just fine). (Note this didn't actually do anything the solve the original problem)
    – thread9000
    Jan 6, 2017 at 0:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.