Atmega32 and scr phase control

Discussion in 'Embedded Systems and Microcontrollers' started by Tinsae, Jul 6, 2015.

  1. Tinsae

    Thread Starter New Member

    Jan 8, 2015
    15
    0
    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;

    }
     
  2. Tinsae

    Thread Starter New Member

    Jan 8, 2015
    15
    0


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

    Moderator

    Aug 21, 2008
    2,647
    632
    You did not say what the unexpected result was.
     
  4. JohnInTX

    Moderator

    Jun 26, 2012
    2,339
    1,021
    I'm not familiar with atmega C or your particular approach but:
    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: Jul 9, 2015
  5. Tinsae

    Thread Starter New Member

    Jan 8, 2015
    15
    0
    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
     
  6. JohnInTX

    Moderator

    Jun 26, 2012
    2,339
    1,021
    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 (Text):
    1.  
    2. //-----------------------------------------------
    3. // Poll button on PB0 to increase phase angle
    4. if( (PINB & (1<<PB0) )==0)
    5. {
    6. cli();
    7. _delay_ms(10);//wait till debounce fade out
    8. phaseangle=phaseangle+1;
    9. sei();
    10. };
    11.  
    12. //-----------------------------------------------
    13. // Poll button on PB5 to decrease phase angle
    14. if( (PINB & (1<<PB5) )==0)
    15. {
    16. cli();
    17. _delay_ms(10);//wait till debounce fade out
    18. phaseangle=phaseangle-1;
    19. sei();
    20. };
    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 believe you will find that it works much better.

    Good luck.
     
  7. Tinsae

    Thread Starter New Member

    Jan 8, 2015
    15
    0
    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
    }
     
  8. JohnInTX

    Moderator

    Jun 26, 2012
    2,339
    1,021
    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:
    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:
    Code (C):
    1. ISR(TIMER0_OVF_vect)
    2. {
    3. //some code must trigger on scr
    4. PORTC=1; // trigger the SCR first, the timer can wait..
    5. //then disable timer counting writing on the prescaler
    6. // the execution time of stopping the timer will provide some pulse width
    7. TCCR0=TCCR0 | 0X0;
    8. 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.
    9. PORTC=0; // end of SCR trigger
    10. }// 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: Jul 18, 2015
Loading...