Sine Wave Problem

Thread Starter

krlngc

Joined Dec 9, 2013
11
Hello,

I'm trying to generate a sine wave that oscillates between 0V-5V at 1Hz with P12F683. So far, without paying attention to the offset I could form the wave. It's a nice sinusoidal wave. I take 50 samples for each period. I use 5 times 4ms PWM for each sample and then Timer2 interrupts; then I fetch the next sample's duty cycle from the look-up table.

However, I can't make the wave swing around 2.5V. The problem is that for 2.5V offset, some values of the look-up table goes beyond 255 which prevents me from setting CCPR1L's value directly from look-up array. So , for every value that is greater than 255, I thought designating 2 LSBs to CCP1CON.DC1B bits and 7 MSBs to CCPR1L register by doing bit shift operations would solve the problem. But it's not working well. And I can't spot the problem. I'd be grateful if you could share your opinions.

Kind Regards,
Kırlangıç


Here's the code;
Rich (BB code):
#include <pic.h>
#include <xc.h>
#include<stdlib.h>
#pragma config FOSC = INTOSCIO, MCLRE = OFF, WDTE = OFF
#define XTAL_FREQ = 4000000

void InitPWM();

char sinval[50]={0, 31, 62, 92, 120, 147, 171, 193, 211, 226, 238, 246, 
250, 250, 246, 238, 226, 211, 193, 171, 147, 120, 92, 62, 31, 0, -31,
 -62, -92, -120, -147, -171, -193, -211, -226, -238, -246, -250, -250,
 -246, -238, -226, -211, -193, -171, -147, -120, -92, -62, -31};


int flag = 0;
int index=0;

int main(int argc, char** argv)
{
InitPWM();

while(1)
{
if(flag==5)
{
  unsigned int y_value= sinval[index]+250;      //250 added due to char's limit
   
   if(y_value>255)
    {
    int index_CCPR1L=y_value>>2;          //get 7 MSB
   int index_CCP1CON=y_value<<7;         
   CCPR1L = index_CCPR1L;                //designate MSB's to CCPR1L
   CCP1CONbits.DC1B =index_CCP1CON>>7;   //designate 2 LSBs to CCP1CONbits.DC1B
   }
    else
    {
    CCPR1L=y_value;
     }
    index++;
   
 if(index==50)
     {index=0;
     CCPR1L=index_CCPR1L;
     CCP1CON =index_CCP1CON>>7;
    }
    flag=0;
}
}
return(EXIT_SUCCESS);
}

void InitPWM()
{
    OSCCONbits.SCS=1;           //Internal oscillator is used for system clock
    OSCCONbits.IRCF=0b110;      // Internal Oscillator Frequency 4 MHz
    CCPR1L=0b00000000;           // Duty Cylce %0
    CCP1CON=0b00001100;          // bit3-0 PWM Mode
    TRISIO2=0;                   // CCP1 output
    PR2=0b11111001;              // 4 ms = (PR +1) *4 * 250ns * TMR2 Prescale value
    T2CON=0b00000111;            // Timer2 is on , Prescale 1:16
    PIE1bits.TMR2IE=1;           // Enable TMR2 PR2 match
    INTCONbits.PEIE=1;           // Enable Peripherial Interrupt
    INTCONbits.GIE=1;            // Enable Global Interrupt
}

void interrupt Interrupt()
{
if (TMR2IF)
{
    flag++;
    TMR2IF=0;
}
}
 

ErnieM

Joined Apr 24, 2011
8,041
The first problem is your array: you just can't cram 9 bits into an 8 bit quantity, that being your char array. -31 looks identical to 225 when you take the sign bit into account.

You have two choices: cut your data precision in half by storing 1/2 the value and doubling it, or make an array of integers.
Once you have proper input numbers, load them into the PWM period registers like so:
Rich (BB code):
   CCP1CONbits.DC1B = value & 0b11 // least sig 2 bits
   CCPR1L = value >> 2;                 // least sig 2 bits
 
Top