Continue to Site

# Generation of sine wave using SPWM in PIC16F684

• 2 min read
I have previously shown how to calculate the values for the sine table. Now I will show you how to use that sine table for generating a sine wave using a PIC16F684. Why PIC16F684? It is a nice little 14-pin PIC that contains all that is needed for SPWM (sinusoidal pulse width modulation) – the ECCP module. Since the ADC or comparator or other peripherals are not used and there are enough pins, I selected the PIC16F684.

You can find the tutorial here: https://tahmidmc.blogspot.com/2011/01/generation-and-implementation-of-sine.html

Let’s run the 16F684 from a 16MHz crystal oscillator and use a 16kHz switching frequency.
So, the required value of PR2 is 249.

The sine table (for half a cycle) is:
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
________________________________________________________________________________________________________________________________
Here is the code:

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
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);
}
________________________________________________________________________________________________________________________________

https://www.4shared.com/file/PlETv7nt/SPWM684.html
https://rapidshare.com/files/3811707712/SPWM684.hex

To make the process of updating sine table value simple, table pointer was used. The frequency here is set to 50Hz and the switching frequency is 16kHz. The 16F684 generates SPWM signals on P1A, P1B, P1C and P1D pins which should then be connected to a full-bridge stage for feeding into transformer.

16kHz frequency is used since it is toward the end of the audible spectrum and so the noise emitted will not be intolerable. Frequency above 20kHz is not used as 20kHz is the maximum frequency for the ECCP module of 16F684.

Since the ECCP module and interrupt take care of the SPWM, it is being executed by the hardware modules. So, while these are running, you can do other stuff as well by coding them in the while(1) loop, which, as you can see, is blank now, since no other task is being carried out besides SPWM.

Generating the sine table:

The SPWM signals:

The generated sine wave:

Tahmid your table has 32 values so to make 16kHz each value is to be repeated 5 times which portion of the code is used to repeat the values please explain. You know I dont use c ,when I made my code because of this I used a long table in JAL

It's this part:
Code:
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;

Tahmid what does the code below actually do particularly that two geater than symbols
Code:
TBL_POINTER_NEW >> 11;

Hi Tahmid,
pls. tell me what does these code do? pls. explain T1IF_bit=0;

adder = FB_Step << 5;
TMR1L = 0;
TMR1H = 0;
T1IF_bit = 0;

I took half the sine since I used it for 10ms and just repeated it for the next 10ms. I change the direction of the bridge each 10ms which is half the time period of my 50Hz sine wave. Since it's half the period, I generate half the cycle.

The sine table starts from zero. You can search online. That's the technique widely used everywhere. You can go through my tutorial:
http://tahmidmc.blogspot.com/2011/01/generation-and-implementation-of-sine.html

@picgak,

>> means bit-shift right.

I use that line specifically to retrieve the 5-bit value from the 16-bit register. Why 5-bit? Because 2^5 = 32. And my sine table uses 32 values.

@siktec,

<< means bit-shift left.

So << 5 is equivalent to multiplying by 32. But it's much quicker than multiplying as the PIC I used - PIC16F684 - doesn't have hardware multiplication capacity.

hi Tahmid,
if i use another micro controller like pic16f886 instead of pic16f684 that you use, will the code you provided work?

You can use the code for PIC microcontrollers that have at least one ECCP module. Make sure you change pins, PIC-specific registers, etc.

can you give complete code for the inverter with feedback control. i have tried the code you provided its only reading one table it does not move the next.

please explain the function of : SET_FREQ = 410;

siktec;bt2273 said:
can you give complete code for the inverter with feedback control. i have tried the code you provided its only reading one table it does not move the next.
Can you please help us with the code mr Tahmid?

Dear Tahmid,

Please let me know that how to combine SPWM signal to make pure sinewave?

Hello Tahmid ,how can I generate another frquency like 10KHz which I can use to command my H_Bridge.

siktec;bt2273 said:
can you give complete code for the inverter with feedback control. i have tried the code you provided its only reading one table it does not move the next.

Did you implement the hardware properly?

imranahmed;bt2335 said:
Dear Tahmid,

Please let me know that how to combine SPWM signal to make pure sinewave?

You need to use the SPWM signals to drive a full-bridge converter. At the output of the converter, you need to use an LC filter.

hello Tahmid,I used a PIC16F1827 it has an ECCP module,I want to generate an SPWM signal can you please help me to modify the codes conveniently so I can get the propoer output.
I want to control my MOSFET H-Bridge with 16KHZ,I am using a quartz of 12MHZ;the formula you are using for getting those SET_FREQ value and the Sine_Table values I am not getting it well.

Here I posted the codes I modified for getting SPMW signal on
P1A:RB3
P1B:RB5
P1C:RB6
P1D:RB7

The codes are here:
PHP:
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 = 512;
TBL_POINTER_SHIFT = 0;
TBL_POINTER_NEW = 0;
TBL_POINTER_OLD = 0;
DUTY_CYCLE = 0;
PR2=187; ///for 16Khz at 12MHZ of quartz
TRISB=0x00;
CCP1CON=0x4D;  //Configuration for PWM out on P1A,P1B,P1C,P1D
TMR2IF_bit = 0;
T2CON = 4; //TMR2 on, prescaler and postscaler 1:1
while (TMR2IF_bit == 0);
TMR2IF_bit = 0;
TRISB=0;
TMR2IE_bit = 1;
GIE_bit = 1;
PEIE_bit = 1;

while(1);
}

I did whatever I can but I am not coming to the good result,I don't have output on those pins.

When I take measurements on those output pins I get a VCC output where I was supposed to get an PWM signal.

Thanks.

Author
Tahmid