I have previously shown how to implement SPWM in PIC16: https://www.edaboard.com/blog/1800/
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:
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:
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:
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.
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:
Code:
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%
};
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:
Code:
FBV = ADC_Get_Sample(FBCh);
if (FBV < 512){
FB_Step++;
if (FB_Step > 12) FB_Step = 12;
}
else{
if (FB_Step > 0){
FB_Step--;
}
}
adder = FB_Step << 5;
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:
Code:
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;
DUTY_CYCLE = TBL_POINTER_SHIFT + adder;
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.