I have previously written quite a few articles on sinusoidal pulse width modulation (SPWM). I've discussed about how to generate the sine table, how to implement it, how to practically generate the SPWM signals (with example code) and also how to implement feedback with simple sine table manipulation with table pointer instead of complex PID control. All these methods have one thing in common regarding the implementation - use of the sine table and its control with the table pointer. Whether you use or implement feedback or not, the table pointer is used to access and retrieve values from the sine table.
Before reading or going through this
article, I suggest you go through these first:
Tutorial (Click here to open tutorial): Generation and Implementation of Sine Wave Table
Article (Click here to open article): Smart Sine – Software to generate sine table
Article (Click here to open article): Generation of sine wave using SPWM in PIC16F684
Article (Click here to open article): Smart Sine – Software to generate sine table
Article (Click here to open article): Generation of sine wave using SPWM in PIC16F684
It took quite a while for me to understand exactly how the table pointer works in this case – to retrieve data from the sine table and feed it to the PWM module and generate the required output 50Hz frequency (you can use any frequency but my requirement is 50Hz). I had come across the method and its explanation when coding for the dsPIC33 microcontroller while I was attempting to make a sine wave inverter using the dsPIC33. After a lot of research and thinking, I could finally implement it for PIC16.
While many have seen my posted codes and explanations regarding sinusoidal pulse width modulation (SPWM), some people have requested me to explain how the table pointer in the interrupt works. Remembering my difficult experience with this, I decided to write up this article to help all of you who are struggling with this to help clear your doubts and make you understand exactly how it works so that one can implement SPWM with a sine table with any number of table values and for any desired output frequency.
Let’s take a look at the code line by line. And I’ll explain it all. Keep in mind that the target microcontroller is a PIC16F684 running off an oscillator frequency of 16MHz. So, if you’re attempting to “port” the code to any other microcontroller keep in mind that the registers will/may be different from those in the PIC16F684.
//----------------------------------------------------------------------------------------
//Programmer: Syed Tahmid Mahbub
//Target Microcontroller: PIC16F684
//Compiler: mikroC PRO for PIC (Can easily port to any other compiler)
//-----------------------------------------------------------------------------------------
unsigned char sin_table[32]={0,25,49,73,96,118,137,
159,177,193,208,220,231,239,245,249,250,249,245,
239,231,220,208,193,177,159,137,118,96,73,49,25};
unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int TBL_temp;
unsigned char DUTY_CYCLE;
void interrupt(){
if (TMR2IF_bit == 1){
TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
if (TBL_POINTER_NEW < TBL_POINTER_OLD){
CCP1CON.P1M1 = ~CCP1CON.P1M1; //Reverse direction of full-bridge
}
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
DUTY_CYCLE = TBL_POINTER_SHIFT;
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;
ANSEL = 0; //Disable ADC
CMCON0 = 7; //Disable Comparator
PR2 = 249;
TRISC = 0x3F;
CCP1CON = 0x4C;
TMR2IF_bit = 0;
T2CON = 4; //TMR2 on, prescaler and postscaler 1:1
while (TMR2IF_bit == 0);
TMR2IF_bit = 0;
TRISC = 0;
TMR2IE_bit = 1;
GIE_bit = 1;
PEIE_bit = 1;
while(1);
}
//-------------------------------------------------------------------------------------
Here's the circuit diagram (the hardware portion of SPWM implementation):
Fig. 1 - Circuit Diagram (Click on image to enlarge it)
For the MOSFET drivers, you can use the common high-low side
drivers – IR2110. For a thorough tutorial on using the IR2110, check out:
Another tutorial (this one regarding low side MOSFET drivers):
Now, back to the software side of things. The registers responsible for the automatic updating of the duty cycle are SET_FREQ, TBL_POINTER_SHIFT, TBL_POINTER_NEW, TBL_POINTER_OLD and DUTY_CYCLE. So, I’ll get to this a little later. Let me deal with the rest first.
Setting ANSEL to 0 selects the ADC-associated pins as digital and this is done since the ADC isn’t required for this program, and this frees up the pins multiplexed to the ADC so that they can be used as digital IO lines. Setting CMCON0 to 7 does the same thing, just for the comparator instead of for the ADC.
PORTC bits 0 to 5 are all made input at first. CCP1CON is set to 0x4C. This sets the ECCP mode to “PWM Mode” with P1A, P1B, P1C and P1D set active-high. Timer 2 is turned on and a polling check is done to check if Timer 2 has overflowed or not. When Timer 2 overflows, the interrupt flag is cleared and PORTC bits are selected as output pins. Timer 2 interrupt, global interrupt and peripheral interrupt are enabled.
Now the program just loops in the infinite endless while loop. So, the program now just does nothing – but execute the interrupt when it occurs. Since PR2=249, the time period is 62.5us. I assume you can do the math. So, an interrupt occurs every 62.5us.
Now on to the main part of this code – the interrupt. Every 62.5us the interrupt service routine is “entered” (if you think of it like that in terms of program “flow”) and executed.
In the main() function, I had assigned the value of 410 to SET_FREQ. SET_FREQ determines the output frequency of the sine wave, which in our case here is 50Hz. You’ll soon see how.
In the interrupt, the variable TBL_POINTER_NEW is updated – every 62.5us it is increased by 410. TBL_POINTER_NEW is a 16-bit variable and at the beginning of program execution has a value of 0. So, after the first interrupt it holds 410, after the second interrupt 820, after the third 1230 and so on. After 159 interrupts, TBL_POINTER_NEW holds 65190. So, at the next interrupt, TBL_POINTER_NEW overflows and holds 64.
The interrupt occurs every 62.5us. At each interrupt TBL_POINTER_NEW is increased by 410. At the 160th interrupt, TBL_POINTER_NEW overflows, just as it does the 320th interrupt, the 480th interrupt and so on.
Initially TBL_POINTER_NEW holds 0 and on subsequent interrupts, TBL_POINTER_NEW holds 410, 820, 1230, 1640, 2050, 2460, 2870, 3280, 3690, 4100 and so on.
TBL_POINTER_SHIFT right-shifts TBL_POINTER_NEW eleven times and stores that value. Right shifting 11 times is the same as dividing by 211 (211 = 2048) – just more efficient. When the microcontroller starts up, TBL_POINTER_SHIFT holds 0 and on subsequent interrupts, TBL_POINTER_SHIFT holds 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3 ….. and so on. Now, the trend is that TBL_POINTER_SHIFT holds the same value for 5 consecutive interrupts – go on, you can do the math. Why 5 times? We’ll see that a little later.
After TBL_POINTER_NEW is shifted 11 times, DUTY_CYCLE is assigned the resultant 5-bit value. This acts as – or rather is – the table pointer and the required value is retrieved off the sine table. This value is assigned to CCPR1L, thus setting the appropriate duty cycle.
Now let’s see why TBL_POINTER_SHIFT is needed to be incremented every 5 interrupts and how we’ve done that.
Our frequency is 50Hz – time period is 20ms. A half cycle takes 10ms. Recall that the sine table used is only for half a cycle. So, the 32 values must be called such that they make up the half cycle. The interrupt service routine is executed each 62.5us and so, retrieving all the values from the sine table and using them to update the duty cycle takes a total time of 62.5us * 32 = 2000us (assuming each value is retrieved/called once). That’s 2ms. But our half cycle is 10ms – 5 times larger than what we have now. So, we increase the time five folds. How? By calling each value from the table 5 times instead of only once. So, the time involved is now 32 * 62.5us * 5 = 10000us = 10ms.
This calculation we’ve just done is related to the frequency – 50Hz desired frequency and thus 10ms half cycle. I’ve shown this “backward” to explain why this has been chosen but remember that the microcontroller doesn’t know you want 50Hz frequency. The microcontroller doesn’t know that the desired time is 10ms.
So, now you know the answer to why I’ve called each sine table value 5 times: to ensure that the sine table that has 32 values occupies the entire 10ms. Now, how did I make it repeat 5 times? By setting SET_FREQ to 410. You might be wondering how this works. Well, it works this way.
SET_FREQ = 410. Each interrupt, TBL_POINTER_NEW is increased by 410. Every 5 interrupts, TBL_POINTER_NEW is increased by 2050 (compared to the initial value). 211 = 2048. Since TBL_POINTER_SHIFT divides TBL_POINTER_NEW by 2048, when TBL_POINTER_NEW increases 5*410 times, TBL_POINTER_SHIFT increases once. So, the number of repeats (5 in this case) is equal to the number of interrupts it takes for TBL_POINTER_SHIFT to increase by one, which is equal to the number of times it takes for SET_FREQ to equal or cross 211 (=2048). Since SET_FREQ = 410, the number of times to cross 2048 is 5 and that is the number of times each table value is called. So, the table pointer is incremented every 5 interrupts. Thus SET_FREQ determines the frequency. If we had set SET_FREQ to 200, the number of times to cross 2048 would be 11, as 200*10 = 2000 (less than 2048) but 200*11 = 2200 (more than 2048). Thus each sine table value would be called 11 times – the table pointer would be incremented every 11 interrupts. The output time period of the sine wave would then be 2 * 32 * 62.5us * 11 = 44000us = 44ms. The output frequency would thus be 22.7 Hz instead of the 50Hz we have now.
SET_FREQ can be calculated as {65536/ (32 * 5)} = 409.6 = 410 rounded off to the nearest integer. That’s [216/{(Number of sine table values) * (Number of times each value is to be called)}].
I’ve talked about SET_FREQ, TBL_POINTER_NEW, TBL_POINTER_SHIFT and right shifting eleven times. Now you may ask why eleven times. Why not 5 or 10 or 12 or any other value? The reason is that we have a sine table with 32 values. 32 = 25. Shifting a 16-bit variable eleven times to the right leaves us with a 5-bit value – one between 0 and 31. These 5 bits are the upper most (most significant) 5 bits. This 5-bit value is the sine table pointer. This works in conjunction with the number of sine table values and the value of SET_FREQ to set or determine the output sine wave frequency. If we had 64 sine table values, we would right-shift TBL_POINTER_NEW 10 times instead of 11 so that the shifting operation results in a 6-bit value. 26 = 64 and that is the number of sine table values we have – the table pointer would have a value between 0 and 63.
At the end of this tutorial, I have covered an example. You should follow the example and I’m sure things will be clear by then (I know that the amount of information presented thus far is overwhelming and difficult to grasp!).
In the interrupt, after the duty cycle is set, TBL_POINTER_OLD is assigned the value of TBL_POINTER_NEW. When TBL_POINTER_NEW is first assigned 410, TBL_POINTER_OLD holds 0. The 11-bit shifting is done. The duty cycle is set and then TBL_POINTER_OLD is set. So, the TBL_POINTER_OLD update trails TBL_POINTER_NEW update. So, every interrupt until TBL_POINTER_NEW overflows, TBL_POINTER_NEW is greater than TBL_POINTER_OLD.
When TBL_POINTER_NEW = 64370 and the ISR is to be executed, TBL_POINTER_OLD also holds 64370. TBL_POINTER_NEW is increased to 64780 and then the sine table value is called and TBL_POINTER_OLD is then updated to 64780. The next interrupt, TBL_POINTER_NEW is increased to 65190 and the “if condition” is again false since at that stage TBL_POINTER_OLD holds 64780 – TBL_POINTER_NEW > TBL_POINTER_OLD. Then at the end of the ISR, TBL_POINTER_OLD is assigned 65190. And now comes the interesting part. TBL_POINTER_NEW now holds 65190 and TBL_POINTER_OLD holds 65190. 410 is to added to TBL_POINTER_OLD and TBL_POINTER_OLD overflows to hold 64. Now, TBL_POINTER_NEW (which holds 64) is less than TBL_POINTER_OLD (which holds 65190) and the if condition is true and P1M1 bit of CCP1CON is inverted. This inverts the direction of the full-bridge drive. When P1A and P1D were being driven previously, P1B and P1C will be now be driven and vice versa. By inverting the direction of the full-bridge drive, we are carrying out the next half cycle with the same duty cycle values and sequence, but in the opposite direction – as is necessary (think AC waveform and opposite half cycle). This happens every (32*5 = 160) interrupts – when all the values of the table have each been called 5 times. Since TBL_POINTER_OLD then has a small value again, since it overflowed, TBL_POINTER_SHIFT will then be equal to 0, meaning that the table pointer has restarted from zero and the SPWM starts over again. So, TBL_POINTER_SHIFT, on subsequent interrupts has the values: 0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,………..30,30,30,30,30,31,31,31,31,31,0,0,0,0,0,1,1,1,1,1,……. And so on.
Now that I’ve explained how it all works (I have a hunch you haven’t fully grasped everything yet), let’s see how you can make necessary modifications to suit your purpose (and make sure you grasp it all properly).
Now let’s consider a situation where we use 20kHz instead of 16kHz, have 64 sine table values and a sine wave frequency of approximately 30Hz.
We would set the number of shifts to 10 instead of 11 so that the shifting operation results in a six-bit value: 26 = 64, since we have 64 sine table values.
For 20kHz frequency, the time period is 50us. 50us * 64 = 3200us (= 3.2ms). Time period for 40Hz is 25ms – half a cycle is thus 12.5ms. As calculated above, the entire calling of the sine table, if each value is called once, takes a total time of 3.2ms. That’s much less than the required 12.5ms and so, each sine table value should be called more than once. Calling each value four times means a total time of 12.8ms, which is close to 12.5ms (the required calculated time). So, each value is to be called four times. The frequency is (1/{0.0128*2})Hz = 39.1Hz – slightly off our target 40Hz.
Earlier, I had mentioned:
SET_FREQ = [216/{(Number of sine table values) * (Number of times each value is to be called)}]
So, in this case, it’ll be SET_FREQ = [216/{64*4}] = 256.
Now to verify this.
SET_FREQ = 256. 256* 3 = 768 (less than 210). 256 * 4 = 1024 (equal to 210). So, each 4 interrupts, the value of the sine table pointer will increase by 1.
So now we have:
SET_FREQ = 256;
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 10;
And that’s it. It’s not too difficult once you grab it. The main part of the interrupt is 7 lines only! And it's taken me 6 pages to explain it! And I hope I’ve helped you understand it clearly so now you can edit my code to your requirement or even write a new code from scratch! Let me know your comments and feedback! Happy coding!
Hi im Hema (PG scholar), for my project i am in need of 3 PWM channels.so i chose pic16f777a, but it is not available in proteus software. what shall i do?
ReplyDeleteplease help me .
DeleteHow i can use this code for pic16f88 ??
You can't use this for PIC16F88 because PIC16F88 does not have ECCP module. You will have to make large modifications and do without the ECCP module, relying heavily on software.
DeleteRegards,
Tahmid.
Hi hema,
DeleteIf PROTEUS simulation is a must, then you must change your microcontroller since, as you know, PIC16F777A is not available in PROTEUS.
Here are some microcontrollers that are available in PROTEUS and have 3x ECCP modules:
PIC18F6527
PIC18F6622
PIC18F6627
PIC18F6628
PIC18F6722
PIC18F6723
PIC18F8527
PIC18F8622
PIC18F8627
PIC18F8722
These dsPIC33 microcontrollers are available in PROTEUS have Motor Control modules that you can make use of (if you can use dsPIC33, I highly recommend them):
dsPIC33FJ12MC201
dsPIC33FJ12MC202
dsPIC33FJ16MC304
dsPIC33FJ32MC202
dsPIC33FJ32MC204
Hope this helps!
Regards,
Tahmid.
@ Anonymous,
ReplyDeleteI have written an article regarding the generation of sine wave without ECCP module - using only one CCP module. I have used PIC16F877A which has only CCP modules. Like PIC16F877A, PIC16F88 doesn't have any ECCP module. But PIC16F88 does have a CCP module which you can use to generate the sine wave using my program/method with slight modification as required to port it to PIC16F88.
View the article here:
Sine Wave Generation without ECCP - Using single CCP Module of PIC16F877A
http://tahmidmc.blogspot.com/2013/02/generation-of-sine-wave-without-eccp_16.html
Regards,
Tahmid.
thank you very much for your help
ReplyDeleteI'm glad to have helped.
DeleteI wish you success in your project!
Regards,
Tahmid.
Please where did u set the value of PR2 in the code. Aw do I make it work in proteus sim
ReplyDeleteI have set PR2 to 249 in the code.
DeleteRegards,
Tahmid.
I cant see any PR2 settings in the code and when I run the simulation, I dont see anything on the oscilloscope.
ReplyDeleteI have set PR2 to 249 in the code. Check the outputs at PIC pins P1A, P1B, P1C and P1D. Ensure that you have built the program successfully and that you have set the correct configuration settings.
DeleteIf you upload your Proteus file, I can take a look.
Regards,
Tahmid.
Hi Tahmid
ReplyDeleteIf I am corect set frq for 60Hz is 492
All rest is the same
I like to tray make 60Hz inverter
Yes, that's correct. SET_FREQ = 492 for 60Hz.
DeleteRegards,
Tahmid.
hi, tahmid how did it came out 492 for 60hz? whats the formula?
Deletehello sir i want v/hz ratio to be kept constant how can i use this code for controlling speed of 3-phase induction motor?
DeleteThanks Tahmid
ReplyDeleteI like to use PIC16F616 for it suply voltage 2-15v.
If you look at data for the chip you'll see that it has internal oscillator of 4MHz.
Please help
The supply voltage is up to 5V, not 15V. I'm sure you already know that and it was a typo on your part.
DeleteFor applications where timing is critical, it is better not to use the internal oscillator. Use an external crystal oscillator or similar. You'll (usually) get better accuracy, precision and lower drift with changing external factors, such as temperature, etc.
Regards,
Tahmid.
I am hoping to drive mosfets directly from PIC if posible .
ReplyDeleteMinimal part count sg3525 to drive ferrite transformer PIC to chop for 60Hz 120V for my windmill project.
Your help is great so far
Thanks.
DeleteUse a driver such as TC427 to drive the MOSFET directly from the PIC.
However, where possible, I recommend using dedicated PWM controllers such as SG3525 as they reduce program complexity and make control (using the PWM controller) rather simple.
I hope that answers your question.
Regards,
Tahmid.
This comment has been removed by the author.
ReplyDeleteSory PIC16HV616.
DeleteAs I can see it is the same as PIC16F684
Thanks for replaying
Hi Tahmid,
ReplyDeleteI am trying to make a sine wave inverter using dsPIC33FJ16GS504, please let me know the procedure of generating sine wave with this pic, what factors to consider and all.
Regards,
The factors to consider are, if not the same, similar. The difference will lie in the implementation.
DeleteRegards,
Tahmid.
Dear Tahmid
ReplyDeleteI've run your code: sine by PIC16F684. But the last place on the oscillators.
I want send Email to you, but I have not your email.
I send link (files : oxilo.JPG and invert.rar) : http://www.4shared.com/account/home.jsp#dir=z5tArTzu
Can you repair?
My email : mr.danghoangtung@gmail.com
Help me.
Thanks Tahmid
Bests Regard
Tung
Hi Tahmid,
ReplyDeletethanks for explaining the above but why cant the same result be gained by simply incrementing one variable and using it to point to the sine values sequentially then resetting that variable when it becomes equal to the number of values? I have loaded and understood your code and method but can't understand why this simpler method will not produce the same results. When I run my code in Proteus it only shows the middle few values/pulses then flat for the rest of the signal. Is the code "falling over it's self" because it's not using large numbers or could it be a fault in Proteus? Could really do with some advice on this as I can't find any obvious fault in my code. I'm waiting for an oscilloscope to be delivered (which I needed any way) so I can determine whether it is a fault in the simulation software but when I run your code it simulates fine.
Regards,
Dale
Do you mean to say that you're going to have all the values in the sine table and don't want to repeatedly call one value? But instead leave that to the sine table?
DeleteUpload what you've done so far. I'd like to take a look.
Regards,
Tahmid.
hi tahmid, can you show me how to generate code for multicarrier signal.For example, sine signal is compared with four carrier signals?
ReplyDeletehope you can help..
Why do you require comparing sine signal with four carrier signals? Why is the multicarrier signal approach required?
DeleteHello Tahmid,
ReplyDeleteI got error CMCON0 = 7 undeclared identifier when build to PIC16F690, Can I remove this without affecting operation of the given codes or function? seems build successful if I comment it out...
hope for your reply.
regards,
Remove that line and instead write:
DeleteCM1CON0 = 0;
CM2CON0 = 0;
The PIC16F690 has 2 analog comparators and thus the change is required. Consult the datasheet for further details.
Hope this helps!
Regards,
Tahmid.
sir can u help me to make a adjustable frequency just a switch from ports to change SET_FREQ = 492;
ReplyDeleteto 3 other set of frequencies?
The 3 frequencies will have three corresponding values of SET_FREQ. You will just need to change SET_FREQ to the required value to get your required frequency. The article here explains how to calculate the value of SET_FREQ for different frequencies. If you have any further questions, feel free to ask!
DeleteRegards,
Tahmid.
hi Tahmid, can i use sg3525/tl494 pwm for chopper transformer and after that i convert it to dc volt and then use your above h-bridge circuit for output as in china inverters or apc use????
ReplyDeletedesign become like this 12v -> chopper transformer -> 280v ac now convert it in 280v dc -> and convert in Ac for load dirctly on h-bridge ...
Yes you can do this. That's how high frequency inverters work.
DeleteRegards,
Tahmid.
sir please tell what will be the value of set frequency with 80 or 90 samples and frequency 50HZ
ReplyDeletePlease go through this article thoroughly. I've covered this in this tutorial. If, after reading, you have doubts or specific comments, feel free to ask.
DeleteRegards,
Tahmid.
Sir please can you let me know where the error is in my calculations for SET_Freq and PR2 because I am using a Quartz of 4MHz and wondering a switching signal of 20KHz and then controlling H-bridge which gives at the output 50Hz;for that I determined as follow the following values:
ReplyDelete1.PR2=((1/PWM_Period)/(1/Fosc)*4*1)-1 So I found:((1/20000Hz)/(1/4000000Hz)*4*1)-1)=49
2.SET_Freq=293; SET_FREQ = [65536/{(Number of sine table values) * (Number of times each value is to be called)}];I am using 32 values in the sine table and I saw that at 50Hz the period =20ms;its half is 10ms and then at 20KHz ,the period is 50us so;50us*32=1600us (=1.6ms) for completing a half cycle of 10ms calling 32 values each one has to be called 7 times;thus 1.6ms*7=11.2 approximately equals 10ms.
So SET_Freq=(65536/(32*7))=292.57 so I took SET_Freq=293.the problem I have is that my circuit at the pins of PIC I am not getting 50Hz but 14.76Hz;can you please tell me where I am wrong?Thanks for your helpful blogs.
slam bai i am awais from pakistan and i have assigned the project swmp with output uupto 380 volts plz tell me how can i use ir 2101 for mosfet driving and connection with ferrite core transformer i am using the tl 494 pwm controller
ReplyDeleteWhat is swmp? Did you mean SPWM?
DeleteDoes your output need to be adjustable?
Describe your specifications in greater detail.
Regards,
Tahmid.
thanks in advance brother reply plz
ReplyDeleteHi Tahmid
ReplyDeletecan i get variable frequency if i change SET_FREQ value continuously?
Yes, you can alter the frequency by altering the value of SET_FREQ.
DeleteRegards,
Tahmid.
Nice Post!! pretty informative..thanks for providing such a nice post.
ReplyDeleteChina Inverter
Hi Tahmid,
ReplyDeleteThat's excellent explanation of sine generation.
Could you please explain the feedback loop?
suppose we generate 230V from SPWM, how do we maintain the voltage on no-load to full-load condition?
Thanks in advance.
Thank you for the compliments.
DeleteWhat I did for feedback was use a "variable" sine table. Basically the sine table had a set of values for different duty cycles and loaded the required set of values depending on the output volatge and if it needed to be increased or decreased.
Take a look at this:
http://tahmidmc.blogspot.com/2012/11/feedback-in-sine-wave-inverter-pic16f.html
Regards,
Tahmid.
Hi Tahmid
ReplyDeleteI have generated a sinewave with a single PWM pin on a microcontroller.
Across the PWM pins(after AND gate) if i connect a RC filter, i get a good sinewave.
But now i connect this to an H bridge with driver(which is working from another inverter) i see lots of problems.
1)Cross conduction, even after adding 0 at both ends)
2)crooked sinewave
What could this be? Is it that, in the ISR updates are slower than overflow period of 62.5us?.Although my controller is running at 8MHz.
i checked that the ISR requires close to 37usec.How can the code run then?
Hello Tahmid great article
ReplyDeleteCan you write a tutorial to generate 3 Phase waves using similar method?
I have built the circuit but my transistors burnt at output.what do i do?
ReplyDeleteHello
ReplyDeleteI am trying the single phase LUT with different index pointers to generate a 3 phase PWM.
i use
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
and generate 3 PWMs at 0, 120deg and 240deg with differing indexes.
But i find that drives in same limbs cross conduct.
How is this normally done? can you please help me?
I have a 6-channel timer to generate a 16KHz PWM on all 6 channels
hello mr tahmid....can this program run for pic18F4431...i need to do project for 3 phase spwm to run induction motor...thank for ur advise mr tahmid...
ReplyDeleteCan you share me the full schematic of the system is not true sine inverter. I needed it. You send her into luankdt01@gmail.com address. Thank you very much.
ReplyDeleteHi tahimid,
ReplyDeleteI am doing my mtech thesis on transformerless inverter for pv system. I am planning to use PIC for generating PWN signals (SPWM method). Since I am a beginner can you give me instructions to start...
hi Tahmid, i'm doing a project about modulation & demodulation ASK signal use pic 16f887.In demodulation circuit, i use ADC of pic to decoder the original signal (the original signal is a char 8 bit EX:''10101010 '') but i can't do it. Can you help me? Thank you so much!
ReplyDeleteI actually added your blog to my favorites and will look forward for more updates. Great Job, Keep it up.
ReplyDeleteHi
ReplyDeleteWhat happens when you have like this: a 1024 point sine table for [0..pi/2] you want 50 Hz for output frequency and have a PWM frequency of 1500 Hz? I get that the total time would be larger then even the 20ms period
Thanks in advanced
John
Hello,
ReplyDeleteHave made several attempts to implement this code using a PIC18F4550 but did not get any satisfactory result (I have no experience with the MikroC compiler). You could edit the code to use this pic, compile and send to me the files on it (design. mcppi and. hex)?
Thanks in advance!
Lenilson
Hi
ReplyDeleteI have to generate SPWM for 3 phase inverter .But with Your logic the number of sine values should always be 2 raised to some value then how will I be able to generate 120 degree out of phase signals?Please do reply
Hello Tamihd:
ReplyDeleteI know as mikroC program so I can not fully understand the whole development given here:
1 Tomas 32 values (sine table with PR2 + 1 = 249 and Tpwm= 62.5 us)
2 The half cycle of the sine wave of 50 Hz is 10 ms
Then these data values must have 160 (10ms / 62.5 us) but there are only 32 values. This means that the 32 values are repeated 5 times in the 10 ms
Question 1 Since no representing the repetitive values in each of the true value of energy stored in each of them, it does not distort the output sine wave output filter requiring a larger LC ?.
Question 2: To design the ferrite transformer which is the frequency used ?.
Question 3 could rethink this development considering the 160 values within 10 ms and stop using pointers?.
José
hello Tahmid ,
ReplyDeleteyour articles are really helpful.I have a doubt .
how does the implementation of Spwm in practically differ from that of silmulations??
1)If i want to change the number of pulses per half cycle in SPWM say around 12 or 30 and my reference signal is 50Hz sine, then the pwm frequency comes around in Hz and for this the value of PR register exceeds the max value it can hold of 256.how to deal with this
2)Also Another doubt is that should the sine table values be taken according to the number of output pulses we can need
(generation and implementation of sine table)
3)how to use Timer interrupts to send the value as many times as we want to make sure that the output frequency is 50hz
This comment has been removed by the author.
ReplyDeleteTahmid: I can generate SPWM code for 60 Hz using a PIC16F874 but I cannot generate any code outside of the ISR. Does this interupt program use all the processor time or do I have something wrong in my interupt?
ReplyDeleteHi Tahmid,
ReplyDeleteI build this inventor on H bridge povered on 325VDC, I have one question is normal output after LC filtering not sine wave, but square wave ? Once connected to the load in output, output is sine wave it is normally ?
Hello Tahmid,
ReplyDeleteI combined a pic16F690 + a hip4081 + a brigde made of 4 irfp064's + 4 extra super fast shotkey's protect the bridge ( i know the fets have their own shotkeys already inside the package ) but it's just to be sure they can handle the generated currents. The mos gate's are protected by 15v zeners to prevent overvoltage ( with is normally not needed in a 12V system but you never know ...) I adjusted the original code as you explained above to shut down the CM1CON0 and the CM2CON0. The problem. It doesn't work and i do not have a scope to look at the generated signals. However: my multimeter does measure frequency and pwm duty, so i can see the 50hz low side drive signals and the 7 - 8 khz high side signals. So the code does work and the chip is programmed as it should. But that's all i can see with inferiour measurement equipment. Strange thing is that the 4081 ( unlike the 4080) wants his input tied to ground to be enabled. ( i tested the setup with 2 leds and just some wires ) So my guess was that the 4081 inverts the pwm input from the pic and thus 0 commes out as 255 and vice verca. Witch would generate a mirrored sine. I could have inverted the pwm with a cd4*** not gate but that requires yet another chip. If you use a processor to do the job i think that is just a very stupid plan. So if the driver inverts the signal i should just invert the pwm values before i feed it to the driver stage to get the correct pwm at the output. So i inverted your list ( 255, 230,206, ... ) and i puched that into the driver stage. But than again it refused to work like it shoud. I placed 2 leds into the bridge to visualy look at what is happening inside. What is see is that the leds are not blinking very equaly and in a kind of semi random from of way. But like i said i don't have a scope to look at what is really happening inside the bridge. I may have overlooked something but i don't see where that could be? Can you make a guess what i could try to make it work? I feel stupid to ask this but maybe you have an obvious sollution that i just dont see for the moment ... I'm not that familiar with pic's and i plan to move your code inside a 8051 type of micro. Witch i understand much better than pic's. But to start with i would like to see your setup work before i move it to my micro of choise ...
Kind Regards,
Tom
hi , Thanks for your helpful post, but please from what you know that the maximum ECCP frequency is 20 Khz , please help because i thik it 's more than 200 Khz
ReplyDeleteHi Tamhid:
ReplyDeleteCan you tell me about the filter you used for producing pure AC wave from SPWM.
Hi Tamhid:
ReplyDeleteCan you tell me about the filter you used for producing pure AC wave from SPWM.
Is this circuit applicable for inverting 12 volt dc voltage to 220 volt ac voltage.
ReplyDeletemr tahmid may ive ur email plz?
ReplyDelete//----------------------------------------------------------------------------------------
ReplyDelete//Programmer: Syed Tahmid Mahbub
//Target Microcontroller: PIC16F684
//Compiler: mikroC PRO for PIC (Can easily port to any other compiler)
//-----------------------------------------------------------------------------------------
unsigned char sin_table[32]={0,25,49,73,96,118,137,
159,177,193,208,220,231,239,245,249,250,249,245,
239,231,220,208,193,177,159,137,118,96,73,49,25};
unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int TBL_temp;
unsigned char DUTY_CYCLE;
void interrupt(){
if (TMR2IF_bit == 1){
TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;
if (TBL_POINTER_NEW < TBL_POINTER_OLD){
CCP1CON.P1M1 = ~CCP1CON.P1M1; //Reverse direction of full-bridge
}
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
DUTY_CYCLE = TBL_POINTER_SHIFT;
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;
ANSEL = 0; //Disable ADC
CMCON0 = 7; //Disable Comparator
PR2 = 249;
TRISC = 0x3F;
CCP1CON = 0x4C;
TMR2IF_bit = 0;
T2CON = 4; //TMR2 on, prescaler and postscaler 1:1
while (TMR2IF_bit == 0);
TMR2IF_bit = 0;
TRISC = 0;
TMR2IE_bit = 1;
GIE_bit = 1;
PEIE_bit = 1;
while(1);
}
//-------------------------------------------------------------------------------------
HEX MEIN KOI CNVERT KR DE
PLZZ
FRIENDZZZZZZZZZZZZZZ
Thanks for a wonderful post....spwm waveforms are generated...but I have not been able to debug your code...please help.
ReplyDeleteTahmid what are the frequencies of P1A,P1B to P1D For 50hz frequency
ReplyDeletenever Mind Answering..... for the BENEFIT OF OTHERS....P1A AND P1C on an Oscilloscope shows 50hz....P1B AND P1D show roughly 16khz..... but you'd see a varying duty cycle..... Regards.
ReplyDeleteHow to exactly match inverter frequency to grid in grid tied application? Any one?
ReplyDeletehi Tahmid ,tanks a lot
ReplyDeleteWhat is the equivalent of registers PR2 and CCPR1L in micro controller avr?
Can this program be used for 3 phase inverter, with 6 igbts....how?
ReplyDeleteHi Tahmid. Your articles are really great.
ReplyDeleteIdonot know why i obtain a sine wave amplitude of 6V on my oscilloscope in proteus after supplying my H-bridge with 12V.
Hi Tamid,
ReplyDeleteI've build a H-bridge circuit in Proteus but it shown some error when I run the simulation but I couldn't find out which part did I built wrng.
The error states that "Time step too small" and "problem node #v:q4:f1#branch" but my circuit does not have this branch.
ReplyDeleteHi Tahmid, very illustrative examples, how can I do if I have a bipolar power source (+) & (-) in the hv side? should I connect the (-) to common earth in order to have a same circuit reference?
ReplyDeletehello sir its that pure sine wave? thank you
ReplyDeleteHello Tahmid ,
ReplyDeleteCan you please tell your email id ??
Hello Tahmid ,
ReplyDeletewhat about pic 12f683 is it good for this code or pic 16f684 is better and can i use the same code for both ?
thanks alot sir Tahmid
I'm just wondering since you are using the ECCP mode (Full Bridge Forward and Reverse) and looking at the data sheets, at these modes only on pin is modulated(PWM) and the other is ACTIVE HIGH. According to what I know both pins should be modulated? How's that? Thank you!!
ReplyDeleteHello Tamid, please I need ur assistance.
ReplyDeleteHi, Your post about sine wave inverter using PIC was a great help. Can you please explain feedback mechanism in sine wave inverter using dsPIC30F/dsPIC30F.
ReplyDeleteHi Tahmid, i´m from Brasil!
ReplyDeleteIm working in your project in a half-bridge inverter, and a can`t undesrtand how to communicate the PWM to IR2112 and mosfets. The pins RC3/RC5 from uc goes to LIN/HN to control low an hi components, right? And how the PWM is connected into de mosfets?
Could you help-me?
Thank you.
hi tahmid .
ReplyDeleteis this code full? if not, May you send my mail?
ALLAH bless you
Hello Sir,
ReplyDeleteWitch controller use for 55khz sine wave generator using SPWM....
Great work keep it up
ReplyDeleteCan I do this with at89s52 and how should I proceed
Thanks
hi can you say whether IR2110 is suitable for 80khz pulses to drive the mosfet.if it no so ,tell me the better choice
ReplyDeleteIt is very suitable. You can crosscheck from the datasheet
DeleteHello sir I'm new in this blog and appreciate your circuit thank for helping people in this blog please I been searching for a circuit to contact with my old inverter board the second stage to produce out put A/C 220v it chopper inverter please can you help me or design me with microcontroller thank you hope to hear from you soon
ReplyDeleteHello sir I'm new in this blog and appreciate your circuit thank for helping people in this blog please I been searching for a circuit to contact with my old inverter board the second stage to produce out put A/C 220v it chopper inverter please can you help me or design me with microcontroller thank you hope to hear from you soon
ReplyDeleteHi Thanks for your Tutorial on Sine wave Invertor...
ReplyDeletei have 1Kva (ferrite core Transformer) invertor, i wrote a program 220V 50Hz AC. its show 220V AC and 50Hz on multi meter but when i plug a 50Watt bulb on invertor voltage drop upto 60V.
Original program working properly. if you have any suggestion please send.
using micro controller : PIC16F716
Thnaks
Help code in pic12f683
ReplyDeletePlease can you share the hex file in a file formats not in a written so that I can easily upload it I will be very glad since am a novice in programming.
ReplyDeleteHow to calculate this sine table for 25Khz instead of 50Hz?
ReplyDeletehi thamid,where is the feedback cirquit in this project? thank you..
ReplyDeleteHi thamid Thanks for the Article please clarify the controller Atinny44A its better suitable this code and i need additional feature for Shutdown pin for any bridge error. Please guide me how to modify this program if possible please mail me : infovengu@gmail.com
ReplyDelete