Newbe in AVR - Triac phase control

Go To Last Post
31 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi everybody,

First of all, sorry for my poor english (I am learning).
I am trying to control a Triac through an ATMega16 running with Xtal of 11,0592MHz.
I have already built a zero crossing detector, generating a 120Hz signal and I attached them to the INT0. All right, INT0 is working and I am using the falling edge of the zero crossing signal. My main source is 60Hz, so each period have 16,666 ms. The Triac's gate is optocoupled through PD5.

Well, I would like to enable the Timer 1 every time that a zero cross were detected, to count at least 5 ms and after this to count a variable period between 0 and 4,5 ms (or almost that). The aim is to control the Triac's gate to obtain a kind of dimming.

Ok, I wrote the following code to do the first part of this issue. But the Timer1 is varying it period.
I will appreciate if anybody could help me to find my error. As I said, I am new in AVR and I really would like to learn with you.

// Initializations ------------------
//
void X0_Init(void)    // Init INT0 (is working)
{
 DDRD &= ~_BV(PD2);    // PD2 as input (120Hz)
 PORTD &= ~_BV(PD2);   // Disable pullups
 MCUCR |= (1<<ISC01);  // Interrupt on falling edge
 GIFR |= (1<<INTF0);   // Clear interrupt flag of INT0
 GICR |= _BV(INT0);    // Enable INT0
}
//
void T1_Init(void)    // Init Timer 1
{
  TIMSK |= _BV(OCIE1A); // Output compare int. enable
  TCCR1B |= _BV(CS12)   // Prescaler of 256
         | _BV(WGM12);  // CTC mode, TOP = OCR1A
  OCR1A = 150;          // Any value, just for test
}

// Interrupts vectors ----------------
//
// For INT0 interrupt
//
SIGNAL (SIG_INTERRUPT0)
{
 cli();	             // Disable all interrupts
 OCR1A = 150;        // Any value, just for test
 PORTD |= _BV(PD5);  // Gate ON
 sei();              // Enable all interrupts
}
//
// For Timer 1 interrupt
//
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
 PORTD &= ~_BV(PD5); // Gate OFF
}

// Main program:
//
int main(void)
{
 cli();                // Disable all interrupts

 DDRD |= (1<<PD5);     // PD5 as output
 PORTD |= (1<<PD5);    // Drive Hi
 PORTD &= ~_BV(PD5);   // Gate OFF (PD5)

 OCR1A = 0;         // I don't know why I wrote this
                    // but seems do none difference

 sei();             // Enable all interrupts

 for (; ;)	    // Infinite loop (do nothing)
  {
  }
  cli();	    // Never reached
  return(0);        // May be reset
}

When I attach a scope to the PD2 and to the PD2, the Timer1 signal (PD5 = Triac's gate) is phased with the PD2 signal (zero cross), but is varying the period. What is wrong ?

Best regards.

PS: I am using Timer 0 in output compare mode to generate interrupts every 5 ms (system tickets) to build a kind of RTC (only seconds, minutes and hours). Is working.

Quote:

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First of all, you need to clear the timer at the zero crossing. I would stop it after it times out and reload and restart it at zero crossing.

Also, you need to detect both positive and negative going crossings. The phase control should be applied to both half-cycles.

You appear to be turning on the triac right after zero crossing and then trying to turn it off after some delay. This won't work, a triac will not turn off until the next zero crossing. You can turn it on after some delay then turn it back off and it will continue to conduct until the next zero crossing.

Hope that helps,
Randy

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your post Randy,

I beg your pardon. I think I didn't understand regarding to clear the timer at zero crossing. Reloading OCR1A at zero crossing is not enough ? Could you please show me an example?

Regarding detection of both positive and negative zero crossing, you are right. I am already doing this. The INT0 generates interrupts at 120Hz (the main source is 60Hz).

You are right also regarding Triac firing. In fact, the Triac turn off at next zero crossing, I really know that. Just I don't know how to use the Timer 1 to do that. So I will appreciate some examples.

Anyway, thank you very much for the time you expend with me.

Best regards.

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Maybe some of these app notes can help
http://www.littelfuse.com/cgi-bi...

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you Lennart, very good references. In fact, excepting ADC, the U16498EE1V1AN00.pdf describe what I am trying to do. But how I am newbie in AVR, I am trying to start from the beggining. I think my main obstacle is understand how to exactly use the Timer 1.
Anyway, thank you very much for your post.
I will keep trying, I promise.
Regards

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Liontec wrote:
Thank you for your post Randy,

I beg your pardon. I think I didn't understand regarding to clear the timer at zero crossing. Reloading OCR1A at zero crossing is not enough ? Could you please show me an example?

Regarding detection of both positive and negative zero crossing, you are right. I am already doing this. The INT0 generates interrupts at 120Hz (the main source is 60Hz).

You are right also regarding Triac firing. In fact, the Triac turn off at next zero crossing, I really know that. Just I don't know how to use the Timer 1 to do that. So I will appreciate some examples.

Anyway, thank you very much for the time you expend with me.

Best regards.

When the timer compare occurs and you have the CTC mode enabled, the timer will start back at zero. You want this to synchronize with zero crossings. I would load the timer with zero and enable it in the zero crossing interrupt and then stop the timer when the output compare match fires. You only need to load OCR1A when you want to change the pulse width.

Randy

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've lived on Earth for 56 years and never knew about Florianopolis Brazil until today. Welcome Liontec. Your English is 1000% better than my Portuguese.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A couple of things to remember - you need to turn the triac off about 500uS before zero crossing otherwise it may hold on for the next cycle. Also, the derived zero crossing pulse may not exactly co-incide with real zero crossing so you need to compensate for this. Especially if you filter the zero crossing - which is what you need to do otherwise the dimmer will flicker when other devices are turned on/off on the mains.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you guys,

Now I got the idea, Randy. Thanks!

Wellcome Bob, Florianópolis is in south region of Brazil. We have beaches like in yours Florida, but in August we have some cold. Anyway, is a beautyfull place. I was in Orlando in 1980, and also in Tampa, and I never will forget these travel. I liked so much.

Hello Kartman, thank you for your post. Very instructive. I confess that I don't know how to do that exactly, but I will remember your advise.

Man, this forum is incredible ! Peoples of all our world joined to help a little newbie like me. Oh! man, I am so thanks!

Just for illustrate, with the code I posted, the signals appear like in the following image:

Why the Timer 1 is varying ?

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Because you don't synchronize the timer to INT0.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Jayjay. However I didn't understand, could you please explain better? May be an example helps.

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Use normal timer mode and the overflow interrupt. On each ZC you set TCNT to your delay value (higher value means shorter time) and deassert the triac gate control pin. In the overflow ISR you disable the timer and fire the triac. Disabling of the timer can be done by stopping it. Don't forget to start it again on each ZC :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK Jayjay, I will try to do that.
Later I will post the results.
Regards.

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh! man, I am almost staying lazy! I think my brain will blow up!

My code doesn't work and I have no idea how to deal with Timer 1. To start and stop the Timer, set or reset it prescaler bits isn't enough?

Please masters of the AVR world! Could anybody post a little code example to light my soul?

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Set CS2..0 to zero to stop. Table 48 on page 112/113 in the datasheet.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am boring Jayjay, I already did that! I did change all code, but it still not working.
I think I will explode my prototype and put my mind in sleep mode until next interrupt wake me to other reality.
By the way, I was thinking about your signature question, and I have a posible answer:
"The other half of the time, programmers search answers in forums like this."

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Post your current code and we might be able to pinpoint the problem ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Goods news man! :D Seems I will survive! I put the following code in the AVR and now I have a beautyfull stable wave on PD5. Thank you Jayjay for light my mind!

Anyway, I really thank you so much and I invite you and anyone that wants to be my Tutor, to follow my newbie steps to growing up until the dimmers come alive and dimmer us with it light. :oops:

Just to remember, I am using Xtal of 11,0592MHz on ATMega16, and the Zero crossing is detected at 120Hz, like in the image I earlier posted.

Ok, for the TCNT1 register I did calculate:
Xtal/Prescaler=Clock_Frequency, where Xtal=11059200Hz and Prescaler=256.
So 11059200/256=43200Hz, and then the period will be 1/43200Hz=23.148us
This means that each Timer_1 count will spend 23.148us.
I wish 10000Hz (0,1ms) resolution, because the main source full wave will spend 1/60Hz=16,667ms and I wish to control the Triac firing angle some degrees.
So, to delay for example 5ms, I need to count 5ms/23.148us=216.
However, the Timer_1 overflows at 65536. Then TCNT1 must be loading with 65536-216=65320. Am I right? I think so!

Well, now I know that TCNT1 must be set with 65320 to generate a delay of 5ms.

// Initializations ------------------ 
// 
void X0_Init(void)    // Init INT0 (it is working fine) 
{ 
 DDRD &= ~_BV(PD2);    // PD2 as input (120Hz) 
 PORTD &= ~_BV(PD2);   // Disable pullups 
 MCUCR |= (1<<ISC01);  // Interrupt on falling edge 
 GIFR |= (1<<INTF0);   // Clear interrupt flag of INT0 
 GICR |= _BV(INT0);    // Enable INT0 
} 
// 
void T1_Init(void)    // Init Timer 1 in normal mode
{ 
  TIMSK |= _BV(TOIE1);  // Overflow int. enable 
  TCCR1A = 0;             // Normal mode
  TCCR1B |= _BV(CS12);  // Prescaler of 256 
  TCNT1 = 65320;       // Preload to 0,1ms
} 

// Interrupts vectors ---------------- 
// 
SIGNAL (SIG_INTERRUPT0)   // For INT0 interrupt
{ 
 TCNT1 = 65320;       // Reload to 0,1ms
 PORTD &= ~_BV(PD5); // Gate OFF 
} 
// 
SIGNAL (SIG_OVERFLOW1)   // For Timer 1 interrupt
{ 
 PORTD |= _BV(PD5);  // Gate ON 
 TCNT1 = 65320;       // Reload to 0,1ms
} 

// Main program --------------------- 
// 
int main(void) 
{ 
 cli();                // Disable all interrupts 

 DDRD |= (1<<PD5);     // PD5 as output 
 PORTD |= (1<<PD5);    // Drive Hi 
 PORTD &= ~_BV(PD5);   // Gate OFF (PD5) 

 sei();              // Enable all interrupts 

 for (; ;)           // Infinite loop (do nothing) 
  { 
  } 

  cli();              // Never reached 
  return(0);       // May be reset 
}

OK, with this code my waves seems like below:

Now I am ready to next step, that is to fire the Triac in the right way. Until now the intention was to have the Timer_1 delaying synchronized with the Zero Cross detection. :D

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
65536-216=65320. Am I right? I think so!

That's right ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just fell over this Word Document

http://www.avorex.com/TRIAC.doc

Seems verry informative , even though the uC selection is "questionable" :-)

Edit: And the code
http://www.avorex.com/TRCODE.zip

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thak you Bingo, you provide very good informations with your post. I recomend to anybody that would like to build something like this, to read it contents.
Wellcome Bingo from Denmark!
Best regards.

Teach is learn twice. So, what do you think regarding learn again?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Guyzz

I have been grumbling about how to calculate those "Phase Angle Correction" lookuptables that are being used in various examples on the net.

I snipped this (In german)
http://www.mikrocontroller.net/t...

For Intensityvalue X(0-256) in a Halfwave use this (the 10 ms must be a 50hz ½ period) 

Triggerpoint = arcos((X/128)-1)*10ms/PI

Can anyone verify this ???

I also found this from toshiba
http://www.toshiba-components.co...

But it seems to be for a motor ,, and could "Easily be modified to a heater or a lightbulb"

Easily ..... Does anyone know what to modify ??

Is the cos-1 (the -1 is lifted above cos) ...the same as arccos ??

This relation is quite convenient in some ways as it gives gentle control at low levels and coarser
control at mid power levels. However the symmetry of the curve means it also gives similar fine
control near the maximum power so that change in input voltage will appear to have very little effect
in this region. The software therefore implements a look up table to convert values of input demand
to output phase angle.
The example uses a table which has approximately equal steps in average voltage for equal changes
in input demand.
The table has 255 elements, corresponding to the 255 possible values for input demand voltage that
can be read from the input ADC. For simplicity the values in the table are scaled into the region 0-255
as well. This allows the table translation to be invoked or not as required without having to alter the
scales assumed by the remainder of the software.

In general, the value of any element n is given by

Table element = (255/pi)("cos-1" * (1-(255-2n/255))

Thus for input demand position 1, the value in the table is :-
= (255/p)(cos-1(1-(253/255))
= 10.17 (10 used)
The look up table therefore gives a linear relation between demand and average voltage out. This
table could be easily modified to provide a linear output of RMS voltage for power control of a heater,
or could be used to compensate for the typical characteristics of a lamp so as to give, for example, a
light output level that was proportional to the input demand voltage

Edit: Corrected the formula from paste errors.

Edit2: It seems like they use this in source code

// y = sin(x)
// integrating to get area under graph
// y = -cos(x) + 1
// y: speed
// x: pulse width length

// actually used:
// x = 255 * acos(-(2 * y / 255 - 1)) / pi
// 0 <= y <= 255, plus don't forget + 0.5 rounding when converting to int

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just tested the equation in Dev-C++


   int x,y;

   i=0;
   printf("\n\r");
   for(y=0;y<=255;y++)
   {

     x = 0.5 + 255 * acos(-(2.0 * y / 255 - 1)) / M_PI ;
     printf("%4d,",x); 
     //printf("  %04f,",x); 
     if(i++ >=7)
     {
            i=0;
            printf("\n\r");
     }
   }
   printf("\n\r");
   system("pause");

The calculations matches the table in the source.

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmmm .... :( :(

Thought there were some triac/dimmer gurus in here

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The classic 's' curve. As to whether you need to do this is debateable. Using the lookup table gives you linear power output but is this what you want? Since we're controlling a lamp load, do you not want linear light output? Different types of lamps give you different responses. Also consider in a domestic environment, the lamp levels will be set to suit, rather than a specific value. The problems creep in when you have widely differing lamp types like fluorescent and incandescent that have widely differing input/light output responses - when these are mixed in the same situation, it may be wise to linearise the response to give a better effect when fading.

As for phase control dimming, do a search on my previous posts on the subject. I describe a method of phase and frequency looking the zero cross signal that only needs to be at the frequency of interest (50/60hz) and can have a phase error that the software corrects. This makes the dimmer more immune to interference and allows you to pick the zero cross signal from the low voltage side of a transformer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have just started a project using a Baby Oragutan ATMega168 and a couple cascaded Littelfuse(Tecor) alternistors to control a 9000W heating system. The calculations and suggestions you have provided here define the requirements for most of the work I would have had to desigened myself.
This was a gold mine for me.
I am currently waiting on the parts but have been actively simulating the project. The register naming convention for the m168 required a lot of study to convert a lot of the existing sourse code over and to get it to compile.
I also ordered a 128x64 led back lighted lcd graphical display to use with the finished design.
If I get the major functionallity done I might add a dual thermocouple interface using the ADC channels.
If I scale the output using op amps I should be able to get great resolution in the 70°C to 100°C range.
I'll have to search the forum for information about getting the AVR to store data on a USB stick or a SD card for logging.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thermocouples probably aren't the best choice for 70-100C. If you want accuracy - PT100 might be a better choice, or for a simpler interface there are many semiconductor sensors that work within your temperature range.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unfortunately, almost all of them are extremely non-linear and extremely hard to calibrate. I am still considering alternatives though. If you have specific parts in mind I will look at their data sheets. The sensors have to be able to function in a harsh, solvent laden environment.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Something like the Dallas DS1820 - no calibration and linearity issues. If there is explosive gases or vapours present you will need to take special precautions regardless of the sensor you choose.

Also, I wouldn't bother with alternistors, I'd just use something like the Semikron SKKT series dual thyristors. For 10amp loads I use a 41A dual thyristor for reliability. The SKKT series can be protected with just a thermal/magnetic circuit breaker and they will survive short circuits whereas less robust devices require fast semiconductor rated fuses that are expensive. Mind you, the Semikron devices will be 10 times the price of an alternistor, but they will survive where the alternistors will fail. Check the i2t specs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As far as the Dallas device is concerned, it looks nice but I am hoping for more resolution.
The SKKT devices don't offer one of the things I was hoping for and that is single trigger voltage polarity. The alternistors are providing all that and very low input current when used as a cascade pair at a quarter the price.
If I want opto isolated devices I tend to use the Crydom devices which have about the same performance as the skkt at about the same price. I like driving these directly off the parallel port of my pc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Guys,

Sorry by my delay in join again. I am not dead, but I am working a lot in other projects (I need to survive, yeah?) so I did have no time to continue (for a while). But I would like to growing this discussion because I am learning so much with all of you. Thank tou very much for your patient. Soon I will come back (wait for me).
Regards.

Teach is learn twice. So, what do you think regarding learn again?