Voltage controlled dimmer with an ATtiny85

Voltage controlled dimmer with an ATtiny85

I came to this project because the AC phase control as described in Arduino Playground - HomePage worked well in a simple sketch on an Arduino Nano, but controlling a lot of other things at the same time, the phase control produced irregular output. So I decided to use a stand alone ATtiny85 to handle the dimming and feed it with an analog signal from the Nano. Nevertheless, read this article to understand what you are doing!

I assembled the following circuit:

I used the BTB08-600BW because is has a built-in snubber filter for inductive loads. It can pull 8 amps. I tried resistors from 33 to 68 kOhm to decrease the voltage over the LTV814, which is an optocoupler that detects zero crossings in both directions. At 33k 0.4 W is dissipated each resistor and the zero crossing spike is narrow, at 68k 0.2 W is dissipated, but the zero crossing spike is much wider, which seems to give no problem.

It took a while to convert the original code into something that works on a Tiny85 but finally this is what works:

// Voltage controlled dimmer with ATtiny85
//
// This arduino sketch includes a zero 
// crossing detect function and an opto-isolated triac.
// 
// AC Phase control is accomplished using the internal 
// hardware timer1 in the ATtiny85
//
// Timing Sequence
// * timer is set up but disabled
// * zero crossing detected
// * timer starts counting from zero
// * comparator set to "delay to on" value
// * counter reaches comparator value
// * comparator ISR turns on triac gate
// * counter set to overflow - pulse width
// * counter reaches overflow
// * overflow ISR turns off triac gate
// * triac stops conducting at next zero cross

// The hardware timer runs at 8MHz. 
// A half period of a 50Hz AC signal takes 10 ms is 80000 counts.
// Prescaler set to 1024 gives 78 counts per half period


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

#define DETECT 2      //zero cross detect, interrupt 0, is physical pin 7
#define GATE 3        //triac gate is physical pin 2
#define PULSE 2       //trigger pulse width (counts)
#define INSTELPIN 2   // =A2 (digital pin4) is physical pin 3 

void setup(){
  // set up pins
  pinMode(DETECT, INPUT);      //zero cross detect
  digitalWrite(DETECT, HIGH);  //enable pull-up resistor
  pinMode(GATE, OUTPUT);       //triac gate control

  // set up Timer1 
  TCCR1 = 0;     // stop timer 
  OCR1A = 50;    //initialize the comparator
  TIMSK = _BV(OCIE1A) | _BV(TOIE1);  //interrupt on Compare Match A | enable timer overflow interrupt
  sei();  // enable interrupts
  // set up zero crossing interrupt
  attachInterrupt(0,zeroCrossingInterrupt, FALLING);    
}  

//Interrupt Service Routines
void zeroCrossingInterrupt(){   
  TCNT1 = 0;   //reset timer - count from zero
  TCCR1 = B00001011;        // prescaler on 1024, see table 12.5 of the tiny85 datasheet
}

ISR(TIMER1_COMPA_vect){    //comparator match
  digitalWrite(GATE,HIGH); //set triac gate to high
  TCNT1 = 255-PULSE;       //trigger pulse width, when TCNT1=255 timer1 overflows
} 
 
ISR(TIMER1_OVF_vect){       //timer1 overflow
  digitalWrite(GATE,LOW);   //turn off triac gate
  TCCR1 = 0;                //disable timer stop unintended triggers
}

void loop(){     // use analog input to set the dimmer
int instelwaarde = analogRead(INSTELPIN);
OCR1A = map(instelwaarde, 0, 1023, 65, 2); 
}

OCR1A sets the delay between zero crossing and firing the triac. In the sketch an analog input of 0V will cause maximum dimming. You can change this, of course.

Do you have a question?

Or should this thread be moved to Exhibition?

No questions left... You can move it to any place where people might enjoy my project.

Thank you for the post!

Looking at the circuit in the first post, is it possible to have the BTB08/600BW "remote".
By this I mean, can I feed AC Live / Neutral into the LTV814 so that the ATTiny can detect the Zero-Crossing.
Have the same AC Live fed into pin 4 of the MOC3052.
Pin 6 of the MOC3052 would then be on a header that would be wired to the Gate of the BTB08.
The AC Live would then be connected to the A2 of the BTB08 and the AC Neutral to the A1 of the BTB08.
What I want to achieve is to have a separate "switch" PCB that would have the ATTiny, LTV814 and the MOC3052. The BTB08 would then be on a heatsink that is mounted on the cabinet.

Is there an example of the final working sketch that was accomplished by ArthurRep?

hi,
Very nice schematic and code Arthur..
I have use it for derivating solar energy surplus to electric boiler.I have reduced attiny clock to 1mhz for lowest consumption (2-2.5ma instead 8mA).I use EL814 and two 47K resistors for zero crossing.I have included also a ZERO volt ac output (no pulse) for low input voltage.
i have reduced the input range for me to 0v_180v ac output.
find enclose code:

code:
// Voltage controlled dimmer with ATtiny85
//
// This arduino sketch includes a zero
// crossing detect function and an opto-isolated triac.
//
// AC Phase control is accomplished using the internal
// hardware timer1 in the ATtiny85
//
// Timing Sequence
// * timer is set up but disabled
// * zero crossing detected
// * timer starts counting from zero
// * comparator set to "delay to on" value
// * counter reaches comparator value
// * comparator ISR turns on triac gate
// * counter set to overflow - pulse width
// * counter reaches overflow
// * overflow ISR turns off triac gate
// * triac stops conducting at next zero cross

// The hardware timer runs at 1MHz (3mA).
// A half period of a 50Hz AC signal takes 10 ms is 10000 counts.
// @ 1MHZ (3ma)prescaler (1000) 128 78 counts per half period

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

#define DETECT 2 //zero cross detect, interrupt 0, is physical pin 7
#define GATE 3 //triac gate is physical pin 2 pourrait etre 0 (pin5)
#define PULSE 2 //trigger pulse width 4 if 512 (counts)
#define INSTELPIN 2 // =A2 (digital pin4) is physical pin 3

void setup(){
// set up pins
pinMode(DETECT, INPUT); //zero cross detect
digitalWrite(DETECT, HIGH); //enable pull-up resistor
pinMode(GATE, OUTPUT); //triac gate control

// set up Timer1
TCCR1 = 0; // stop timer
OCR1A = 50; //initialize the comparator
TIMSK = _BV(OCIE1A) | _BV(TOIE1); //interrupt on Compare Match A | enable timer overflow interrupt
sei(); // enable interrupts
// set up zero crossing interrupt
attachInterrupt(0,zeroCrossingInterrupt, FALLING); //
}

//Interrupt Service Routines
void zeroCrossingInterrupt(){
TCNT1 = 0; //reset timer - count from zero
TCCR1 = B00001000; // 1000 for 64 see table 12.5 of the tiny85 datasheet
}

ISR(TIMER1_COMPA_vect){ //comparator match
if(OCR1A>65){ //send no pulse to triac for low input voltage for 0v output
return;
}
digitalWrite(GATE,HIGH); //set triac gate to high
TCNT1 = 255-PULSE; //trigger pulse width, when TCNT1=255 timer1 overflows
}

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

void loop(){ // use analog input to set the dimmer
int instelwaarde = analogRead(INSTELPIN);
OCR1A = map(instelwaarde, 0, 1023, 70, 25);// 0v to 180v (220v input)
}

thanks again

I am using the above sketch code by ArthurRep as edited by mcvl as a "soft-starter" for a heating element.
This code limits the voltage output to 180V.
How would I change the code below to get a full 220V output:

void loop(){     // use analog input to set the dimmer
int instelwaarde = analogRead(INSTELPIN);
OCR1A = map(instelwaarde, 0, 1023, 70, 25);// 0v to 180v (220v input)
}

I would also like to change the functionality from reading an Analog input so that once power is applied, the TRIAC will switch:

//int instelwaarde = 1023;  // Output is 108V
int instelwaarde = 1020;  // Output is 127V
OCR1A = map(instelwaarde, 0, 1023, 70, 25);// 0v to 180v (220v input)

What value for "int instelwaarde =" would give me a full 220V output?

What exactly is: OCR1A = map(instelwaarde, 0, 1023, 70, 25);
Where:
instelwaarde = input value
0 = ?
1023 = ?
70 = ?
25 = ?

Your assistance is greatly appreciated.

hi,
For a soft start i suppose you increase Vin from 0v to 5v-->0 to 1023 (DAC conversion)
For 0v you need the max delay pulse :60-70 (need to be adjust because that cause flicking if you are over 10ms period)
for 5v you need the minimum delay for 220v :2
the final code is:

OCR1A = map(instelwaarde, 0, 1023, 70, 2);

regards

another precision:

the line in my code vs arthur

if(OCR1A>65){ //send no pulse to triac for low input voltage for 0v output
return;
}
is also to avoid the flicking and can be adjust up to 69 according to value of OCR1A (70 in this case)

instelwaarde=input value (0 to 1023)
regards

Hie;

I am bit new to this arduino family.... can anyone explain the entire code to me??

I am trying to code the same in proteus using c code. (AVRGCC)

The interrupt service routines for comparing and overflow are partially understood. I am not getting how

the following TWO code will be initiated? as a subroutine for interrupt ? and if yes then how?

void zeroCrossingInterrupt()

{
TCNT1 = 0; //reset timer - count from zero
TCCR1 = B00001011; // prescaler on 1024, see table 12.5 of the tiny85 datasheet
}

void loop()

{ // use analog input to set the dimmer
int instelwaarde = analogRead(INSTELPIN);
OCR1A = map(instelwaarde, 0, 1023, 65, 2);
}

I have read the map function. But for AVRGCC what will be equivalent code that can be used for reading

analog input and mapping ?

Also how

attachInterrupt(0,zeroCrossingInterrupt, FALLING);

can be used in C code?

Thank you in advance.

{archive_file_path}(wiring.c.o): In function __vector_4': C:\Users\Roma\AppData\Roaming\Arduino15\packages\digistump\hardware\avr\1.6.7\cores\tiny/wiring.c:93: multiple definition of __vector_4'
sketch_may24b.cpp.o:C:\Program Files (x86)\Arduino/sketch_may24b.ino:62: first defined here
collect2.exe: error: ld returned 1 exit status

Board - digispark.
IDE - 1.6.5

Hi,

Is it possible to use this code on 3.3v Arduino Pro-Mini for 4 channels of dimmer.

If so Can you please help me with the code changes.

Thanks

I am not able to compile the sketch given in arduino. i am using DigiSpark Module ATtiny85. Please help

error:

core\core.a(wiring.c.o): In function `__vector_4':

Hi,
I am using this code and circuit for 230V light dimmer, I am using ESP32 DAC(0 to 3.3V) outputs to feed ATTINY85 MCU control voltage, I see my light getting dimmed but getting constant flickering, Please help to fix it. Thanks.

Hello to all,
I need help to finalize my project. It is a solar router to send the excess of production to the hot water tank. I have two wattmeters PZEM-004T V3 of which I make the difference and I send a 0-5Vcc signal 0/5V towards the dimmer described here. Everything works.
I still have one small difficulty to overcome. I can refine the parameters of this line "OCR1A = map(instelwaarde, 0, 1023, 65, 2); ", the best I can achieve is 8.5 milliseconds of delay. I would like to get 10. Is this possible and if so what should I do?

Many thanks in advance!

--
Philippe

Here are two screen shots of the oscilloscope. The upper yellow trace shows the pulses shaped by a 2N7000. This way the edges are steep.
The blue trace at the bottom shows the pulses to the triac, measured at pin 2 of the ATtiny85. As you can see, the best delay I can get is 8.9ms!

Here is the schematic I designed and used.

What is the wattage of the 330 ohm resistor? Not sure how the gate of the triac works in terms of current draw, but assume it's limiting the current pretty substantially.

Otherwise 120 / 330 = ~360mA, 360mA * 120V = ~43.6W. Assume this isn't a 50W resistor. Just want to check how this works before building the circuit.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.