Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

SPWM using PIC16F628A CCP Pin problem

Status
Not open for further replies.
Hello everyone. I am building a sinewave inverter. I am copying a program from the web. I have PORTED it for Hi-tech Compiler and PIC 628. I tested the pins on DSO. But the results are not satisfying coz I get gating signals on the Pins but not getting the SPWM signals on RB3 pin. What I get two pulses of same width after a very long DISTANCE. I cud not measure the freqncy. These are my assmptions:
PWM freq= 5Khz, Osc= 20Mhz. I want the sinewave of 50 Hz output.
So PR2= 999; SET_FREQ= 1311 (2^16/no. values in sine table ) As the Author SAID.
I have also done some Modifications like mult to make the REMAINED value ie 14 zero after every half cycle.
I don't know you are getting me or not but I hope u will certainly help me. Program is as below:-

//Programmer: Pravin Gosavi
//---------------------------------------------------------------
#include<htc.h>
#define _XTAL_FREQ 20000000UL
unsigned char sin_table[50]={ 0 , 8 , 24 , 46 , 76 , 114 , 156 , 206 , 258 ,
314 , 374 , 436 , 500 ,562 , 624 , 684 , 740 , 792 , 842 , 884 ,
922 , 952 , 974 , 990 , 998 , 998 , 990 , 974 , 952 ,922 , 884 ,
842 , 792 , 740 , 684 , 624 , 562 , 500 , 436 , 374 , 314 , 258 ,
206 , 156 , 114 ,76 , 46 , 24 , 8 , 0};
unsigned int TBL_POINTER_NEW,
TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int TBL_temp;
unsigned char DUTY_CYCLE, mult;

unsigned char Direction;

void interrupt isr ()
{
if (TMR2IF == 1)

{
TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;

if (TBL_POINTER_NEW < TBL_POINTER_OLD)
{
if (Direction == 0)
{
PORTBbits.RB1 = 0; //A
PORTBbits.RB7 = 0; //D
PORTBbits.RB5 = 1; //B
PORTBbits.RB6 = 1; //C
Direction = 1;
}

else
{
PORTBbits.RB5 = 0; //B
PORTBbits.RB6 = 0; //C
PORTBbits.RB1 = 1; //A
PORTBbits.RB7 = 1; //D
Direction = 0;
}
mult =0;
}

TBL_POINTER_SHIFT = TBL_POINTER_NEW%1311;
DUTY_CYCLE = TBL_POINTER_SHIFT;
CCPR1L = sin_table[DUTY_CYCLE];
TBL_POINTER_OLD = TBL_POINTER_NEW*mult;
mult=1;

TMR2IF = 0; //finally set intrpt flag zero

}

} //interupt end

void main()
{
CMCON=0X07;
TRISA = 0;
SET_FREQ = 1311; //65536/(no of values in sine table)
PORTB = 0;
TRISB = 0;

PR2 = 999; // 5kHz
CCPR1L = 0;
CCP1CON = 12;//PWM mode

TRISB = 0xFF;
TMR2IF = 0;
T2CON = 0x04; //---------------TMR2 on

while (TMR2IF == 0);
TMR2IF = 0; //Clear TMR2IF
PORTB = 0;
TRISB = 0;

// Enable Timer 2 interrupt, global interrupt and peripheral interrupt
TMR2IE = 1;
GIE = 1;
PEIE = 1;

while (1)
{
PORTAbits.RA1=0;
PORTAbits.RA1=1;
__delay_ms(3);
PORTAbits.RA1=0;
__delay_ms(5);
PORTAbits.RA1=1;
__delay_ms(3);
PORTAbits.RA1=0;
__delay_ms(100);

}
}


Thanks.
 
There is major issues with timing... You interrupt has an average of 48uS run time... With your timer set to 1:1 it times out at 51uS... All that's ever happening is interrupt...

You do realize that the PWM also uses timer2??
 
Yeah timer 2 is used to create an Interrupt.
And also I realised Timer 2 is 8-bit timer. And can count upto 255. But I have used 65536.
I m really cnfusd betn all these.
Please can u explain more how this works?
 
Whooah!!

Quite a few issues here...

Timer2 has a 1:1 prescale... PR2 = 999??? PR2 is an 8 bit register

For a 5khz signal..

T2CON = 5;
PR2 = 255;

Your sine table is an unsigned character table yet you have 10 bit values in..

I recommend using the code as is but making the sine out 8 bit..

C:
unsigned char sin_table[50]={ 0 , 2 , 6 , 13 , 19 , 28 ,39 , 52 , 64 ,
   78 , 93 , 109 , 125 ,140 , 156 , 171 , 185 , 198 , 211 , 221 ,
   230 , 238 , 243 , 252 , 254 , 254 ,252 ,243 , 238 ,230 , 221 ,
   210 , 198 , 185 , 171 ,156 , 140 , 125 , 109 , 93 , 78 , 64 ,
   52 , 39 , 28,19 , 13 , 6 , 2 , 0};

To get it working I just used DUTY_CYCLE as an incrementing value 0~49 to see the sine
I used a 100 ohm 10uH and a1uF filter to get the sine output....

The last issue was the sine table selection... you increase the frequency by 1311 but the only use the modulus of 1311??

so DUTY_CYCLE will always contain 0... The correct way is to divide by 1311 to get a table position..

Hopefully this will get you started

C:
//Programmer: Pravin Gosavi
//---------------------------------------------------------------
#include<htc.h>
#define _XTAL_FREQ 20000000UL
unsigned char sin_table[50]={ 0 , 2 , 6 , 13 , 19 , 28 ,39 , 52 , 64 ,
78 , 93 , 109 , 125 ,140 , 156 , 171 , 185 , 198 , 211 , 221 ,
230 , 238 , 243 , 252 , 254 , 254 ,252 ,243 , 238 ,230 , 221 ,
210 , 198 , 185 , 171 ,156 , 140 , 125 , 109 , 93 , 78 , 64 ,
52 , 39 , 28,19 , 13 , 6 , 2 , 0};
unsigned int TBL_POINTER_NEW,
TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int TBL_temp;
unsigned char DUTY_CYCLE, mult;

unsigned char Direction;

void interrupt isr ()
{
if (TMR2IF == 1)

{
TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;

if (TBL_POINTER_NEW < TBL_POINTER_OLD)
{
if (Direction == 0)
{
PORTBbits.RB1 = 0; //A
PORTBbits.RB7 = 0; //D
PORTBbits.RB5 = 1; //B
PORTBbits.RB6 = 1; //C
Direction = 1;
}

else
{
PORTBbits.RB5 = 0; //B
PORTBbits.RB6 = 0; //C
PORTBbits.RB1 = 1; //A
PORTBbits.RB7 = 1; //D
Direction = 0;
}
mult =0;
}

TBL_POINTER_SHIFT = TBL_POINTER_NEW/1311;
if(DUTY_CYCLE++ >48)
   DUTY_CYCLE = 0; //= TBL_POINTER_SHIFT; // <<<<YOU NEED TO CHANGE THIS
CCPR1L = sin_table[DUTY_CYCLE];
TBL_POINTER_OLD = TBL_POINTER_NEW*mult;
mult=1;

TMR2IF = 0; //finally set intrpt flag zero

}

} //interupt end

void main()
{
CMCON=0X07;
TRISA = 0;
SET_FREQ = 1311; //65536/(no of values in sine table)
PORTB = 0;
TRISB = 0;

PR2 = 255; // 5kHz
CCPR1L = 0;
CCP1CON = 12;//PWM mode

TRISB = 0xFF;
TMR2IF = 0;
T2CON = 0x05; //---------------TMR2 on

while (TMR2IF == 0);
TMR2IF = 0; //Clear TMR2IF
PORTB = 0;
TRISB = 0;

// Enable Timer 2 interrupt, global interrupt and peripheral interrupt
TMR2IE = 1;
GIE = 1;
PEIE = 1;

while (1)
   {
   PORTAbits.RA1=0;
   PORTAbits.RA1=1;
   __delay_ms(3);
   PORTAbits.RA1=0;
   __delay_ms(5);
   PORTAbits.RA1=1;
   __delay_ms(3);
   PORTAbits.RA1=0;
   __delay_ms(100);

   }
}
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top