Help! Problem with triac firing control.

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

I build a dimmer using phase firing control and the result is in picture below. I use AVR GCC to compile this code:

#define F_CPU 12000000UL
#include 
#include 
#include 

void delayms(uint16_t millis) 
{
	while (millis)
	{
		_delay_ms(1);
		millis--;
	}
}

void delayus(uint16_t micros) 
{
	while (micros)
	{
		_delay_us(1);
		micros--;
	}
}


int main(void)
{

DDRB=0x01;
    
DDRD=0x00;      // PD2 (INT0 pin) is now an input    
    
MCUCR |= (1 << ISC01);    // Falling edge
    
GICR |= (1 << INT0);      // Turns on INT0

sei();                    // turn on interrupts


  while (1) 
   {}	
  return 0;
}


ISR (INT0_vect)
{
  PORTB=0x00;
  delayms(5);       // 50% brightness
  PORTB=0x01;       //
  delayus(10);      // firing pulse width 10us
  PORTB=0x00;
}

Why the green wave does not change? even I vary the delay time (1 until 9ms), it still look like that.

Pls guide me to solve my problem?

Attachment(s): 

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

Show us your circuit.

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

Using your delays from the ISR is not good!

It all starts with a mental vision.

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

kk6gm wrote:
Show us your circuit.

[/img]

Attachment(s): 

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

KitCarlson wrote:
Using your delays from the ISR is not good!

Why? What are the reasons?

Can you show me something "GOOD"?

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

Using delays in an isr is not good as you tie up the isr for too long. The timers have a compare function that is useful for phase control that will give you more precise delays without processor intervention. If the oscilloscope display is from a simulation, then the simulation doesn't know to turn the triac off as it would in the real world.

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

It seems your triac U7 is always opened.
I would try to ground the point B0. The bulb should go off.

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

Dondody wrote:
KitCarlson wrote:
Using your delays from the ISR is not good!

Why? What are the reasons?


Because in most real-world embedded systems, there is always some other work that the processor can be doing. Here, depending on your brightness setting, you could be wasting 90% or more of your processor time in a delay, and holding off other interrupts for as much as 9 or 10ms. That's enough time to miss e.g. 20 incoming characters at 19200 baud. You can often get away with long software delays (> 10s of microseconds) in simple educational programs, but it's a very bad habit to get into. Instead, for timing-related events learn to use all the features of your timers: interrupts, capture inputs and compare outputs.

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

Quote:
Because in most real-world embedded systems, there is always some other work that the processor can be doing. Here, depending on your brightness setting, you could be wasting 90% or more of your processor time in a delay, and holding off other interrupts for as much as 9 or 10ms. That's enough time to miss e.g. 20 incoming characters at 19200 baud. You can often get away with long software delays (> 10s of microseconds) in simple educational programs, but it's a very bad habit to get into. Instead, for timing-related events learn to use all the features of your timers: interrupts, capture inputs and compare outputs.

Well, do you have any references for learning the features you've mentioned?? An example may easier to understand?

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

Dondody wrote:
Quote:
Because in most real-world embedded systems, there is always some other work that the processor can be doing. Here, depending on your brightness setting, you could be wasting 90% or more of your processor time in a delay, and holding off other interrupts for as much as 9 or 10ms. That's enough time to miss e.g. 20 incoming characters at 19200 baud. You can often get away with long software delays (> 10s of microseconds) in simple educational programs, but it's a very bad habit to get into. Instead, for timing-related events learn to use all the features of your timers: interrupts, capture inputs and compare outputs.

Well, do you have any references for learning the features you've mentioned?? An example may easier to understand?

Not offhand. Have a look in the tutorial section. But the basic idea is simple enough: (pseudocode)

ZC_ISR()
{
  set_timer_to_0;
  set_timer_compare_to_desired_delay;
}

COMPARE_ISR()
{
  fire_triac;
}

Now you have 2 interrupts per half-cycle, but the total time spent in ISRs is only a few microseconds rather than milliseconds.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ZC_ISR()
{
  set_timer_to_0;
  set_timer_compare_to_desired_delay;
}

COMPARE_ISR()
{
  fire_triac;
}

Is this in CTC mode?

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

Dondody wrote:

ZC_ISR()
{
  set_timer_to_0;
  set_timer_compare_to_desired_delay;
}

COMPARE_ISR()
{
  fire_triac;
}

Is this in CTC mode?


No, because there's no benefit to clearing the timer back to 0 at the compare. You don't clear the timer until the next zero crossing.

Actually, a more jitter-free method might be (thinking on the fly here) to use the ZC to trigger an input capture, and on the associated interrupt, add the desired wait value to the capture value and write that value into the compare register.

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

Ctc mode? Probably not. There's a number of open sourve light dimmers based on avrs on the web.

I've described a technique i use at least once on thesr forums. I use a capture and compare channel.

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

Dondody,
I share the same thoughts as Kartman, use the timer in the free running mode, the input capture and output compares work together.

Much information on timer application can be found in the datasheet. There are a huge number of applications, correct use of timers is essential in embedded control.

I find starting simple and verifying, then adding functionality helps both in learning and the progress of a project.

It all starts with a mental vision.

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

OK, I try to use timer.
Now I need to determine the prescaler value right (1,8,64,256, or 1024)

OCR1A=F_CPU/prescaler

What prescaler value should I use for 12MHz crystal? for my system that is having zero crossing signal every 10ms.
Do I need to generate delay every second, millisecond, or microsecond?

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

A prescaler of 8 should give you adequate resolution. Read up on compare mode. When you get zero cross capture, load up the OCR register with the value of the ICR register plus the required delay. For example, if you want a 5ms delay, that would be 7500 timer ticks at 12MHz with a prescale of 8. If you enabled interrupts and the port bit feature, the port bit would be a logic'1' 5ms after the zero cross and then in the output compare interrupt, you would add 10us of delay to the OCR and set it to clear the port bit. In 10us, the compare hardware will clear your port bit. All very accurately.

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

OK, this is what I've build:

#define F_CPU 12000000UL
#include 
#include 
#include 


void timer_init()
{
TCCR1B |= (1<<WGM12 |1<<CS11);	// Prescaler value 8
TIMSK |= (1<<OCIE1A);
TCNT1 = 0;		// Initialize timer	
}


void timer_set(int time)
{
	int max;
	max = (5/1000)*(12000000/8)-1;
	OCR1A = max;
	sei();		// Enable global interrupts 
}



// Zero Crossing Detector
ISR(INT0_vect)
{
	PORTB|= (1<<PB0);     // High = TRIAC Off
	TCNT1= 0x00;	      // Reset TCNT1
	TCCR1B|= (1<<WGM12 | 1<<CS11); // Prescaler 8
}



// Timer1 compare ISR
ISR(TIMER1_COMPA_vect )
{
   	PORTB|= (1<<PB0); //High = TRIAC Off (500us) 
	_delay_us(500);
	PORTB&= (~(1<<PB0)); 	// Low = TRIAC ON
	_delay_us(10);
   	TCCR1B = 0x0;  		// Stop timer
}


// Main function
int main (void)
{
	DDRD &= ~((1<<PD6)|(1<<PD7));	
	PORTD = 0xff;
	
        // Zero crossing detector to INT0
	MCUCR|=((1<<ISC01)|(1<<ISC00));	//Rising edge
	GICR|=(1<<INT0);	// Enable INT0

	timer_init();
	timer_set(1000);  // time in millisecond

	while(1)
	{
	
	}
}

Finally, the triac is NOT triggered at all :)
What's wrong?

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

Have you run the code in the simulator? Is timer1 a 8 bit or 16 bit timer? What is the value of max?r

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

Yes I have and there is no triggering pulse at all.
Timer1 16 bit.
max=7500-1
=7499

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

What did you check? Is the timer running? Does the match occur? Is the correct interrupt enabled? The purpose of the simulator is that you can put breakpoints, stop and start the execution, change variable values etc so you get an idea of where the problem is. Learning to track down your bugs is a useful skill, so please dont tell us "it doesnt work". At leadt give us some information on what you've tried.

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

The delays used in the ISR(TIMER1_COMPA_vect ) should be avoided.

Reading the datasheet, and understanding of setting of OCR1A will help.

The timer_set() is not the correct way!!! As Kartman suggested set the OCR1A the correct number of ticks ahead from the input capture ICR1 time. Then in the compare ISR, do the output control and set the OCR1A register ahead for the second delay. Do this by adding to the OCR1A. Think of it as setting an alarm clock.

You may find the need of a global state variable to control the two tasks shared in the output compare ISR.

It all starts with a mental vision.

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

I bet this is the problem:
max = (5/1000)*(12000000/8)-1; Because: the expression evaluator generates the code to do the 5/1000 in parens first, and it gets 0 because its using integer arithmetic. Print out max. I betcha its zero. I guess since this is The Moment Of Learning, I should tell you how to calc max without a problem I'd use something like
max = 5*12000000UL/8000-1; This multiplies the 5 times 12million using longs first. (See the UL in there?)

Imagecraft compiler user

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

Quote:
Finally, the triac is NOT triggered at all
Maybe because you have forgotten to set portb.0 as output.
Also this
int max;
   max = (5/1000)*(12000000/8)-1; 

will not work.

Try (not tested)

#define F_CPU 12000000UL
#include 
#include 
#include 


//-------------------------------
// Zero Crossing Detector
ISR(INT0_vect)
{
   TCNT1 = 0x00;                   // Reset timer1
   TCCR1B = (1<<WGM12 | 1<<CS11);  // start timer1
}


//-------------------------------
// Timer1 compare ISR
ISR(TIMER1_COMPA_vect )
{
   PORTB |= (1<<PB0);      // start triac pulse 
   _delay_us(10);
   PORTB &= ~(1<<PB0);     // stop triac pulse
   TCCR1B = 0;             // Stop timer
}


// ===========================================================
int main (void)
{
   // init ports
   DDRB |= (1<<PB0);                   // output (to triac)   
   
   // init INT0
   MCUCR |= ((1<<ISC01)|(1<<ISC00));   // Rising edge
   GICR |= (1<<INT0);                  // Enable INT0

   // init timer 
   TCCR1B |= (1<<WGM12)|(1<<CS11);     // mode CTC, top=OCR1A, prescaler 8
   TIMSK  |= (1<<OCIE1A);              // enable COMPA interrupt 
   
   sei();
   
   // 1 timer_step[us] = prescaler/F_CPU[MHz] = 8/12 = 0.666 us
   // 1 milisec = 1500 steps
   while(1)
   {
      // test
      OCR1A = 1500;    // pulse triac 1 ms after zero crossing
      _delay_ms(2000);

      OCR1A = 3000;    // 2 ms 
      _delay_ms(2000);

      OCR1A = 4500;    // 3 ms 
      _delay_ms(2000);

      OCR1A = 6000;    // 4 ms 
      _delay_ms(2000);

      OCR1A = 7500;    // 5 ms 
      _delay_ms(2000);

      OCR1A = 9000;    // 6 ms 
      _delay_ms(2000);

      // etc.
   }
} 

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

Oh my!

I will try to help again. The use of delays is not correct!!! Delays in software are blocking. This means that once they start they must finish, with the exception of an ISR, that will tale time away from the delay. And when delays are also used in the ISR there is a quandary. The solution is not to use delays at all, and use timer compare ISR instead for precise control of time events.

Timer registers have different uses depending on modes settings of the timer. Reading about timers will help with this. Your program needs to deal with OCR1A settings in a real-time way. This means that OCR1A will not be set from main. It will be set ahead from the "present". The "present" can be TCNT1 (ICR1) in that ISR, or from the OCR1A ISR, the value of OCR1A.

A free running timer counts away, in your case for a 16 bit timer 0 to 65535, then rolls over and repeats ....

So when a zero cross happens The Input capture is triggered, and the ICR1 is the stored value of TCNT1 at that time. So if you want to turn on a port at a time after, OCR1A = ICR1 + xxx; where xxx is the desired delay. When the the timer reaches OCR1A value the timer compare ISR happens, then you turn the port pin on, and set the new OCR1A (OCR1A += ddd; where ddd is delay in ticks for when you want to the next compare to happen for turning the port pin off. Because the compare ISR has two different duties to do it, is necessary to use a control variable, that is set when the OCR1A is set, so the compare operation is handled for the correct type of delay based in an "if" or other statement.

The end result is the code is non-blocking and the ISR codes are short.

It may be an advantage to perhaps make a simple project and experiment with only the OCR1A and a compare ISR. A test to control a output pin for a duty cycle signal is good to start with.

It all starts with a mental vision.

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

KitCarlson:

Quote:
The solution is not to use delays at all

I hope you are not going in extremis and you will bear delay 10 us in my code.
Or not?

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

Visovian,
With all respect to your work, it is best to test your own code and see if it works as you intend. It may be a good learning experience.

My experience suggests that involvement in programming in conjunction with testing resolves many the cause and effect issues. The end result is a development of neural networks in the mind. Then by writing code with the thought of what uC does for statements, yields code that often works without the need to debug. It is an on going learning process. When problems are discovered, learning happens, and for me retention is improved. I learn from mistakes.

It all starts with a mental vision.

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

Quote:
it is best to test your own code and see if it works as you intend.
You are right. Mostly I do so.
I have not a triac at hand, so today I have tested my code in real with a thyristor. It works as I intended.