## Sunday, November 4, 2012

### Feedback in sine wave inverter (PIC16F series based)

I have previously shown how to calculate the values for the sine table: http://tahmidmc.blogspot.com/2011/01/generation-and-implementation-of-sine.html

I have also shown how to implement SPWM in PIC16: http://tahmidmc.blogspot.com/2012/10/generation-of-sine-wave-using-spwm-in_10.html

Now I will show how to implement feedback for SPWM.

Due to various limitations in PIC16, such as ADC speed, instruction time and the ALU, it is extremely difficult, if not impossible, to calculate in real time the values required for feedback in sinusoidal pulse width modulation (SPWM). Thus, to implement feedback, a different approach must be used. That approach would be to retrieve the values from a sine table that contains the duty cycle values for a specific duty cycle. Here is one sine table I used, for example:

const unsigned char sin_table[416]={
0, 16, 32, 47, 62, 77, 91, 103, 115, 126, 136, 144, 151, 156, 160, 162, 163, 162, 160, 156, 151, 144, 136, 126, 115, 103, 91, 77, 62, 47, 32, 16, //65%

0, 17, 33, 49, 65, 80, 94, 107, 120, 131, 141, 149, 156, 162, 166, 168, 169, 168, 166, 162, 156, 149, 141, 131, 120, 107, 94, 80, 65, 49, 33, 17, //67.5%

0, 17, 34, 51, 67, 82, 97, 111, 124, 135, 146, 154, 162, 167, 172, 174, 175, 174, 172, 167, 162, 154, 146, 135, 124, 111, 97, 82, 67, 51, 34, 17, //70%

0, 18, 35, 53, 69, 85, 101, 115, 128, 140, 150, 160, 167, 173, 178, 180, 181, 180, 178, 173, 167, 160, 150, 140, 128, 115, 101, 85, 69, 53, 35, 18, //72.5%

0, 18, 37, 55, 72, 89, 104, 119, 133, 145, 156, 166, 174, 180, 184, 187, 188, 187, 184, 180, 174, 166, 156, 145, 133, 119, 104, 89, 72, 55, 37, 18, //75%

0, 19, 38, 56, 74, 91, 108, 123, 137, 150, 161, 171, 179, 186, 190, 193, 194, 193, 190, 186, 179, 171, 161, 150, 137, 123, 108, 91, 74, 56, 38, 19, //77.5%

0, 20, 39, 58, 77, 94, 111, 127, 141, 155, 166, 176, 185, 191, 196, 199, 200, 199, 196, 191, 185, 176, 166, 155, 141, 127, 111, 94, 77, 58, 39, 20, //80%

0, 20, 40, 60, 79, 97, 114, 131, 146, 159, 171, 182, 190, 197, 202, 205, 206, 205, 202, 197, 190, 182, 171, 159, 146, 131, 114, 97, 79, 60, 40, 20, //82.5%

0, 21, 42, 62, 82, 100, 118, 135, 151, 165, 177, 188, 197, 204, 209, 212, 213, 212, 209, 204, 197, 188, 177, 165, 151, 135, 118, 100, 82, 62, 42, 21, //85

0, 21, 43, 64, 84, 103, 122, 139, 155, 169, 182, 193, 202, 210, 215, 218, 219, 218, 215, 210, 202, 193, 182, 169, 155, 139, 122, 103, 84, 64, 43, 21, //87.5%

0, 22, 44, 65, 86, 106, 125, 143, 159, 174, 187, 198, 208, 215, 221, 224, 225, 224, 221, 215, 208, 198, 187, 174, 159, 143, 125, 106, 86, 65, 44, 22, //90%

0, 23, 45, 67, 88, 109, 128, 147, 163, 179, 192, 204, 213, 221, 227, 230, 231, 230, 227, 221, 213, 204, 192, 179, 163, 147, 128, 109, 88, 67, 45, 23, //92.5%

0, 23, 46, 69, 91, 112, 132, 151, 168, 184, 198, 210, 220, 228, 233, 237, 238, 237, 233, 228, 220, 210, 198, 184, 168, 151, 132, 112, 91, 69, 46, 23 //95%

//0, 25, 49, 73, 96, 118, 139, 159, 177, 193, 208, 220, 231, 239, 245, 249, 250, 249, 245, 239, 231, 220, 208, 193, 177, 159, 139, 118, 96, 73, 49, 25, //100%

Each set of values corresponding to one duty cycle has 32 values.

A table pointer is used to retrieve the values for a given duty cycle. So, when the value of the table pointer is 0, the program reads the first 32 values (65% duty cycle), then the next 32 values when value of table pointer is 1 and so on.

The microcontroller first starts with the lowest duty cycle and then analyses the output voltage.

If the output voltage must be increased, the value of the table pointer is incremented and so, the next set of values is retrieved, increasing duty cycle and thus output voltage. If output voltage must be decreased, the value of the table pointer is decremented so that the previous set of values is retrieved, lowering duty cycle and thus output voltage.

Here is how the table pointer is updated:

if (FBV < 512){
FB_Step++;
if (FB_Step > 12) FB_Step = 12;
}
else{
if (FB_Step > 0){
FB_Step--;
}
}
TMR1L = 0;
TMR1H = 0;
T1IF_bit = 0;

The reference value of the ADC is 5V, so 512 represents a voltage of 2.5V, which is the feedback reference voltage in this example. When voltage on ADC pin is >2.5V, table pointer value is decremented and when it is <2.5V, table pointer value is incremented.

The required set of values is retrieved and applied by something like this:
TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
if (TBL_POINTER_NEW < TBL_POINTER_OLD){
P1M1_bit = ~P1M1_bit;
}
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
CCPR1L = sin_table[DUTY_CYCLE];
TBL_POINTER_OLD = TBL_POINTER_NEW;
TMR2IF_bit = 0;

Now that I've shown how to generate a sine table manually and with "Smart Sine", implement SPWM in PIC16 and now, how to implement feedback, you can easily make a sine wave inverter using the information I've provided. All you need to do is make sure you've understood what I've said and do some research on your own to make the project complete.

To make this clearer and so that you understand better, I am presenting some common questions and their answers.

Question: I am designing a pure sine wave inverter using an output H bridge at 310vdc. Is there any need for feed back control if I keep the 310 Vdc steady?
Answer: If you can keep the 310VDC steady, then there is no need for feedback of SPWM. Your output will be relatively stable, since the DC bus is regulated.

Question: Why is the feedback not necessary, since there will be a voltage drop when there is increase in load? Remember the code is not incrementing or decrementing at this time. Now take an example of your normal modified sine inverter using SG3524 or any PWM IC. The output voltage drops when
there is increase in load but the battery voltage doesn't change. Therefore there will be a need to control the code also. Right?
Answer: When there is increase in load, you will notice that the battery voltage always decreases due to the internal resistance. Measure the battery voltage of the inverter under load and you will see that it decreases as load increases. A battery that measures about 12-13V open circuit may drop to 11V or lower under load. Plus, there is a significant drop by the transformer under load.

Also, think about this: in the H-bridge converter, when load increases (and so current increases) but the +ve bus voltage is constant, where will the voltage be dropped? There is no transformer to deal with, as
the primary side PWM will take care of drops by the transformer (and battery voltage drop) and keep the output fixed. The only place for voltage drop is the MOSFETs and there will be a drop in voltage in the MOSFETs, but not so large that the output voltage will be beyond acceptable bounds.

Question: You have shown 32 values for each duty cycle in the program. Can I use 192 for my 3.5kHz design?
Answer: You can use any number of duty cycle values in an array. 32 is usually sufficient, but with 192, greater precision can be had, especially since the frequency is 3.5kHz and the time period is much longer as compared to 16kHz. So, the SPWM is more accurate. However, just keep in mind that all of the values are stored in program memory. So, it will consume more program memory. You can use the software Smart Sine to generate the sine table: http://tahmidmc.blogspot.com/2012/10/smart-sine-software-to-generate-sine.html
For manual calculation, go through this tutorial: http://tahmidmc.blogspot.com/2011/01/generation-and-implementation-of-sine.html

Question: What about this unsigned char I can see (416) in the code. What is it used for?
Answer: 32 values correspond to the sine wave at one duty cycle. I have set 13 duty cycle settings. 13 * 32 = 416
There are total 416 values in the array, 13 sets, and each set (containing 32 values) corresponds to one duty cycle setting.

Each set of values corresponding to one duty cycle has 32 values.

A table pointer is used to retrieve the values for a given duty cycle. So, when the value of the table pointer is 0, the program reads the first 32 values (65% duty cycle), then the next 32 values when value of table pointer is 1 and so on.

Practical Example:
The microcontroller first starts with the lowest duty cycle and then analyses the output voltage.

If the output voltage must be increased, the value of the table pointer is incremented and so, the next set of values is retrieved, increasing duty cycle and thus output voltage. If output voltage must be decreased, the value of the table pointer is decremented so that the previous set of values is retrieved, lowering duty cycle and thus output voltage. The table pointer keeps increasing by 1 to increase the duty cycle and so, the output voltage of the inverter.
Practical example: At the beginning of program execution, the table pointer is zero and the microcontroller starts with 65% duty cycle. Let's assume we have a 8V (primary) to 256V (secondary) transformer and a full bridge converter is being used to drive the transformer. The bridge is being driven by signals from the microcontroller - these SPWM signals.

The RMS voltage to the transformer primary will be (0.65 * 12/1.4142135)V = 5.5V.
Turns ratio of the transformer (primary:secondary) is 1:32.
So, secondary voltage (assuming 100% transformer efficiency) will be 32*5.5V = 176V.
As we require an output of 220V, this is lower than required. So, output voltage must be increased. So, table pointer is incremented to 1.
Then, duty cycle is 67.5% and output voltage is 183V.
Table pointer is incremented to 2.
Duty cycle is 70% and output voltage is 190V.
Table pointer is incremented to 3.
Duty cycle is 72.5% and output voltage is 197V.
Table pointer is incremented to 4.
Duty cycle is 75% and output voltage is 204V.
Table pointer is incremented to 5.
Duty cycle is 77.5% and output voltage is 210V.
Table pointer is incremented to 6.
Duty cycle is 80% and output voltage is 217V.
Table pointer is incremented to 7.
Duty cycle is 82.5% and output voltage is 224V.
Table pointer is decremented to 6.
Duty cycle is 80% and output voltage is 217V.
Table pointer is incremented to 7.
Duty cycle is 82.5% and output voltage is 224V.
Table pointer is decremented to 6.
Duty cycle is 80% and output voltage is 217V.
.
.
.
.
And so on.

This is how regulation is achieved.

This is all at 12V. But, you can see how the table pointer will be changed to maintain a constant output.

1. Take a look here for details:

tahmidmc.blogspot.com/2013/02/demystifying-use-of-table-pointer-in.html

Regards,
Tahmid.

2. Very good explanation. Simple way of feedback instead of complex PID calculations.
Thank you.
J.T.Rao

3. Hey Tahmid great stuff. I wanted to know where to put the feedback code. I put it in the interrupt and in the while loop exclusively; it didn't work. I have a general understanding of what is going on but i get lost on how to make sure that the feed back gets updated every 5 interrupts because it seems that the time and registers take care of that. Thanks

1. Nevermind I figured out what was going on and I modified your code to create a different implementation. I used a 2d array and made the interrupt last longer that way on every interrupt it would grab a value from the table.

2. sir can you guide me for square wave inverter with 16f72 feedback in asm launguge ?

3. Have you started coding? Where are you getting stuck or are facing problems?

4. I'm from Russia.
I can not code feedback+spwm.

1. Training is slow, but the result is positive.

Regards,tantra-yog.

5. Hi,

I have not understood how you have generated sine table for one duty cycle? For example the first 32 values corresponds to 67% and next 32 set of values corresponds to say 70% duty cycle.How you have calculated could you please explain me.

Thank you.

Praveen.
praveen4u83@gmail.com

1. I calculated the sine wave table with 100% duty cycle (the last set of values in the table). Then for the required duty cycle, I divided/multipllied each value in the table. For example, for 67% duty cycle, I multiplied each value in the table by 0.67 to give th required values.

Regards,
Tahmid.

6. Nice Post!! pretty informative..thanks for providing such a nice post.

sine wave inverter

7. Check the code.

const unsigned char sin_table[416]=
{
0,16,33,49,64,79,93,106,118,129,138,146,153,158,161,163,163,161,158,153,146,138,129,118,106,93,79,64,49,33,16,0, //65%
0,17,34,51,67,82,97,110,122,134,143,152,158,164,167,169,169,167,164,158,152,143,134,122,110,97,82,67,51,34,17,0, //67.5%
0,18,35,52,69,85,100,114,127,138,149,157,164,169,173,175,175,173,169,164,157,149,138,127,114,100,85,69,52,35,18,0, //70%
0,18,36,54,71,88,103,118,131,143,154,163,170,175,179,181,181,179,175,170,163,154,143,131,118,103,88,71,54,36,18,0, //72.5%
0,19,38,56,74,91,107,122,136,149,160,169,176,182,186,188,188,186,182,176,169,160,149,136,122,107,91,74,56,38,19,0, //75%
0,20,39,58,77,94,111,126,141,153,165,174,182,188,192,194,194,192,188,182,174,165,153,141,126,111,94,77,58,39,20,0, //77.5%
0,20,40,60,79,97,114,130,145,158,170,180,188,194,198,200,200,198,194,188,180,170,158,145,130,114,97,79,60,40,20,0, //80%
0,21,41,62,81,100,118,134,149,163,175,185,193,199,204,206,206,204,199,193,185,175,163,149,134,118,100,81,62,41,21,0, //82.5%
0,22,43,64,84,103,122,139,154,168,181,191,200,206,211,213,213,211,206,200,191,181,168,154,139,122,103,84,64,43,22,0, //85
0,22,44,66,86,106,125,143,159,173,186,197,205,212,216,219,219,216,212,205,197,186,173,159,143,125,106,86,66,44,22,0, //87.5%
0,23,45,67,89,109,129,147,163,178,191,202,211,218,222,225,225,222,218,211,202,191,178,163,147,129,109,89,67,45,23,0, //90%
0,23,46,69,91,112,132,150,167,183,196,207,217,224,228,231,231,228,224,217,207,196,183,167,150,132,112,91,69,46,23,0, //92.5%
0,24,48,71,94,116,136,155,173,188,202,214,223,230,235,238,238,235,230,223,214,202,188,173,155,136,116,94,71,48,24,0, //95%
};

unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int DUTY_CYCLE, FBV, FB_Step, adder;

void interrupt()
{
if (TMR2IF_bit == 1){TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
if (TBL_POINTER_NEW < TBL_POINTER_OLD){P1M1_bit = ~P1M1_bit;}
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
CCPR1L = sin_table[DUTY_CYCLE];
TBL_POINTER_OLD = TBL_POINTER_NEW;
TMR2IF_bit = 0;
}}

void main()
{
SET_FREQ = 410;
TBL_POINTER_SHIFT = 0;
TBL_POINTER_NEW = 0;
TBL_POINTER_OLD = 0;
DUTY_CYCLE = 0;
FB_Step = 0;
T1CON = 0b00001001;//1:1 Prescale Value, Enables Timer1
ANSEL = 0b00000001;//RA0/AN0 as analogue input.
TRISA = 0b00000001;//PortA as output except RA0 as input
CMCON0 = 7;
PR2 = 249;
TRISC = 0x3F;
CCP1CON = 0x4C;
TMR2IF_bit = 0;
T2CON = 4;
while (TMR2IF_bit == 0);
TMR2IF_bit = 0;
TRISC = 0;
TMR2IE_bit = 1;
GIE_bit = 1;
PEIE_bit = 1;

while(1)
{
if (VFB < 512){FB_Step++;
if (FB_Step > 12) FB_Step = 12;}
else
{if (FB_Step > 0){FB_Step--;}}
TMR1L = 0;
TMR1H = 0;
T1IF_bit = 0;
}
}

1. The feedback option don't work......
Plz check this code.................

8. I can't get feedback from the following code:
(Plzz help to build it work properly)

const unsigned char sin_table[416]=
{
0,16,33,49,64,79,93,106,118,129,138,146,153,158,161,163,163,161,158,153,146,138,129,118,106,93,79,64,49,33,16,0, //65%
0,17,34,51,67,82,97,110,122,134,143,152,158,164,167,169,169,167,164,158,152,143,134,122,110,97,82,67,51,34,17,0, //67.5%
0,18,35,52,69,85,100,114,127,138,149,157,164,169,173,175,175,173,169,164,157,149,138,127,114,100,85,69,52,35,18,0, //70%
0,18,36,54,71,88,103,118,131,143,154,163,170,175,179,181,181,179,175,170,163,154,143,131,118,103,88,71,54,36,18,0, //72.5%
0,19,38,56,74,91,107,122,136,149,160,169,176,182,186,188,188,186,182,176,169,160,149,136,122,107,91,74,56,38,19,0, //75%
0,20,39,58,77,94,111,126,141,153,165,174,182,188,192,194,194,192,188,182,174,165,153,141,126,111,94,77,58,39,20,0, //77.5%
0,20,40,60,79,97,114,130,145,158,170,180,188,194,198,200,200,198,194,188,180,170,158,145,130,114,97,79,60,40,20,0, //80%
0,21,41,62,81,100,118,134,149,163,175,185,193,199,204,206,206,204,199,193,185,175,163,149,134,118,100,81,62,41,21,0, //82.5%
0,22,43,64,84,103,122,139,154,168,181,191,200,206,211,213,213,211,206,200,191,181,168,154,139,122,103,84,64,43,22,0, //85
0,22,44,66,86,106,125,143,159,173,186,197,205,212,216,219,219,216,212,205,197,186,173,159,143,125,106,86,66,44,22,0, //87.5%
0,23,45,67,89,109,129,147,163,178,191,202,211,218,222,225,225,222,218,211,202,191,178,163,147,129,109,89,67,45,23,0, //90%
0,23,46,69,91,112,132,150,167,183,196,207,217,224,228,231,231,228,224,217,207,196,183,167,150,132,112,91,69,46,23,0, //92.5%
0,24,48,71,94,116,136,155,173,188,202,214,223,230,235,238,238,235,230,223,214,202,188,173,155,136,116,94,71,48,24,0, //95%
};

unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int DUTY_CYCLE, FBV, FB_Step, adder;

void interrupt()
{
if (TMR2IF_bit == 1){TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
if (TBL_POINTER_NEW < TBL_POINTER_OLD){P1M1_bit = ~P1M1_bit;}
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
CCPR1L = sin_table[DUTY_CYCLE];
TBL_POINTER_OLD = TBL_POINTER_NEW;
TMR2IF_bit = 0;
}}

void main()
{
SET_FREQ = 410;
TBL_POINTER_SHIFT = 0;
TBL_POINTER_NEW = 0;
TBL_POINTER_OLD = 0;
DUTY_CYCLE = 0;
FB_Step = 0;
T1CON = 0b00001001;//1:1 Prescale Value, Enables Timer1
ANSEL = 0b00000001;//RA0/AN0 as analogue input.
TRISA = 0b00000001;//PortA as output except RA0 as input
CMCON0 = 7;
PR2 = 249;
TRISC = 0x3F;
CCP1CON = 0x4C;
TMR2IF_bit = 0;
T2CON = 4;
while (TMR2IF_bit == 0);
TMR2IF_bit = 0;
TRISC = 0;
TMR2IE_bit = 1;
GIE_bit = 1;
PEIE_bit = 1;

while(1)
{
if (VFB < 512){FB_Step++;
if (FB_Step > 12) FB_Step = 12;}
else
{if (FB_Step > 0){FB_Step--;}}
TMR1L = 0;
TMR1H = 0;
T1IF_bit = 0;
}
}

9. Sorri error VFB FBV

const unsigned char sin_table[416]=
{
0,16,33,49,64,79,93,106,118,129,138,146,153,158,161,163,163,161,158,153,146,138,129,118,106,93,79,64,49,33,16,0, //65%
0,17,34,51,67,82,97,110,122,134,143,152,158,164,167,169,169,167,164,158,152,143,134,122,110,97,82,67,51,34,17,0, //67.5%
0,18,35,52,69,85,100,114,127,138,149,157,164,169,173,175,175,173,169,164,157,149,138,127,114,100,85,69,52,35,18,0, //70%
0,18,36,54,71,88,103,118,131,143,154,163,170,175,179,181,181,179,175,170,163,154,143,131,118,103,88,71,54,36,18,0, //72.5%
0,19,38,56,74,91,107,122,136,149,160,169,176,182,186,188,188,186,182,176,169,160,149,136,122,107,91,74,56,38,19,0, //75%
0,20,39,58,77,94,111,126,141,153,165,174,182,188,192,194,194,192,188,182,174,165,153,141,126,111,94,77,58,39,20,0, //77.5%
0,20,40,60,79,97,114,130,145,158,170,180,188,194,198,200,200,198,194,188,180,170,158,145,130,114,97,79,60,40,20,0, //80%
0,21,41,62,81,100,118,134,149,163,175,185,193,199,204,206,206,204,199,193,185,175,163,149,134,118,100,81,62,41,21,0, //82.5%
0,22,43,64,84,103,122,139,154,168,181,191,200,206,211,213,213,211,206,200,191,181,168,154,139,122,103,84,64,43,22,0, //85
0,22,44,66,86,106,125,143,159,173,186,197,205,212,216,219,219,216,212,205,197,186,173,159,143,125,106,86,66,44,22,0, //87.5%
0,23,45,67,89,109,129,147,163,178,191,202,211,218,222,225,225,222,218,211,202,191,178,163,147,129,109,89,67,45,23,0, //90%
0,23,46,69,91,112,132,150,167,183,196,207,217,224,228,231,231,228,224,217,207,196,183,167,150,132,112,91,69,46,23,0, //92.5%
0,24,48,71,94,116,136,155,173,188,202,214,223,230,235,238,238,235,230,223,214,202,188,173,155,136,116,94,71,48,24,0, //95%
};

unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int DUTY_CYCLE, FBV, FB_Step, adder;

void interrupt()
{
if (TMR2IF_bit == 1){TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
if (TBL_POINTER_NEW < TBL_POINTER_OLD){P1M1_bit = ~P1M1_bit;}
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
CCPR1L = sin_table[DUTY_CYCLE];
TBL_POINTER_OLD = TBL_POINTER_NEW;
TMR2IF_bit = 0;
}}

void main()
{
SET_FREQ = 410;
TBL_POINTER_SHIFT = 0;
TBL_POINTER_NEW = 0;
TBL_POINTER_OLD = 0;
DUTY_CYCLE = 0;
FB_Step = 0;
T1CON = 0b00001001;//1:1 Prescale Value, Enables Timer1
ANSEL = 0b00000001;//RA0/AN0 as analogue input.
TRISA = 0b00000001;//PortA as output except RA0 as input
CMCON0 = 7;
PR2 = 249;
TRISC = 0x3F;
CCP1CON = 0x4C;
TMR2IF_bit = 0;
T2CON = 4;
while (TMR2IF_bit == 0);
TMR2IF_bit = 0;
TRISC = 0;
TMR2IE_bit = 1;
GIE_bit = 1;
PEIE_bit = 1;

while(1)
{
if (FBV < 512){FB_Step++;
if (FB_Step > 12) FB_Step = 12;
}
else
{
if (FB_Step > 0){FB_Step--;}}
TMR1L = 0;
TMR1H = 0;
T1IF_bit = 0;
}
}

MicroC , Proteus ... files

the code is not final

Regards,tantra-yog.

1. Friends Check the code...

Regards,tantra-yog.
tantra-yog@yandex.ru

2. it works...... thanks

3. This comment has been removed by the author.

4. please how to change frequency to 60hz please in my cowntry

10. I have tried to build this code using PIC16F72. But the output shows "not enough RAM in sine_table". The datasheet of the said MCU shows 128x8 bytes of data memory (RAM) is there. If 32 values are used in sine_table, it builds properly. Please offer some comment on this issue.

1. Hi, where you able to solve this problem? I'm facing a similar problem in dsPIC30f. If Yes, then please share the solution. Thanks.

11. Tahmid you are the best of the best.

12. This is good and informative post.

13. Tahmid I love and highly appreciate your work in Power Electronics & its integration with uC.
I have been planning to design Complete Sine Wave UPS including Feedback for regulated output voltage using a single Microcontroller PIC16F887 for all purposes, I have completed its LCD Display for Voltages, Battery Percentage, Over Under Voltage Protection & Automatic Switching etc,, BUT I NEED YOUR HELP REGARDING CERTAIN PROBLEMS AND ONE OF THESE IS BELOW...

I have found this one code in above comments and this work perfectly in Proteus Simulation but for PIC16F684.
But when I try to build it for PIC16F887 using MikroC it highlights the these two lines as an ERROR..
T1IF_bit = 0;
CMCON0 = 7;

const unsigned char sin_table[416]=
{
0,16,33,49,64,79,93,106,118,129,138,146,153,158,161,163,163,161,158,153,146,138,129,118,106,93,79,64,49,33,16,0, //65%
0,17,34,51,67,82,97,110,122,134,143,152,158,164,167,169,169,167,164,158,152,143,134,122,110,97,82,67,51,34,17,0, //67.5%
0,18,35,52,69,85,100,114,127,138,149,157,164,169,173,175,175,173,169,164,157,149,138,127,114,100,85,69,52,35,18,0, //70%
0,18,36,54,71,88,103,118,131,143,154,163,170,175,179,181,181,179,175,170,163,154,143,131,118,103,88,71,54,36,18,0, //72.5%
0,19,38,56,74,91,107,122,136,149,160,169,176,182,186,188,188,186,182,176,169,160,149,136,122,107,91,74,56,38,19,0, //75%
0,20,39,58,77,94,111,126,141,153,165,174,182,188,192,194,194,192,188,182,174,165,153,141,126,111,94,77,58,39,20,0, //77.5%
0,20,40,60,79,97,114,130,145,158,170,180,188,194,198,200,200,198,194,188,180,170,158,145,130,114,97,79,60,40,20,0, //80%
0,21,41,62,81,100,118,134,149,163,175,185,193,199,204,206,206,204,199,193,185,175,163,149,134,118,100,81,62,41,21,0, //82.5%
0,22,43,64,84,103,122,139,154,168,181,191,200,206,211,213,213,211,206,200,191,181,168,154,139,122,103,84,64,43,22,0, //85
0,22,44,66,86,106,125,143,159,173,186,197,205,212,216,219,219,216,212,205,197,186,173,159,143,125,106,86,66,44,22,0, //87.5%
0,23,45,67,89,109,129,147,163,178,191,202,211,218,222,225,225,222,218,211,202,191,178,163,147,129,109,89,67,45,23,0, //90%
0,23,46,69,91,112,132,150,167,183,196,207,217,224,228,231,231,228,224,217,207,196,183,167,150,132,112,91,69,46,23,0, //92.5%
0,24,48,71,94,116,136,155,173,188,202,214,223,230,235,238,238,235,230,223,214,202,188,173,155,136,116,94,71,48,24,0, //95%
};

unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int DUTY_CYCLE, FBV, FB_Step, adder;

void interrupt()
{
if (TMR2IF_bit == 1){TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
if (TBL_POINTER_NEW < TBL_POINTER_OLD){P1M1_bit = ~P1M1_bit;}
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
CCPR1L = sin_table[DUTY_CYCLE];
TBL_POINTER_OLD = TBL_POINTER_NEW;
TMR2IF_bit = 0;
}}

void main()
{
SET_FREQ = 410;
TBL_POINTER_SHIFT = 0;
TBL_POINTER_NEW = 0;
TBL_POINTER_OLD = 0;
DUTY_CYCLE = 0;
FB_Step = 0;
T1CON = 0b00001001;//1:1 Prescale Value, Enables Timer1
ANSEL = 0b00000001;//RA0/AN0 as analogue input.
TRISA = 0b00000001;//PortA as output except RA0 as input
CMCON0 = 7;
PR2 = 249;
TRISC = 0x3F;
CCP1CON = 0x4C;
TMR2IF_bit = 0;
T2CON = 4;
while (TMR2IF_bit == 0);
TMR2IF_bit = 0;
TRISC = 0;
TMR2IE_bit = 1;
GIE_bit = 1;
PEIE_bit = 1;

while(1)
{
if (FBV < 512){FB_Step++;
if (FB_Step > 12) FB_Step = 12;
}
else
{
if (FB_Step > 0){FB_Step--;}}
TMR1L = 0;
TMR1H = 0;
T1IF_bit = 0;
}
}

14. Hi,
If you are using pic16f887 for this inverter, you can remove or put the comment sign // in front of CMCON0 = 7; and also in front of TMR1L = 0;
TMR1H = 0;
T1IF_bit = 0; .when you compile the code it will work. the feedback control works but it is not steady the out put voltage keep flickering and not steady. that is the problem i have notice with this code. if any body has a solution i will like to know.

1. You will need to change the feedback "update frequency" - ie the rate at which feedback occurs - depending on your observed results to obtain better results. Try using an RC low pass filter at the input of the ADC pin responsible for feedback readback. Additionally, you may want to slow down the feedback or speed it up as required to obtain stable results. How large are your observed output voltage variations?

Let me know how it goes!

Regards,
Tahmid.

2. Tahmid Please help me out as its my university project of designing this pure sine wave inverter. I have implemented the configuration but my MicroController got burnt when i turned on the power... I have used the hardware configuration as follows in the image... PLZ HELP

http://check.wholepk.com/circuit.BMP

15. Hi,
without load my output voltage is in the range of 270v for a transformer designed for 8v(primary) to 230v(secondary) winding. when i load with 100w, the output voltage drop to 230v, when i increase the load to 200w the output drop to 200v when i adjust the variable resistor that control the feedback, the output voltage changes rapidly between 200,220 and 240. At this point when i switch off the load, the output voltage goes more than300v. What part of the code will i alter to change the feedback "update frequency". and how do i slow down the feedback or speed it up.

16. Siktec would you plz share your circuit diagram of power stage with microcontroller

17. Siktec, I think its problem due to calibration of Feedback Control Variable Resistor, you are calibrating it after applying load to transformer, you should calibrate it under no load condition to 230V output, when you will put load, it will occur an increment in RMS voltage through feedback and hence, output voltage would be regulated...!
It goes more than 300v due to factor that you calibrate it to stable voltage under 200w load.

18. Hi Tahmid,

Looks like, for the feedback, you are using "pure" ADC value without any software processing (CMIIW).
What kind of circuit do you use to feed the ADC with RMS value of the sinewave AC signal?

Thank you.

1. In this case, the output is rectified, filtered and stepped down with a simple voltage divider.

2. Sir plz upload feedback of sine wave inverter by using atmega 16 and sir plz guide me to implement it on hardware only feedback part

19. Hi,
The command "if (FBV < 512){FB_Step++" FBV is always true for FBV < 512. bcoz FBV never > 512. So that the statement " FB_Step = 12" is also always true. I unable to understand the feedback code. plz add comment to the code........

1. FBV is the reading from the ADC. It can be between 0 and 1023. So, it is definitely possible to have FBV > 512.

2. ohh!! I understand.....
But what I do when I use 16f72. Its range is 0 to 255 only.

Thanks.

3. You can just change the value of 512 based on your feedback circuit and your expected voltage at the feedback pin.

20. Hi,
I face some problem using this code. I convert Mikro C code to PicBasic Pro. SPWM is working properly. but when I add feedback to my code nothing is happen. I mean that SPWM work but feedback not work. I design a square wave inverter.

problem picture 1: http://www.imagesup.net/di-1139633743615.jpg
problem picture 2: http://www.imagesup.net/?di=1113963382729

my PicBasic Pro code: (anyone plz check my code if I am worng then correct it)
DEFINE OSE 10
ON INTERRUPT GOTO ISR

'*************************VARIABLES
tblpointernew VAR WORD
tblpointerold VAR WORD
tblpointershift VAR WORD
setfreq VAR WORD
tbltemp VAR WORD
dutycycle VAR BYTE
flag VAR WORD
SINVAL VAR BYTE
VOLT VAR BYTE
FBV VAR BYTE
FBS VAR BYTE
direction VAR BIT
'*************************ALIAS
MOSA VAR PORTC.5
MOSB VAR PORTC.6

PEIE VAR INTCON.6
GIE VAR INTCON.7
TMR1IF VAR PIR1.0
TMR2IF VAR PIR1.1
TMR2IE VAR PIE1.1
'******************************

MAIN:
setfreq = 410
tblpointernew = 0
tblpointerold = 0
tblpointershift = 0
dutycycle = 0
FBV = 0
FBS = 0
TRISC = 0
PORTC = 0
PR2 = 249
CCPR1L = 0
CCP1CON = 12
TMR2IF = 0
T2CON = \$04
TMR2IF = 0
TMR2IE = 1
GIE = 1
PEIE = 1
direction = 0

START:
IF FBV < 255 THEN
FBS = FBS + 1
IF FBS > 8 THEN FBS = 8
ELSE
IF FBS > 0 THEN FBS = FBS - 1
ENDIF
TMR1L = 0 : TMR1H = 0 : TMR1IF = 0
GOTO START

DISABLE
isr:
IF TMR2IF == 1 THEN
update:
tblpointernew = tblpointerold + setfreq
IF tblpointernew < tblpointerold THEN
IF direction == 0 THEN
mosa = 0
mosb = 1
direction = 1
ELSE
mosa = 1
mosb = 0
direction = 0
ENDIF
ENDIF
tblpointershift = tblpointernew >> 11
dutycycle = tblpointershift + ADDER '(FOR FEEDBACK OPTION)
LOOKUP dutycycle, [0,16,33,49,64,79,93,106,118,129,138,146,153,158,161,163,163,161,158,153,146,138,129,118,106,93,79,64,49,33,16,0,_ '//65%
0,18,35,52,69,85,100,114,127,138,149,157,164,169,173,175,175,173,169,164,157,149,138,127,114,100,85,69,52,35,18,0,_ '//70%
0,19,38,56,74,91,107,122,136,149,160,169,176,182,186,188,188,186,182,176,169,160,149,136,122,107,91,74,56,38,19,0,_ '//75%
0,20,40,60,79,97,114,130,145,158,170,180,188,194,198,200,200,198,194,188,180,170,158,145,130,114,97,79,60,40,20,0,_ '//80%
0,22,43,64,84,103,122,139,154,168,181,191,200,206,211,213,213,211,206,200,191,181,168,154,139,122,103,84,64,43,22,0,_ '//85
0,23,45,67,89,109,129,147,163,178,191,202,211,218,222,225,225,222,218,211,202,191,178,163,147,129,109,89,67,45,23,0,_ '//90%
0,23,46,69,91,112,132,150,167,183,196,207,217,224,228,231,231,228,224,217,207,196,183,167,150,132,112,91,69,46,23,0,_ '//92.5%
0,24,48,71,94,116,136,155,173,188,202,214,223,230,235,238,238,235,230,223,214,202,188,173,155,136,116,94,71,48,24,0], sinval '//95%
CCPR1L = SINVAL
tblpointerold = tblpointernew
TMR2IF = 0
ENDIF
RESUME
ENABLE

21. Hi,
I design a Full bride Inverter. But I want to add feedback option to my project. I got 50Hz freq from my full bridge.
plz anyone help me!!!!!!!!!! How I add feedback to my project??????

my picbasic code::
DEFINE OSC 16
ON INTERRUPT GOTO UPDATE

DIR VAR BYTE
'************************* Assign some Interrupt associated aliases
T0IE VAR INTCON.5 ' TMR0 Overflow Interrupt Enable
T0IF VAR INTCON.2 ' TMR0 Overflow Interrupt Flag
GIE VAR INTCON.7 ' Global Interrupt Enable
PS0 VAR OPTION_REG.0 ' Prescaler ratio bit-0
PS1 VAR OPTION_REG.1 ' Prescaler ratio bit-1
PS2 VAR OPTION_REG.2 ' Prescaler ratio bit-2
PSA VAR OPTION_REG.3 ' Prescaler Assignment (1=assigned to WDT 0=assigned to oscillator)
T0CS VAR OPTION_REG.5 ' Timer0 Clock Source Select (0=Internal clock 1=External PORTA.4)

PWM1 VAR PORTC.5 ' Alias servo pin1
PWM2 VAR PORTC.6 ' Alias servo pin2
TRISC = 000000 ' Configure PORTC as outputs
PORTC = 0 ' Clear PORTB
'********************* Initiate the interrupt
GIE = 0 ' Turn off global interrupts
PSA = 0 ' Assign the prescaler to external oscillator
PS0 = 1 ' Set the prescaler
PS1 = 1 ' to increment TMR0
PS2 = 1 ' every 256th instruction cycle
T0CS = 0 ' Assign TMR0 clock to internal source
TMR0 = 0 ' Clear TMR0 initially
T0IE = 1 ' Enable TMR0 overflow interrupt
GIE = 1 ' Enable global interrupts

MAIN:

GOTO MAIN

DISABLE
UPDATE:
TMR0 = 100
IF DIR = 0 THEN
PWM1 = 1
PWM2 = 0
DIR = 1
ELSE
PWM2 = 1
PWM1 = 0
DIR = 0
ENDIF
T0IF = 0
RESUME
ENABLE

22. Without a working code and a basic simulation of such concepts these posts are useless and it serves neither an educational purpose nor a technical one. Sorry, but most of your posts here and in the forums falls in the commercial propaganda category...PIC16 inverter(unorganized, no schematic bogus project), Topo-magic unfinished software for almost three years, PIC controlled AVR with no schematics just pictures of you and some guy that you did him a solid...and the list goes on. If you wanna publish something for free just do it don't tease and post some worthless tripe.

23. This comment has been removed by the author.

24. Hello Tahmid, please I need your help. I have designed your sine-wave inverter using pic16f690 and IRS2110. I got a clean sine-wave at the output after the filter, especially when loaded with about 100W load. It works perfectly with resistive loads without any issue, but if I connect hair-cut clipper or ac motor, the operation is not steady. They keep turning on and off continuously but the voltage did not flunctuate. I tried different bootstrap caps 10uf,22uf,47uf,100uf and 220uf but its the same issue. Please advice.

May 29, 2014 at 7:27 AM

1. Did you take a look at the output waveform with an oscilloscope? That will reveal a bit.

Also, what is the power rating of the clipper / motor you used?

2. Dear Tahmid, thank you for the reply. I used an oscilloscope to observe the waveform, the waveform is pure-sine, I was really impressed, but its like it collapsed at about every 4 seconds. It does it so fast that you can't notice except you observe carefully. I can hear the transformer (8V-260V) breaking every 4seconds. If I connect an lcd tv, dvd or any appliances that uses switching power supply they worked fine. But with devices that rely on ordinary transformer as power source (Inductive loads), they fluctuate every 4 seconds. My lcd tv is 200w and it worked fine but the 10W clipper did not.
Thank you, I will appreciate your response.

3. Can you observe the output waveform using an oscilloscope and see how long the output is off/low during the cycling shutting off?

Additionally, could you probe the microcontroller outputs to see what happens to the SPWM drive signals when the output goes off/low? Do all the outputs go low? Or what is observed? That will give some insight into what might possibly be going on.

4. I observed the four output with a scope. The 2 low side signals(16khz) did not go low at the same time. When one is on the other is off. Same thing with the two highside signals(50hz). I also observed one highside and one lowside signals at a time, they did not go off at the same time. My highside mosfets also get hotter than the lowside ones, I used 100uF bootstrap caps. Do you have an idea? Or should I try an isolated highside driver with TLP250 and separate power supply?

25. Hi Tahmid,,
i have a question related to feedback of spwm inverter....
you have set a pointer for the feedback...when voltage is less than 2.5V,then it will be increamented to keep the voltage back at its initial value...by increasing or decreasing pointer value,duty cycle changes...So,will duty cycle of 50Hz sinewave ( output of sine wave inverter after filter ) also change? i think it will change..if not then why?

26. here is how the code for the feedback for guys using basic should look like

While 1 = 1
FbackV = ADIn 0 ' get feed back voltage from channel 0

If FbackV < 512 Then ' is feed back voltage less than 2.5v refrence voltage (this depends on what u want to use as refrence)
FbStep = FbStep + 1 ' if yes increment fbstep
If FbStep > 12 Then ' is fbstep greater than 12?
FbStep = 12 'if yes limit to 12 so that we wont overflow our table (i felt it should be 13 not 12) tahmid please respond
EndIf

ElseIf FbackV > 512 Then 'is feedback voltage greater than 2.5v refrence
FbStep = FbStep - 1 'if yes decrement fbstep
If FbStep < 0 Then 'is fbstep less than 0
FbStep = 0 ' limit it to if yes
EndIf
EndIf

Wend

Hope this helps

tunde

27. Hi Tahmid

I implemented this code but there is a big issue of o/p voltage stability.
Lot of oscillations on o/p..No matter how fast the loop executes , there is jitter on o/p
Secondly, load response is quite poor.
Do you have an idea how this can be tackled?

28. Dear tahmid, thanks for this Feedback in SPWM. please help me include a low voltage detector using a comparator in shutting down the spwm when the voltage get low from the battery.. thank u.

1. You can use the internal ADC to measure the battery voltage and shut down the SPWM in software when battery is too low.

29. Send the sine wave inverter circuit and code to stevejossy80@yahoo.com

30. HI.
my View is that u dont do your feed back voltage check all d time. And also you need to have something like a band gap before u do ur regulation.
Say for instance if your output voltage falls between 230v and 225, u dont really need to adjust the voltage as most equipment will function well using this voltage range.
You can even extend the range between 220 and 230 such that as long as you output voltage is still within this gap u dont go into the voltage compensation loop.

Example:

If your reference is 512 which is equivalent to 2.5v on a 10bit adc or 128 on an 8bit adc as the case may be.

Now, assuming your max output voltage to be 230 volts which is equivalent to 1023 so an output voltage of 200V will be 889. this can actually be your reference. And an output of 220V will be 978 so now you can track your range in something like this.

while FbackV >978 and <1023
do watever
wend

Compensation:
if FbackV < 978 then ' that is if output voltage is less than 220volts then do compensation
do compensation here
end if

so like that you can keep your output stable. output fluctuating i think is as a result of d fact that, the code is trying to compensate for change in voltage levels all the time.

while you voltage is still within the range you set compensation will not happen.

hope this helps.

1. Hello,
I have been leaning towards your line of thinking because when I implement the feedback code as given by tahmid, my open circuit voltage was 250Vac but when on load (no matter how small) the voltage drops to 150 and the feedback doesn't come into effect. Hence, I am thinking of sampling the output at an interval of between 4ms to 10ms. So, please, what would you suggest the sampling interval should be?

Regards
Faruq

31. Hi Tamhid:

Can you tell me about the filter you used for producing pure AC wave from SPWM.

32. hi tahmid

i am doing project on AC to DC converter

can this feed back code used in this ac to dc converter ?

if it can be used then where we have to put this feedback loop

pls help me..

33. Thanks Mr. Tahmid it's very helpful details. for a sine wave h bridge is we have to control the pwm of both push pull and h bridge for feedback

34. Hi
l was caught up by your wonderful work, and l know you can help me, l bought power inverter using
PIC16F876A using 20MHz crystal but is damage, l want you to help me to get HEX file for it or program for me, l dont mind if l have to pay

1. hi Fred, How far with your project? Has it worked? what makes you think your inverter is not working because of the Program and nothing else?

2. Because the IC pic16F876A got burnt

35. Anyone here having complete code for SPWM inverter including Feedback for regulated output voltage using a single Microcontroller with LCD Display for Voltages, Battery Percentage, Over Under Voltage Protection & Automatic Switching etc

36. Dear tahmid, please help me to write the code for the internal ADC to measure the battery voltage and shut down the SPWM in software when battery is too low.

37. im just reading this post after so long
but im grateful for it its been very helpful in my design
although at what point did you connect the feedback ?
the drain, source where exactly
and through wha size of resistor
thank you sir

38. What is the use of TMR1 code in the Feedback code ?

39. my array does not access more than the 255th value

40. Hi Mr. Tahmid
Thank you for that information
I made inverter circuit with feedback
But when put load 200 watt the output voltage down .
Why?

1. I same for you. When put 45watt the output from 270vac down up 150vac. Why? If you complete inverter, you can send me code?

2. 310V: 220 x sqrt(2)!

41. Sir plz upload feedback of sine wave inverter by using atmega 16 and sir plz guide me to implement it on hardware only feedback part

42. Sir I need that feedback look like this.

43. hi dear its blog very nice and helpful thanks from inverter

44. This comment has been removed by the author.

45. how to generate sine table with dead time?

46. So much inspired with the documents you have shared. Thanks a lot, this was much useful and handy. Battery is the only source that assists to prevent us from the power demanding time, so choice of your battery should give at least minimum power consumption so better to buy your batteries & inverters from the battery authorized dealers.
Inverter Battery dealers in Chennai

47. KK Batteries is one of the best Inverter Service centre in Chennai. We provide batteries with guarantee thus making us the best Car Battery Dealers in Chennai. We are Inverter Battery dealers in Chennai with various accessible models. Inverter Battery dealers in Chennai

48. KK Batteries is one of the best Inverter Service centre in Chennai. We provide batteries with guarantee thus making us the best Car Battery Dealers in Chennai. We are Inverter Battery dealers in Chennai with various accessible models. Inverter Battery dealers in Chennai

49. KK Batteries is one of the best Inverter Service centre in Chennai. We provide batteries with guarantee thus making us the best Car Battery Dealers in Chennai. We are Inverter Battery dealers in Chennai with various accessible models. Inverter Battery dealers in Chennai

50. KK Batteries is one of the best Inverter Service centre in Chennai. We provide batteries with guarantee thus making us the best Car Battery Dealers in Chennai. We are Inverter Battery dealers in Chennai with various accessible models. Inverter Battery dealers in Chennai

51. It is very interesting topic. Thank you. Mobile Recharge Apps