AC dimmer code issus

Hi there

I've found this code on the internet which dims AC output down which works fine. ( This is the code below)

int AC_LOAD = 5;    // Output to Opto Triac pin
int dimming = 128;  // Dimming level (0-128)  0 = ON, 128 = OFF
/* Due to timing problems, the use of ‘0’ can sometimes make the circuit 
flicker. It is safer to use a value slightly higher than ‘0’
*/
void setup()
{
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  attachInterrupt(0, zero_crosss_int, RISING);  
// Chooses '0' as interrupt for the zero-crossing
}
// the interrupt function must take no parameters and return nothing
void zero_crosss_int()  
// function to be fired at the zero crossing to dim the light
{
  // Firing angle calculation : 1 full 50Hz wave =1/50=20ms  
  // Every zerocrossing thus: (50Hz)-> 10ms (1/2 Cycle) For 60Hz => 8.33ms

  // 10ms=10000us
  // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65
  int dimtime = (75*dimming);    // For 60Hz =>65     
  delayMicroseconds(dimtime);    // Off cycle
  digitalWrite(AC_LOAD, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propogation delay
                                 //(for 60Hz use 8.33)
  digitalWrite(AC_LOAD, LOW);    // triac Off
}
void loop()  {
 for (int i=5; i <= 128; i++)
{
 dimming=i;
 delay(10);
 }
 }

What I'm trying to do is to control the AC output using a pot, I have tried doing this on the code below but the bulb seems to flash erratically what have I done wrong ?

int POT_pin = A3;             // Pot for testing the dimming
int AC_LOAD = 5;    // Output to Opto Triac pin
int dimming = 128;  // Dimming level (0-128)  0 = ON, 128 = OFF
int val =0;
/* Due to timing problems, the use of ‘0’ can sometimes make the circuit 
flicker. It is safer to use a value slightly higher than ‘0’
*/
void setup()
{
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  attachInterrupt(0, zero_crosss_int, RISING);  
// Chooses '0' as interrupt for the zero-crossing
}
// the interrupt function must take no parameters and return nothing
void zero_crosss_int()  
// function to be fired at the zero crossing to dim the light
{
  // Firing angle calculation : 1 full 50Hz wave =1/50=20ms  
  // Every zerocrossing thus: (50Hz)-> 10ms (1/2 Cycle) For 60Hz => 8.33ms

  // 10ms=10000us
  // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65
  int dimtime = (75*dimming);    // For 60Hz =>65     
  delayMicroseconds(dimtime);    // Off cycle
  digitalWrite(AC_LOAD, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propogation delay
                                 //(for 60Hz use 8.33)
  digitalWrite(AC_LOAD, LOW);    // triac Off
}
void loop()  { 

        val = analogRead(POT_pin) ;        // pont input
        dimming = map(val, 0, 1023, 0, 128);
 }

thanks Joe

        dimming = map(val, 0, 1023, 0, 128);

That's a rather slow way to (effectively) divide by 8. Surely you can find a much faster way.

How many times is map() interrupted while is it executing?

How many times is

   dimming = val << 3:

going to be interrupted?

Thanks for your reply I've tired that and it's still acting erratically any other ideas to over come this?
I
Thanks Joe

You appear to be using delayMicroseconds() inside an interrupt. I don't know about delayMicroseconds(), but you're definitely not supposed to use the regular delay() inside an interrupt. delayMicroseconds() might be part of your problem?

Yes I get what you are saying but on the other hand It does work when I'm not using a pot

Maybe your variable 'dimming' needs to be volatile?

volatile int dimming = 128;

Use serial.print to show what value of dimming is actually being set by your pot and confirm that the values are correct

But as has been previously mentioned, the code you downloaded is not very good.

Putting delays inside very problematic, because nothing else can happen while the delay is running,

There are numerous other postings on how to do this. Find some better code.
Preferably some code that uses the hardware timers to do the delay

Ps.

I wrote some code that does this but it uses 2 timers and requires either an Arduino Leonardo or Arduino Micro, as they use the Atmega32u chip that has an additional hardware timer

One more thought -- analog inputs are susceptible to noise, especially if you are using a high impedance pot (more than 10K). I assume you have the two ends of the pot connected to VCC and ground? What value is the pot?

tylernt:
Maybe your variable 'dimming' needs to be volatile?

volatile int dimming = 128;

Thanks for that I've tried it and its made no odds

Use serial.print to show what value of dimming is actually being set by your pot and confirm that the values are correct

Done that all ready readings look nice and smooth from 0 to 1023

I wrote some code that does this but it uses 2 timers and requires either an Arduino Leonardo or Arduino Micro, as they use the Atmega32u chip that has an additional hardware timer

Unfortunately my pcb is based around the ATmega328p so if I can get away using this I would prefer to.

One more thought -- analog inputs are susceptible to noise, especially if you are using a high impedance pot (more than 10K). I assume you have the two ends of the pot connected to VCC and ground? What value is the pot?

I am using a 10k pot and yes I have VCC and GND either side of the pot

I have also tried this code which I found on a Google search which I think divides the input from the pot into 8 ( correct me if im wrong)

#include <TimerOne.h>           // Avaiable from http://www.arduino.cc/playground/Code/Timer1

volatile int i=0;               // Variable to use as a counter
volatile boolean zero_cross=0;  // Boolean to store a "switch" to tell us if we have crossed zero
int AC_pin = 5;                // Output to Opto Triac
int POT_pin = A3;             // Pot for testing the dimming
int LED = 11;                    // LED for testing
int dim = 0;                    // Dimming level (0-128)  0 = on, 128 = 0ff

int freqStep = 65;    // This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want. 
// 
// The only tricky part is that the chopper circuit chops the AC wave twice per
// cycle, once on the positive half and once at the negative half. This meeans
// the chopping happens at 120Hz for a 60Hz supply or 100Hz for a 50Hz supply. 

// To calculate freqStep you divide the length of one full half-wave of the power
// cycle (in microseconds) by the number of brightness steps. 
//
// (1000000 uS / 120 Hz) / 128 brightness steps = 65 uS / brightness step
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave.

void setup() {                                      // Begin setup
  pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
  pinMode(LED, OUTPUT);                             // Set the LED pin as output
  attachInterrupt(0, zero_cross_detect, RISING);   // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
  Timer1.attachInterrupt(dim_check, freqStep);      
  // Use the TimerOne Library to attach an interrupt
  // to the function we use to check to see if it is 
  // the right time to fire the triac.  This function 
  // will now run every freqStep in microseconds.                                            
}

void zero_cross_detect() {    
  zero_cross = true;               // set the boolean to true to tell our dimming function that a zero cross has occured
  i=0;
  digitalWrite(AC_pin, LOW);
}                                 

// Turn on the TRIAC at the appropriate time
void dim_check() {                   
  if(zero_cross == true) {              
    if(i>=dim) {                     
      digitalWrite(AC_pin, HIGH);  // turn on light       
      i=0;  // reset time step counter                         
      zero_cross=false;    // reset zero cross detection
    } 
    else {
      i++;  // increment time step counter                     
    }                                
  }                                  
}                                      

void loop() {                        
  dim = analogRead(POT_pin) / 8;  // read dimmer value from potentiometer
  analogWrite(LED, dim);  // write dimmer value to the LED, for debugging
}

But once again I just get mad strobe effect or just stays on continually

I also tried this code off arduino website which seems to work fine but not using a pot

// AC Control V1.1
//
// This arduino sketch is for use with the heater 
// control circuit board which includes a zero 
// crossing detect fucntion and an opto-isolated triac.
//
// AC Phase control is accomplished using the internal 
// hardware timer1 in the arduino
//
// Timing Sequence
// * timer is set up but disabled
// * zero crossing detected on pin 2
// * 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 truns off triac gate
// * triac stops conducting at next zero cross


// The hardware timer runs at 16MHz. Using a
// divide by 256 on the counter each count is 
// 16 microseconds.  1/2 wave of a 60Hz AC signal
// is about 520 counts (8,333 microseconds).


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

#define DETECT 2  //zero cross detect
#define GATE 5    //triac gate
#define PULSE 4   //trigger pulse width (counts)
int i=483;

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 
  //(see ATMEGA 328 data sheet pg 134 for more details)
  OCR1A = 100;      //initialize the comparator
  TIMSK1 = 0x03;    //enable comparator A and overflow interrupts
  TCCR1A = 0x00;    //timer control registers set for
  TCCR1B = 0x00;    //normal operation, timer disabled


  // set up zero crossing interrupt
  attachInterrupt(0,zeroCrossingInterrupt, RISING);    
    //IRQ0 is pin 2. Call zeroCrossingInterrupt 
    //on rising signal

}  

//Interrupt Service Routines

void zeroCrossingInterrupt(){ //zero cross detect   
  TCCR1B=0x04; //start timer with divide by 256 input
  TCNT1 = 0;   //reset timer - count from zero
}

ISR(TIMER1_COMPA_vect){ //comparator match
  digitalWrite(GATE,HIGH);  //set triac gate to high
  TCNT1 = 65536-PULSE;      //trigger pulse width
}

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

void loop(){ // sample code to exercise the circuit

i--;
OCR1A = i;     //set the compare register brightness desired.
if (i<65){i=483;}                      
delay(15);                             

}

I have to wonder. Are you having a hardware problem or a software problem. Read the potentiometer, but do nothing with the result, hardcoding a dimming value. Does the problem persist?

Joes:

// AC Control V1.1

//
// This arduino sketch is for use with the heater
// control circuit board which includes a zero
// crossing detect fucntion and an opto-isolated triac.
//
// AC Phase control is accomplished using the internal
// hardware timer1 in the arduino

I would recommend you use this sketch as a base, since it uses the hardware timers, and add some pot analogRead() code to it.

I have to wonder. Are you having a hardware problem or a software problem. Read the potentiometer, but do nothing with the result, hardcoding a dimming value. Does the problem persist?

Yes I have tied doing a serial read on dim on this code below
I thought I had an hardware issues as well intill I noticed codes that not using the pots seem to work fine

#include <TimerOne.h>           // Avaiable from http://www.arduino.cc/playground/Code/Timer1

volatile int i=0;               // Variable to use as a counter
volatile boolean zero_cross=0;  // Boolean to store a "switch" to tell us if we have crossed zero
int AC_pin = 5;                // Output to Opto Triac
int POT_pin = A3;             // Pot for testing the dimming
int LED = 11;                    // LED for testing
int dim = 0;                    // Dimming level (0-128)  0 = on, 128 = 0ff

int freqStep = 65;    // This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want. 
// 
// The only tricky part is that the chopper circuit chops the AC wave twice per
// cycle, once on the positive half and once at the negative half. This meeans
// the chopping happens at 120Hz for a 60Hz supply or 100Hz for a 50Hz supply. 

// To calculate freqStep you divide the length of one full half-wave of the power
// cycle (in microseconds) by the number of brightness steps. 
//
// (1000000 uS / 120 Hz) / 128 brightness steps = 65 uS / brightness step
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave.

void setup() {                                      // Begin setup
  pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
  pinMode(LED, OUTPUT);                             // Set the LED pin as output
  attachInterrupt(0, zero_cross_detect, RISING);   // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
  Timer1.attachInterrupt(dim_check, freqStep);      
  // Use the TimerOne Library to attach an interrupt
  // to the function we use to check to see if it is 
  // the right time to fire the triac.  This function 
  // will now run every freqStep in microseconds.                                            
}

void zero_cross_detect() {    
  zero_cross = true;               // set the boolean to true to tell our dimming function that a zero cross has occured
  i=0;
  digitalWrite(AC_pin, LOW);
}                                 

// Turn on the TRIAC at the appropriate time
void dim_check() {                   
  if(zero_cross == true) {              
    if(i>=dim) {                     
      digitalWrite(AC_pin, HIGH);  // turn on light       
      i=0;  // reset time step counter                         
      zero_cross=false;    // reset zero cross detection
    } 
    else {
      i++;  // increment time step counter                     
    }                                
  }                                  
}                                      

void loop() {                        
  dim = analogRead(POT_pin) / 8;  // read dimmer value from potentiometer
  analogWrite(LED, dim);  // write dimmer value to the LED, for debugging
}

Ok tylernt I will have a go in the next few mins of adapting it to use a pot

Thanks everyone for help so far :smiley:

right i'm back with the strobes lol am i on the right lines here?

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

#define DETECT 2  //zero cross detect
#define GATE 5    //triac gate
#define PULSE 4   //trigger pulse width (counts)
int i=483;
int POT_pin = A3;             // Pot for testing the dimming

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 
  //(see ATMEGA 328 data sheet pg 134 for more details)
  OCR1A = 100;      //initialize the comparator
  TIMSK1 = 0x03;    //enable comparator A and overflow interrupts
  TCCR1A = 0x00;    //timer control registers set for
  TCCR1B = 0x00;    //normal operation, timer disabled


  // set up zero crossing interrupt
  attachInterrupt(0,zeroCrossingInterrupt, RISING);    
    //IRQ0 is pin 2. Call zeroCrossingInterrupt 
    //on rising signal

}  

//Interrupt Service Routines

void zeroCrossingInterrupt(){ //zero cross detect   
  TCCR1B=0x04; //start timer with divide by 256 input
  TCNT1 = 0;   //reset timer - count from zero
}

ISR(TIMER1_COMPA_vect){ //comparator match
  digitalWrite(GATE,HIGH);  //set triac gate to high
  TCNT1 = 65536-PULSE;      //trigger pulse width
}

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

void loop(){ // sample code to exercise the circuit

 i = analogRead(POT_pin) / 8;  // read dimmer value from potentiometer

i--;
OCR1A = i;     //set the compare register brightness desired.
//if (i<65){i=483;}                      
//delay(15); 

}

I don't know much about dimming AC but this:

//if (i<65){i=483;}

Seems like it might be important.

I thought that the line of code was what was dimming the output so I was replacing that line of code with

i = analogRead(POT_pin) / 8;

Or am I incorrect?

Yes you should still divide the analogRead by 8, but in addition to that, if (i<65){i=483;} seems to keep the output value within a certain bound. Maybe bad things happen when i is less than 65?

ok cool

Rite I have this at the moment

void loop() {
i--;
OCRIA = i;
if (i<65) {i=483;}
i = analogRead(POT_pin) / 8;
delay(15);
}

When you turn the pot one way light comes on full brightness and as you just turn it off to stop it goes out.

Obviously I'm still miles off lol

I think you want

void loop() {
i = analogRead(POT_pin) / 8;
i--;
if (i<65) {i=483;}
OCRIA = i;
delay(15);
}

still not working, just on or off :~

through out this thread, I've constantly read that the use of a pot exacerbates the control stability and I wonder about 3 things,

  1. how long are the pot wires?
  2. have you tried a 10 to 100uF bypass capacitor on the pot or on the pcb where the pot supply and ground connects
    And
  3. have you tried a 10 to 100 nF bypass capacitor from the pot wiper (the pot center lead usually)
    What you describe could well be caused by the switching transients coupling to the pot center wire

Doc