Probelms with Heater control example

So from arduino we have the zero cross detection ac phase control, I modified it with some debugging because the code doesn't work.

// 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 9    //triac gate
#define PULSE 4   //trigger pulse width (counts)
int i=483;

void setup(){

  Serial.begin(9600);
  // set up pins
  pinMode(DETECT, INPUT);     //zero cross detect
//  digitalWrite(DETECT, HIGH); //enable pull-up resistor (don't do this as circuit contains pull-up)
  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
  Serial.println("Trigger")
}

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

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

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

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

}

So nothing happens, in the serial monitor I get the word "Trigger" but I never get a high or a low and the triac never fires, anyone got any help?

You've put a Serial call in an ISR - doesn't work. You cannot use delay() or Serial or anything else inside
an ISR that itself waits for interrupts to happen.

I debug ISR's using digitalWrite () on a spare pin and hooking an oscilloscope to that pin - typically
I'd set the pin on entry and clear on exit, then you can see when and for how long it runs.

So I made it write to pin 3 with an attached interrupt on 1, should this work? No output still

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

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

void setup(){

  Serial.begin(9600);
  // 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);
  attachInterrupt(1,thingy, CHANGE);  
    //IRQ0 is pin 2. Call zeroCrossingInterrupt 
    //on rising signal

}  
void thingy(){
  Serial.println("Change");
}

//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
  digitalWrite(3,HIGH);
}

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

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

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

}
[code]

gundark2:
So I made it write to pin 3 with an attached interrupt on 1, should this work? No output still

#include <avr/io.h>

#include <avr/interrupt.h>

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

void setup(){

Serial.begin(9600);
  // 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);
  attachInterrupt(1,thingy, CHANGE); 
    //IRQ0 is pin 2. Call zeroCrossingInterrupt
    //on rising signal


void thingy(){
  Serial.println("Change");
}

//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
  digitalWrite(3,HIGH);
}

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

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

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

}

[code]

So I forgot to pinmode(3, OUTPUT) making progress now

OK, im really confused now

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

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

void setup(){

  Serial.begin(9600);
  // set up pins
  pinMode(DETECT, INPUT);     //zero cross detect
//  digitalWrite(DETECT, HIGH); //enable pull-up resistor
  pinMode(GATE, OUTPUT);      //triac gate control
  pinMode(3, OUTPUT);

  // 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);
  attachInterrupt(1,thingy, CHANGE);  
    //IRQ0 is pin 2. Call zeroCrossingInterrupt 
    //on rising signal

}  
void thingy(){
  Serial.println("Change");
}

//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
  digitalWrite(3,HIGH);
}

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

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

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

}

So now for some reason the triac is firing, but it doing one second blinks of a light bulb, man I'm lost.

So I think why its blinking is that im moving to the other side of the ac wave and its not firing on that part of the wave, but Im really just grasping at straws here.

I'm just curious, what kind of load are you controlling with
the TRIAC?
A 1 second cycling might be that a glitch is resetting the uP.
Dwight

So from arduino we have the zero cross detection ac phase control, I modified it with some debugging because the code doesn't work.

In fact, given that it is example code I would expect it to be correct and there may be a hardware problem.

Are you using the circuit posted with the sample code Arduino Playground - ACPhaseControl

Are you using the H11AA1 as a zero cross detector? Do you have a 10K pullup reisistor on the output of the H11AA1.

To confirm the zero cross detection, I would try a simple sketch to count interrupts on pin2 DETECT and see if you are indeed getting two per AC cycle. Your having seen the word "trigger" doesn't give me confidence that you have the zero crossing interrupt you expect.

volatile unsigned long  count = 0;
unsigned long copyCount = 0;

unsigned long lastRead = 0;
unsigned long interval = 1000;//one second

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");
  
  pinMode(2,INPUT_PULLUP);
  attachInterrupt(0, isrCount, RISING); //interrupt signal to pin 2
}

void loop()
{
  if (millis() - lastRead >= interval) //read interrupt count every second
  {
    lastRead  += interval;
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    count = 0;
    interrupts();
 
    Serial.println(copyCount);

  }
}

void isrCount()
{
  count++;
}

You didn't state which processor you are using.
The pin to interrupt is different for different processors.
Dwight

dwightthinker:
I'm just curious, what kind of load are you controlling with
the TRIAC?
A 1 second cycling might be that a glitch is resetting the uP.
Dwight

Currently I am controlling a light bulb just for testing purposes.

cattledog:
In fact, given that it is example code I would expect it to be correct and there may be a hardware problem.

Are you using the circuit posted with the sample code Arduino Playground - ACPhaseControl

Are you using the H11AA1 as a zero cross detector? Do you have a 10K pullup reisistor on the output of the H11AA1.

To confirm the zero cross detection, I would try a simple sketch to count interrupts on pin2 DETECT and see if you are indeed getting two per AC cycle. Your having seen the word "trigger" doesn't give me confidence that you have the zero crossing interrupt you expect.

volatile unsigned long  count = 0;

unsigned long copyCount = 0;

unsigned long lastRead = 0;
unsigned long interval = 1000;//one second

void setup()
{
 Serial.begin(115200);
 Serial.println("start...");
 
 pinMode(2,INPUT_PULLUP);
 attachInterrupt(0, isrCount, RISING); //interrupt signal to pin 2
}

void loop()
{
 if (millis() - lastRead >= interval) //read interrupt count every second
 {
   lastRead  += interval;
   // disable interrupts,make copy of count,reenable interrupts
   noInterrupts();
   copyCount = count;
   count = 0;
   interrupts();

Serial.println(copyCount);

}
}

void isrCount()
{
 count++;
}

I am using the circuit from the ACPhaseControl, the only modification I have is that instead of the Triac and the MOC3052 I am using an SSR. I took a look at the data sheet and a breakdown of one of the units and that portion of the circuit, the Triac driver, is what is contained inside the SSR.

dwightthinker:
You didn't state which processor you are using.
The pin to interrupt is different for different processors.
Dwight

I am using a pro mini 5v with the atmega 328, which I thought seemed to be what they were using. I am going to do as you suggested and report back my findings.

So here is the output from your code, thank you by the way.

start...
121
120
120
120
120
120
120
121
120
120
120
120
120
120
120
120
120
120

So I have been tinkering to in my free time with code.

#include "TimerOne.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include "ACPWM.h"

#define DETECT 2  //zero cross detect
#define GATE 9    //triac gate

int ACT = 0;
int TS = 0;
int dcount = 0;
int delayTime = 1000;
float multiplyByFactor = 0.95;

void setup() {

//    ACpwm.initialize(60,DETECT,RISING,GATE,0);  
//  Serial.begin(9600);
// put your setup code here, to run once:
//  Timer1.initialize(16666); //Fraction of time for event, 1 sec 1000000
//  Timer1.pwm(9,512); //pinnumber,percentege of time with gate on, 100% is 1024
  // set up pins
  pinMode(DETECT, INPUT);     //zero cross detect
  pinMode(GATE, OUTPUT);      //triac gate control

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

}

void loop() {
    delayMicroseconds(TS);
    digitalWrite(GATE, HIGH);   // sets the LED on
    delayMicroseconds(200);     // waits for a bit
    digitalWrite(GATE, LOW);    // sets the LED off
    if(TS == 3000) TS=0;
}

void zeroCrossingInterrupt(){ //zero cross detect   
  ACT++;
  if(ACT=240)  {
    TS++;
    ACT=0;
  }
//  delayMicroseconds(55);
//  digitalWrite(GATE, HIGH);
//  delayMicroseconds(40);
//  digitalWrite(GATE, LOW);
}

So this starts with the bulb on full brightness, then as time goes on it kind of dims, but it has a horrible flicker. As well, every now and then I get a spike of full brightness as it moves down the scale of dimming. So I know that I should probably have a scope, I am currently in the process of saving up for one. But I know I can get the triac to fire, does this tell you guys anything?

You are not triggering based on the zero cross, you
are triggering based on some delay from the loop.
What you are seeing is called beating. The loop has a
a different time relative to the zero crossing.
Some times it is close to a harmonic. Those are the times you
see funny behavior.
To use zero crossing properly, you have to turn on the light
at the same part of the cycle and then off. You must wait
until the next zero cross.
The speed of your loop is much faster than 60 cycles,
varies in duration and is not synchronized to the zero cross.
Also, you comments should be correct. If your turning on a
SSR the comment should say that.
Dwight

the only modification I have is that instead of the Triac and the MOC3052 I am using an SSR. I took a look at the data sheet and a breakdown of one of the units and that portion of the circuit, the Triac driver, is what is contained inside the SSR.

If that is the case, and you are indeed getting the zero crossing pulse then the Playground example code should work.

So I have been tinkering to in my free time with code.

I am not familiar with the library you are using, and the code you have written is faulty as dwightthinker has pointed out.

I would recommend going back to the AC phase control example code and getting it to work. If it doesn't work as expected, I would still suspect your hardware. Can you provide a link to the data sheet of our output SSR and a sketch to sho how you have it connected?

cattledog:
If that is the case, and you are indeed getting the zero crossing pulse then the Playground example code should work.

I am not familiar with the library you are using, and the code you have written is faulty as dwightthinker has pointed out.

I would recommend going back to the AC phase control example code and getting it to work. If it doesn't work as expected, I would still suspect your hardware. Can you provide a link to the data sheet of our output SSR and a sketch to sho how you have it connected?

http://www.datasheetspdf.com/mobile/789332/SSR-40DA.html page 3 shows the inside of the relay.

I don't know much about posting on forums so I don't know how to post a sketch, if someone doesn't mind telling me how they do it I would be happy to.

I have made progress with the original sketch, if I take this line

#define PULSE 4   //trigger pulse width (counts)

and change 4 to (40-520) The light bulb blinks, the closer to 40 the shorter the time period is the light is on, once I get to 520 the light just stays on constantly)

With PULSE set at 200 the light is on for 4 seconds off for 6

I looked at the data sheet, and I believe that the SSR has a built in zero crossing detector circuit, and is not the random fire type required for this application.

I think this is confirmed by your experience with the pulse width setting.

From the code posted, Timer1 is set with a prescaler of 256, so that each tick is 16 microseconds long.When you change the Trigger pulse to 520 the trigger pulse width will be 8.3ms which is long enough to make the internal zero cross trigger find the next zero crossing at 60Hz.

So from what I think I understand you saying my hardware is not capable of dimming, at least not with this method?

So from what I think I understand you saying my hardware is not capable of dimming, at least not with this method?

Yes, that is what I think.

The response of your heater is going to be relatively slow.
If you have a zero cross detector added, you can fire the
SSR relative to the cycle timing. The increments are only 8.333..
milliseconds but you can add or subtract an extra half cycle
to average the difference.
For a light, you need to be able to trigger at a random point during
the cycle, based on knowing where the zero cross was.
Remember, a heating element reacts a lot slower than a light.
Dwight

gundark2:
Currently I am controlling a light bulb just for testing purposes.

I am using the circuit from the ACPhaseControl, the only modification I have is that instead of the Triac and the MOC3052 I am using an SSR. I took a look at the data sheet and a breakdown of one of the units and that portion of the circuit, the Triac driver, is what is contained inside the SSR.

I am using a pro mini 5v with the atmega 328, which I thought seemed to be what they were using. I am going to do as you suggested and report back my findings.

Aren't SSRs only able to control DC?

Or am I confusing that with an SCR?