|

AVR C code for RMS voltage control using BT-136 and MOC-3021

To accomplish the firing angle (RMS) firing angle control of an AC load, please refer to the hardware arrangement explained here. Here is the schematic taken from the application notes of MOC3021 :


There is a need of zero crossing detector, that will provide the reference point. Just after the microcontroller detects the zero crossing of 220V AC, it will turn on the BJT C828 (shown above) with some delay. This delay will determine the RMS voltage across the AC load. Say for example on 50 Hz AC,  the time period comes out to be 20ms. That means the microcontroller will detect the zero crossing every 10 ms. So the range of delay, after which the microcontroller will trigger C828, comes out to be 0-10ms. At delay of 0ms, whole sinusoid will pass through the AC load. Similarly at 5ms i-e firing angle of 90', the RMS voltage across the AC load will be 110V. Therefore we can say that by varying the delay from 0-10ms, we get varying RMS voltage from 220V to 0V.

I have tested the above circuitry using AVR ATmega16L. What microcontroller needs to do is to generate an interrupt on zero crossing and then call the delay routine. How zero crossing of 220V AC is accomplished on microcontroller, will be discussed later. Here is the C code for AVR studio, to test the firing angle control of AC load:

#include <avr/interrupt.h>
#include <avr/iom16.h>
#include <util/delay.h>


volatile int int_flag=0;


ISR( INT0_vect )
{
int_flag=1;
}


void int0_init( void )
{
    MCUCR = (0<<ISC01)|(1<<ISC00);  // enable any level change interrupt
    GICR = (1<<INT0);               // enable INT0
}


int main( void )
{
        DDRB   = 0xFF;     // PORTB as output
DDRA   = 0xFF;     
DDRC   = 0xFF;


  
    int0_init();                    // configure INT0

    sei();                          // enable global interrupts

    while (1)                       // loop forever, 
        
{
asm("nop");

if(int_flag==1)
{

PORTB=0x00;
PORTA=0x00;
PORTC=0x00;
PORTC=0xFF;
PORTB|=(1<<PB0);
_delay_ms(0.625);
PORTB=(1<<PB1)|(1<<PB0);
_delay_ms(0.625);
PORTB=(1<<PB2)|(1<<PB1)|(1<<PB0);
_delay_ms(0.625);
PORTB=(1<<PB3)|(1<<PB2)|(1<<PB1)|(1<<PB0);
_delay_ms(0.625);
PORTB=(1<<PB4)|(1<<PB3)|(1<<PB2)|(1<<PB1)|(1<<PB0);
_delay_ms(0.625);
PORTB=(1<<PB5)|(1<<PB4)|(1<<PB3)|(1<<PB2)|(1<<PB1)|(1<<PB0);
_delay_ms(0.625);
PORTB=(1<<PB6)|(1<<PB5)|(1<<PB4)|(1<<PB3)|(1<<PB2)|(1<<PB1)|(1<<PB0);
_delay_ms(0.625);
PORTB=(1<<PB7)|(1<<PB6)|(1<<PB5)|(1<<PB4)|(1<<PB3)|(1<<PB2)|(1<<PB1)|(1<<PB0);
_delay_ms(0.625);
PORTA=(1<<PA0);
_delay_ms(0.625);
PORTA=(1<<PA1)|(1<<PA0);
_delay_ms(0.625);
PORTA=(1<<PA2)|(1<<PA1)|(1<<PA0);
_delay_ms(0.625);
PORTA=(1<<PA3)|(1<<PA2)|(1<<PA1)|(1<<PA0);
_delay_ms(0.625);
PORTA=(1<<PA4)|(1<<PA3)|(1<<PA2)|(1<<PA1)|(1<<PA0);
_delay_ms(0.625);
PORTA=(1<<PA5)|(1<<PA4)|(1<<PA3)|(1<<PA2)|(1<<PA1)|(1<<PA0);
_delay_ms(0.625);
PORTA=(1<<PA6)|(1<<PA5)|(1<<PA4)|(1<<PA3)|(1<<PA2)|(1<<PA1)|(1<<PA0);
_delay_ms(0.625);
PORTA=(1<<PA7)|(1<<PA6)|(1<<PA5)|(1<<PA4)|(1<<PA3)|(1<<PA2)|(1<<PA1)|(1<<PA0);
int_flag=0;

}

}
    return(0);
}

What is happening in the code? The two ports of AVR ATmega16 is dedicated to test the RMS voltage control of an AC load. Any pin of PORTA and PORTB can be connected to the BJT. Pin 0 of PORTB will trigger the transistor at a delay of 0ms, Pin 1 at a delay of 0.625 ms. In fact the the firing angle is divided into 16 steps (as their are 16 pins dedicated), therefore as you move from PINB0 to PINB7 and then from PINA0 to PINA7, you get an increment of 0.625ms each time you move from one pin to another. If the BJT is connected across PINB0, you get RMS voltage 220 across the load. This RMS voltage will decrease as you move to PINB1 and further till PINA7, as the delay is increasing. 

The above code has been tested successfully. Contact elprojects@ymail.com for any queries.

Posted by Muhammad Ahmed on 22:49. Filed under , , , . You can follow any responses to this entry through the RSS 2.0. Feel free to leave a response

Labels

Recently Commented

Recently Added