Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

How to change voltage level in PWM controlled 3 phase inverter?

Status
Not open for further replies.

suman.sardar

Junior Member level 3
Joined
Dec 6, 2016
Messages
26
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
198
I am designing a 3 phase DC-AC inverter with PIC18F4431. But I am having difficulties while changing voltage level at the inverter output. I am using PCPWM. How to vary the modulation index ?
The circuit I used (Inverter output filter may be different) and waveform I got are as follows:
TEK00001.PNG
Pic Development Board for PCPWM.pdsprj-page-001.jpg
 

You have to vary the VBus voltage. Pink singnal is not correct. it is slightly distorted. Zip and post the code which I gave to you or the latest code. I will fix it.

Also the output voltage can be adjusted by varying the PWM duty but for that feedback has to be provided. One of the Phase volatge has to be scaled down and converted to DC so that your nominal output voltage should produce 2.5V DC for adc input. Based on if output voltage is lesser or higher different PWM sets have to be used to get constant output voltage. This method can also be used to vary the output voltage if you need higher or lower voltage by using different PWM duty sets.
 
Last edited:
Code is same as before. Output voltage level can be varied by varying modulation index. Is it possible to vary modulation index in open loop configuration?
And also in PCPWM which register controls these voltage or freq modulation index?
 

You are using Tahmid's method and so don't change any register value, instead create different sets of PWM duties and then use them to vary the PWM duty and get the desired output voltage. Are you also varying VBus Voltage ? What is your VBus voltage ?

Use this code. I have made changes to third phase PWM duty updating code in ISR. Now, there will be no distortion in the Pink signal. Also I have added LCD Code. I have tested it and it is working fine. Use LCD to display Input Voltage, Output Voltage, etc...


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
/* 
 * Project Three Phase Inverter
 * File:   main.c
 * Author: Okada
 *
 * Created on April 6, 2017, 12:13 AM
 */
 
 
#define _XTAL_FREQ 20000000
 
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <p18f4431.h>
 
#pragma config OSC      = HS
#pragma config FCMEN    = ON
#pragma config IESO     = OFF
#pragma config DEBUG    = OFF
#pragma config LVP      = OFF
#pragma config PWRTEN   = ON
#pragma config WDTEN    = OFF
#pragma config WDPS     = 2048
#pragma config WINEN    = OFF
#pragma config MCLRE    = ON
#pragma config BOREN    = ON
#pragma config BORV     = 42
#pragma config PWMPIN   = OFF
#pragma config LPOL     = HIGH
#pragma config HPOL     = HIGH
#pragma config T1OSCMX  = OFF
#pragma config STVREN   = ON
#pragma config CP0      = OFF
#pragma config CP1      = OFF
#pragma config CPB      = OFF
#pragma config CPD      = OFF
#pragma config WRT0     = OFF
#pragma config WRT1     = OFF
#pragma config WRTC     = OFF
#pragma config WRTB     = OFF
#pragma config WRTD     = OFF
#pragma config EBTR0    = OFF
#pragma config EBTR1    = OFF
#pragma config EBTRB    = OFF
 
//ISR Method - Uncomment only one option at a time
#define METHOD1
//#define METHOD2
 
//AC Frequency - Uncomment only one option at a time
//#define One_Hz
//#define Twenty_Hz
#define Fifty_Hz
//#define Two_Hundred_Hz
//#define One_KHz
//#define Ten_KHz
 
/*
 * pwm resolution = log((1*FOSC)/Fpwm) / log(2)
 * pwm resolution = log((20000000/16000) / log(2))
 * pwm resolution = 1225 (98% of 2^10.2877)
 *
 * So, Sine table max value should be 1225 and it should have 32 entries for 180 degrees
 */
 
#define _LCD_FIRST_ROW          0x80     //Move cursor to the 1st row
#define _LCD_SECOND_ROW         0xC0     //Move cursor to the 2nd row
#define _LCD_THIRD_ROW          0x94     //Move cursor to the 3rd row
#define _LCD_FOURTH_ROW         0xD4     //Move cursor to the 4th row
#define _LCD_CLEAR              0x01     //Clear display
#define _LCD_RETURN_HOME        0x02     //Return cursor to home position, returns a
                                         //shifted display to its original position.
                                         //Display data RAM is unaffected.
#define _LCD_CURSOR_OFF         0x0C     //Turn off cursor
#define _LCD_UNDERLINE_ON       0x0E     //Underline cursor on
#define _LCD_BLINK_CURSOR_ON    0x0F     //Blink cursor on
#define _LCD_MOVE_CURSOR_LEFT   0x10     //Move cursor left without changing
                                         //display data RAM
#define _LCD_MOVE_CURSOR_RIGHT  0x14     //Move cursor right without changing
                                         //display data RAM
#define _LCD_TURN_ON            0x0C     //Turn Lcd display on
#define _LCD_TURN_OFF           0x08     //Turn Lcd display off
#define _LCD_SHIFT_LEFT         0x18     //Shift display left without changing
                                         //display data RAM
#define _LCD_SHIFT_RIGHT        0x1E     //Shift display right without changing
                                         //display data RAM
 
// LCD module connections
#define LCD_RS LATDbits.LATD0
#define LCD_EN LATDbits.LATD1
#define LCD_D4 LATDbits.LATD2
#define LCD_D5 LATDbits.LATD3
#define LCD_D6 LATDbits.LATD4
#define LCD_D7 LATDbits.LATD5
 
#define LCD_RS_Direction TRISDbits.TRISD0
#define LCD_EN_Direction TRISDbits.TRISD1
#define LCD_D4_Direction TRISDbits.TRISD2
#define LCD_D5_Direction TRISDbits.TRISD3
#define LCD_D6_Direction TRISDbits.TRISD4
#define LCD_D7_Direction TRISDbits.TRISD5
// End LCD module connections 
        
#define EN_DELAY 300
#define LCD_STROBE {LCD_EN = 1; __delay_us(EN_DELAY); LCD_EN = 0; __delay_us(EN_DELAY);}; 
 
unsigned int sine_table[32] = {
                                //0,9,37,83,144,218,302,394,490,586,678,762,836,897,943,971,
                                //980,971,943,897,836,762,678,586,490,394,302,218,144,83,37,9
                                0,12,47,103,179,272,378,493,613,732,847,953,1046,1122,1178,1213,
                                1225,1213,1178,1122,1046,953,847,732,613,493,378,272,179,103,47,12
                              };
 
char *text1 = "3P-Inverter";
char *text2 = "Testing...";
char *text3 = "LCD Working";
 
#ifndef Ten_KHz
    #ifdef METHOD1
        unsigned int TBL_POINTER_NEW   = 0;
        unsigned int TBL_POINTER_OLD   = 0;
        unsigned int TBL_POINTER_SHIFT = 0;
        unsigned char DUTY_CYCLE[3]    = {0, 0, 0};
        unsigned int SET_FREQ = 410;
    #endif
 
    #ifdef METHOD2
        unsigned int TBL_POINTER_NEW[3]   = {0, 0, 0};
        unsigned int TBL_POINTER_OLD[3]   = {0, 0, 0};
        unsigned int TBL_POINTER_SHIFT[3] = {0, 0, 0};
        unsigned char DUTY_CYCLE[3]       = {0, 0, 0};
        unsigned int SET_FREQ = 410;
    #endif
#endif
 
#ifdef Ten_KHz
    #ifdef METHOD1
        unsigned long int TBL_POINTER_NEW   = 0;
        unsigned long int TBL_POINTER_OLD   = 0;
        unsigned long int TBL_POINTER_SHIFT = 0;
        unsigned char DUTY_CYCLE[3]    = {0, 0, 0};
        unsigned long int SET_FREQ = 410;
    #endif
 
    #ifdef METHOD2
        unsigned long int TBL_POINTER_NEW[3]   = {0, 0, 0};
        unsigned long int TBL_POINTER_OLD[3]   = {0, 0, 0};
        unsigned long int TBL_POINTER_SHIFT[3] = {0, 0, 0};
        unsigned char DUTY_CYCLE[3]       = {0, 0, 0};
        unsigned long int SET_FREQ = 410;
    #endif
#endif
 
const char character[] = {6,9,9,6,0,0,0,0};
        
void __delayX_mSec(unsigned long int mSec);
 
void LCD_Cmd(char out_char);
void LCD_Chr(char row, char column, char out_char);
void LCD_Chr_Cp(char out_char);
void LCD_Init();
void LCD_Out(char row, char col, char *text);
void LCD_Out_Cp(char *text);
        
//Timer2
//Prescaler 1:1; Postscaler 1:2; TMR2 Preload = 155; Actual Interrupt Time : 62.4 us, PWM frequency: 16KHz
void InitTimer2(){
  T2CON = 0x0C;
  PIE1bits.TMR2IE = 1;
  PR2 = 155;
  INTCON = 0xC0;
}
 
void interrupt isr(){
  if((PIE1bits.TMR2IE) && (PIR1bits.TMR2IF)) {
      //Enter your code here
 
      //Example Calculation for 50Hz AC
      //SET_FREQ = 65536 / (32 * 5) = 410
      //Required AC Frequency = 50 Hz
      //PWM frequency = 16KHz
      //Tpwm = 1/16KHz = 62.5us  (Timer2 Interrupt Period)
      //62.5us * 32 * 5 = 10ms (for 180 degrees)
      //10ms * 2 = 20ms
      //AC frequency = 1/20ms = 50.0Hz
 
      #ifdef METHOD1
        //#ifndef Ten_KHz
            TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
            TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
            DUTY_CYCLE[0] = TBL_POINTER_SHIFT;
            DUTY_CYCLE[1] = TBL_POINTER_SHIFT;
            DUTY_CYCLE[2] = TBL_POINTER_SHIFT;
 
            if((DUTY_CYCLE[1] + 21) < 32)DUTY_CYCLE[1] += 21;
            else DUTY_CYCLE[1] -= 11;
 
            if((DUTY_CYCLE[2] + 11) < 32)DUTY_CYCLE[2] += 11;
            else DUTY_CYCLE[2] -= 21;
 
            PDC0L = sine_table[DUTY_CYCLE[0]];
            PDC0H = sine_table[DUTY_CYCLE[0]] >> 8;
 
            PDC1L = sine_table[DUTY_CYCLE[1]];
            PDC1H = sine_table[DUTY_CYCLE[1]] >> 8;
 
            PDC2L = sine_table[DUTY_CYCLE[2]];
            PDC2H = sine_table[DUTY_CYCLE[2]] >> 8;
 
            TBL_POINTER_OLD = TBL_POINTER_NEW;
        //#endif
 
        //#ifdef Ten_KHz
            
        //#endif 
      #endif
      
      #ifdef METHOD2
        //#ifndef Ten_KHz
            TBL_POINTER_NEW[0] = TBL_POINTER_OLD[0] + SET_FREQ;
            TBL_POINTER_SHIFT[0] = TBL_POINTER_NEW[0] >> 11;
            DUTY_CYCLE[0] = TBL_POINTER_SHIFT[0];
            PDC0L = sine_table[DUTY_CYCLE[0]];
            PDC0H = sine_table[DUTY_CYCLE[0]] >> 8;
            TBL_POINTER_OLD[0] = TBL_POINTER_NEW[0];
            
            
            
            TBL_POINTER_NEW[1] = TBL_POINTER_OLD[1] + SET_FREQ;
            TBL_POINTER_SHIFT[1] = TBL_POINTER_NEW[1] >> 11;
            DUTY_CYCLE[1] = TBL_POINTER_SHIFT[1];
            
            if((DUTY_CYCLE[1] + 21) < 32)DUTY_CYCLE[1] += 21;
            else DUTY_CYCLE[1] -= 11;
            
            PDC1L = sine_table[DUTY_CYCLE[1]];
            PDC1H = sine_table[DUTY_CYCLE[1]] >> 8;
            TBL_POINTER_OLD[1] = TBL_POINTER_NEW[1];
            
            
            
            TBL_POINTER_NEW[2] = TBL_POINTER_OLD[2] + SET_FREQ;
            TBL_POINTER_SHIFT[2] = TBL_POINTER_NEW[2] >> 11;
            DUTY_CYCLE[2] = TBL_POINTER_SHIFT[2];
            
            if((DUTY_CYCLE[2] + 11) < 32)DUTY_CYCLE[2] += 11;
            else DUTY_CYCLE[2] -= 21;
            
            PDC2L = sine_table[DUTY_CYCLE[2]];
            PDC2H = sine_table[DUTY_CYCLE[2]] >> 8;
            TBL_POINTER_OLD[2] = TBL_POINTER_NEW[2];
        //#endif
 
        //#ifdef Ten_KHz
            
        //#endif
      #endif
 
      PIR1bits.TMR2IF = 0;
  }
}
 
void __delayX_mSec(unsigned long int mSec) {
    while(mSec) {
        __delay_ms(1);
        mSec--;
    }
}
 
void LCD_Cmd(char out_char) {
    
    LCD_RS = 0;
 
    LCD_D4 = (out_char & 0x10)?1:0;
    LCD_D5 = (out_char & 0x20)?1:0;
    LCD_D6 = (out_char & 0x40)?1:0;
    LCD_D7 = (out_char & 0x80)?1:0;
    LCD_STROBE
    LCD_D4 = (out_char & 0x01)?1:0;
    LCD_D5 = (out_char & 0x02)?1:0;
    LCD_D6 = (out_char & 0x04)?1:0;
    LCD_D7 = (out_char & 0x08)?1:0;
    LCD_STROBE
 
    if(out_char == 0x01)__delay_ms(2);
}
 
void LCD_Chr(char row, char column, char out_char) {
    switch(row) {
 
        case 1:
        LCD_Cmd(0x80 + (column - 1));
        break;
        case 2:
        LCD_Cmd(0xC0 + (column - 1));
        break;
        case 3:
        LCD_Cmd(0x94 + (column - 1));
        break;
        case 4:
        LCD_Cmd(0xD4 + (column - 1));
        break;
    };
 
    LCD_RS = 1;
 
    LCD_D4 = (out_char & 0x10)?1:0;
    LCD_D5 = (out_char & 0x20)?1:0;
    LCD_D6 = (out_char & 0x40)?1:0;
    LCD_D7 = (out_char & 0x80)?1:0;
    LCD_STROBE
 
    LCD_D4 = (out_char & 0x01)?1:0;
    LCD_D5 = (out_char & 0x02)?1:0;
    LCD_D6 = (out_char & 0x04)?1:0;
    LCD_D7 = (out_char & 0x08)?1:0;
    LCD_STROBE
}
 
void LCD_Chr_Cp(char out_char) {
    LCD_RS = 1;
 
    LCD_D4 = (out_char & 0x10)?1:0;
    LCD_D5 = (out_char & 0x20)?1:0;
    LCD_D6 = (out_char & 0x40)?1:0;
    LCD_D7 = (out_char & 0x80)?1:0;
    LCD_STROBE
 
    LCD_D4 = (out_char & 0x01)?1:0;
    LCD_D5 = (out_char & 0x02)?1:0;
    LCD_D6 = (out_char & 0x04)?1:0;
    LCD_D7 = (out_char & 0x08)?1:0;
    LCD_STROBE
}
 
 
void LCD_Init() {
    __delayX_mSec(200);
 
    LCD_RS_Direction = 0;
    LCD_EN_Direction = 0;
    LCD_D4_Direction = 0;
    LCD_D5_Direction = 0;
    LCD_D6_Direction = 0;
    LCD_D7_Direction = 0;
 
    LCD_RS = 0;
    LCD_EN = 0;
    LCD_D4 = 0;
    LCD_D5 = 0;
    LCD_D6 = 0;
    LCD_D7 = 0;
 
    __delay_ms(30);
 
    LCD_D4 = 1;
    LCD_D5 = 1;
    LCD_D6 = 0;
    LCD_D7 = 0;
 
    LCD_STROBE
 
    __delay_ms(30);
 
    LCD_D4 = 1;
    LCD_D5 = 1;
    LCD_D6 = 0;
    LCD_D7 = 0;
 
    LCD_STROBE
 
    __delay_ms(30);
 
    LCD_D4 = 1;
    LCD_D5 = 1;
    LCD_D6 = 0;
    LCD_D7 = 0;
 
    LCD_STROBE
 
    __delay_ms(30);
 
    LCD_D4 = 0;
    LCD_D5 = 1;
    LCD_D6 = 0;
    LCD_D7 = 0;
 
    LCD_STROBE
 
    __delay_ms(30);
 
    LCD_Cmd(0x28);
    LCD_Cmd(0x06);
}
 
void LCD_Out(char row, char col, char *text) {
    while(*text) {
         LCD_Chr(row, col++, *text++);
    }
}
 
void LCD_Out_Cp(char *text) {
    while(*text)
         LCD_Chr_Cp(*text++);
}
 
void CustomChar(char pos_row, char pos_char) {
    char i;
 
    LCD_Cmd(64);
 
    for (i = 0; i<=7; i++){
        LCD_Chr_Cp(character[i]);
    }
 
    LCD_Chr(pos_row, pos_char, 0);
}
 
int main(int argc, char** argv) {
 
    TRISA = 0xC0;
    TRISB = 0x00;
    TRISC = 0x00;
    TRISD = 0x00;
    
    LCD_Init();
    LCD_Cmd(_LCD_CURSOR_OFF);
    LCD_Cmd(_LCD_CLEAR);
    
    LCD_Out(1,1,text1);
 
    #ifdef One_Hz
        SET_FREQ = 8; //8.2
    #endif
 
    #ifdef Twenty_Hz
        SET_FREQ = 164;
    #endif
 
    #ifdef Fifty_Hz    
        SET_FREQ = 410;
    #endif
 
    #ifdef Two_Hundred_Hz      
        SET_FREQ = 1640;
    #endif
 
    #ifdef One_KHz
        SET_FREQ = 8200;
    #endif
 
    #ifdef Ten_KHz
        //SET_FREQ = 5368709120; //5374034001;   //Not Possible, Value Exceeds 16-Bit Value
    #endif
 
    PTCON0 = 0x00;
    PWMCON0 = 0x40;
    PWMCON1 = 0x01;
    DTCON = 0x00;
    OVDCOND = 0xFF;
    OVDCONS = 0xFF;
    FLTCONFIG = 0x00;
 
    //PTPER = ((Tpwm * Fosc/4) / PTMRPS) - 1
    //PTMRPS = 1:1 = 1
    //Tpwm = 62.5us, 16 KHz Fpwm
    //((62.5u * 20000000/4) / 1) - 1
    //PTPER = 311.5 = 312 = 0x0138
 
    PTPERL = 0x38;
    PTPERH = 0x01;
    SEVTCMPL = 0x00;
    SEVTCMPH = 0x00;
 
    InitTimer2();
 
    PTCON1 = 0x80;
 
    while(1) {
            LCD_Out(2,1,text2);
            __delayX_mSec(500);
            LCD_Out(2,1,text3);
            __delayX_mSec(500);
    }
 
    return (0);
}

 
Last edited:

Fixed Vbus = 96v
I can always reduce the duty cycle value from 1225 (all other duty cycle values as well). Right?
Did you calculate the duty cycle in excel sheet or with the help of some sine look up table generator like SMARTSINE?
 

I use tools available at this website.

https://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml

After generating sine table I just arranged then so that starting value is 0.

- - - Updated - - -

Yes, you can change the peak PWM duty value.

1225 peak value I got for 98% duty.

* pwm resolution = log((1*FOSC)/Fpwm) / log(2)
* pwm resolution = log((20000000/16000) / log(2))
* pwm resolution = 1225 (98% of 2^10.2877)

To lower the Inverter output voltage make another sine table like 78% of 2^10.2877 that is peak value = 0.78 * 2450 = 978

You get this.

Code:
489,584,676,761,835,896,941,969,978,969,941,896,835,761,676,584,
489,394,302,217,143,82,37,9,0,9,37,82,143,217,302,394,

=

Code:
0,9,37,82,143,217,302,394,489,584,676,761,835,896,941,969,
978,969,941,896,835,761,676,584,489,394,302,217,143,82,37,9

This will lower the voltage


What range of Vo you need ?
 

Note also there are several errors on the schematic:

1. VDD and MCLR have maximum 5V limit but you have them connected to 12V
2. C9 & C10 probably should be ~22pF not 1000uF
3. R20, R21, R22, C7, C8 and C9 valus look suspicious but I'm not sure what the load is.

Brian.
 

Reducing duty cycle values is reducing the magnitude of sine wave. But the waveform is getting a dc shift. Why is that?
MI=0.8.png

For lower lower % of 2^10.2877 the DC shift is even more
 

What is the load ?
 

No load condition. I just used RC filter at inverter output and then took hooked up the Oscilloscope
 

Same problem for all the three phases ?

I tested the code for 80% duty in Proteus and I don't see any problem. See attached image and simulation video.
 

Attachments

  • Three Phase Inverter.png
    Three Phase Inverter.png
    140.8 KB · Views: 145
  • Three Phase Inverter - Proteus Simulation Video.rar
    300.7 KB · Views: 117

Yeah with all the phases.
I checked it in hardware. Waveforms are getting DC shifted for lower values. Except that everything looks fine.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top