Atmega32 and scr phase control

Thread Starter

Tinsae

Joined Jan 8, 2015
134
Dear All, I have been struggling with this circuit and code. my intention is to control scr phase angle with atmega32, the result i found is not as i expected. my expectation is that when i press the push button angle increment and bulb fade a bit till total dim. but the circuit did the first 3-4 push and unexpected result happen.

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

#define F_CPU 8000000l
#include <util/delay.h>

uint8_t EEMEM first;

uint16_t EEMEM dummy;

unsigned int cnt=0;
int counter=0;
unsigned short ny=0;

int phaseangle=1;//phaseangle up to 100 is ok with 500us but it seems that the upper limit should be 20
int main()
{

DDRD=1<<PD2;
PORTD=1<<PD2;
DDRC=0XFF;
DDRB=0X00;//SETTING THE PORT FOR INPU
PORTB=0XFF;//ENABLING PULL UPS

GICR=1<<INT0;
MCUCR=1<<1 | 1<<0;
sei();

while(1)
{

if( (PINB & (1<<PB0) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle+1;
sei();
};

if( (PINB & (1<<PB5) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle-1;
sei();
};

}
return(1);
}



ISR(INT0_vect)
{
PORTC=0;
//i have to write something that let the process to delay before sending pulse to
//the scr gate
// our frequency is 50Hz therefore one positive or negative cycle will have 1/(2*50) seconds
//duration (1/100)*1000ms=10ms
//or (1/100)*1000000us=10000us;
for (ny=0;ny<phaseangle;ny++)
_delay_us(5); //try with higher number like 7000
//now send pulse to the gate here
PORTC=1;
//PORTC=1;
//PORTC=1;

}
 

Attachments

Thread Starter

Tinsae

Joined Jan 8, 2015
134
Dear All, I have been struggling with this circuit and code. my intention is to control scr phase angle with atmega32, the result i found is not as i expected. my expectation is that when i press the push button angle increment and bulb fade a bit till total dim. but the circuit did the first 3-4 push and unexpected result happen.

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

#define F_CPU 8000000l
#include <util/delay.h>

uint8_t EEMEM first;

uint16_t EEMEM dummy;

unsigned int cnt=0;
int counter=0;
unsigned short ny=0;

int phaseangle=1;//phaseangle up to 100 is ok with 500us but it seems that the upper limit should be 20
int main()
{

DDRD=1<<PD2;
PORTD=1<<PD2;
DDRC=0XFF;
DDRB=0X00;//SETTING THE PORT FOR INPU
PORTB=0XFF;//ENABLING PULL UPS

GICR=1<<INT0;
MCUCR=1<<1 | 1<<0;
sei();

while(1)
{

if( (PINB & (1<<PB0) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle+1;
sei();
};

if( (PINB & (1<<PB5) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle-1;
sei();
};

}
return(1);
}



ISR(INT0_vect)
{
PORTC=0;
//i have to write something that let the process to delay before sending pulse to
//the scr gate
// our frequency is 50Hz therefore one positive or negative cycle will have 1/(2*50) seconds
//duration (1/100)*1000ms=10ms
//or (1/100)*1000000us=10000us;
for (ny=0;ny<phaseangle;ny++)
_delay_us(5); //try with higher number like 7000
//now send pulse to the gate here
PORTC=1;
//PORTC=1;
//PORTC=1;

}


what is wrong i am not getting any response about my post
 

JohnInTX

Joined Jun 26, 2012
4,787
I'm not familiar with atmega C or your particular approach but:
if( (PINB & (1<<PB0) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle+1;
sei();
};
If cli() disables interrupts, you won't be able to use an interrupt-controlled phaze angle output. Also, this code is repeated twice - why?
In the interrupt routine, you don't want to use a C delay (or any delay for that matter) like you show. You'll never get it / keep it synchronized with the line frequency.

I've done phase angle with a PIC like this:

Use 2 interrupts, one from the zero crossing detector and one from a timer that counts off time from zero-cross to SCR trigger.
The desired phase angle is computed by the main program, converted to a raw timer setting and stored where it can be accessed quickly on the zero crossing interrupt.
At zero crossing, the processor is interrupted and you quickly load the timer with the pre-computed timer value the corresponds to the phase delay AND enable the timer interrupt.
When the timer runs out and interrupts the processor, quickly pulse the SCR gate then stop the timer / disable its interrupt to avoid re-triggering.
Repeat at the next zero crossing.

Note that there are no delay() routines in the interrupt service. That's a good practice for any interrupt driven scheme.

The main program does whatever it has to do to make the timer load value available to the interrupt driven phase angle control. It can delay as necessary but can never turn off interrupts (unless the output is OFF). Note that once the phase angle is computed and the timer setting is loaded, the main program has to do nothing further to keep the SCR fed - that's all done by the 2 interrupts. When the phase angle changes, just compute the new timer delay value and store it. It will be used on the next cycle. Nice.

Good luck.
 
Last edited:

Thread Starter

Tinsae

Joined Jan 8, 2015
134
Thank you all! my answer to your questions
1. my unexpected result is the bulb doesn't deem/bright at fixed level as i press the button. when i press the first push, it deem a bit, the second press dim more and the third dim even more (this is the way i want it to act) but after the third press any press will not make the bulb dim at a fixed point. the bulb will dim to zero and bright to full by its own and it repeat the cycle indefinitely but i need it to be fixed dim or bright.

i tried changing phaseangle pre sette value but it doesn't help.
2.
if( (PINB & (1<<PB0) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle+1;
sei();
};

if( (PINB & (1<<PB5) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle-1;
sei();
};

the above two codes are not identical look pb5 and pb0 in their if clause. these two code check any press on push button of increase angle and decrease (as shown in my drawing i have two push button one for increase phase angle the other for decreasing )
also i use cli(); such that user can increase or decrease angle without interruption after the user set the angle i immediately enabled the interrupt by setting sei(); look at the code. i have tried without them but it is more worse.

i will try your suggestion using two interrupt and avoiding delay inside interrupt service routing
 

JohnInTX

Joined Jun 26, 2012
4,787
the above two codes are not identical look pb5 and pb0 in their if clause
Ah, I see - sorry I missed that. It would be good to have more/better comments on your code. The easier it is to read it, the easier it is to understand and find bugs.
Code:
//-----------------------------------------------
// Poll button on PB0 to increase phase angle
if( (PINB & (1<<PB0) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle+1;
sei();
};

//-----------------------------------------------
// Poll button on PB5 to decrease phase angle
if( (PINB & (1<<PB5) )==0)
{
cli();
_delay_ms(10);//wait till debounce fade out
phaseangle=phaseangle-1;
sei();
};
also i use cli(); such that user can increase or decrease angle without interruption after the user set the angle i immediately enabled the interrupt by setting sei(); look at the code. i have tried without them but it is more worse.
That is because your interrupt routine has large delays in it. As I said, you never want any delays in an interrupt routine. Its considered bad practice and you now know why.

i will try your suggestion using two interrupt and avoiding delay inside interrupt service routing
I believe you will find that it works much better.

Good luck.
 

Thread Starter

Tinsae

Joined Jan 8, 2015
134
Thank you very much. I have just applied your suggestions and some additional rework (like changing the internal calibrated RC oscillator to 8MHz) done and the result is much better thank you. Still there is very faint problem like flickering of the load it is acceptable.
the final code look like this

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

#define F_CPU 8000000l
#include <util/delay.h>

unsigned int phase=10;
int main()
{

DDRD=1<<PD2;
PORTD=1<<PD2;
DDRC=0XFF;
DDRB=0X00;//SETTING THE PORT FOR INPU
PORTB=0XFF;//ENABLING PULL UPS

TIMSK=1<<TOIE0;
GICR=1<<INT0;
MCUCR=1<<1 | 1<<0; //rising edge generate interrupt
sei();
TCNT0=phase;


while(1)
{

if( (PINB & (1<<PB0) )==0)
{
_delay_ms(50);//wait till debounce fade out
phase+=1;

};

if( (PINB & (1<<PB5) )==0)
{
_delay_ms(50);//wait till debounce fade out
phase-=1;
};

}
return(1);
}

ISR(TIMER0_OVF_vect)
{
//some code must trigger on scr
//disable timer counting writing on the prescaler
TCCR0=TCCR0 | 0X0;
PORTC=1;
}

ISR(INT0_vect)
{
PORTC=0;
//i have to write something that let the process to delay before sending pulse to
//the scr gate
// our frequency is 50Hz therefore one positive or negative cycle will have 1/(2*50) seconds
//duration (1/100)*1000ms=10ms
//or (1/100)*1000000us=10000us;
//enable timer counting
TCNT0=phase;
TCCR0=TCCR0 | 0b00000100;//prescaler
}
 

JohnInTX

Joined Jun 26, 2012
4,787
Are you saying that the problem is that with no changes to 'phase', you get a flickering load due to inaccurate triggering?
One thing to do is pulse the SCR gate in the interrupt routine:
ISR(TIMER0_OVF_vect)
{
//some code must trigger on scr
//disable timer counting writing on the prescaler
TCCR0=TCCR0 | 0X0;
PORTC=1;
}
You are leaving the SCR gate trigger ON until zero crossing - I am wondering if due to interrupt latency, zero-crossing detect delay etc, the SCR re-triggers at zero crossing because you are late turning off the gate drive. Try something like this:
C:
ISR(TIMER0_OVF_vect)
{
//some code must trigger on scr
PORTC=1; // trigger the SCR first, the timer can wait..
//then disable timer counting writing on the prescaler
// the execution time of stopping the timer will provide some pulse width
TCCR0=TCCR0 | 0X0;
delay_a_little_bit_more(); //to stretch the pulse just enough to trigger the SCR if more time is needed. If you have more interrupt housekeeping to do, here's the place to do it.
PORTC=0; // end of SCR trigger
}// end of SCR trigger ISR
Yeah, I know I said not to delay in an interrupt routine - sometimes you need a little bit. If that fixes your problem, that's great. If you need too much delay (you probably won't) we can do it differently. Also, you probably want to use individual bits on PORTC. OK for now.

Good luck!

BTW Use CODE tags (click on the toolbar in the edit window) to make your code easier to read. If you modify the CODE tag to say CODE=C, you get really nice formatting..
 
Last edited:
Top