Sine Wave Problem

Discussion in 'Embedded Systems and Microcontrollers' started by krlngc, Jun 24, 2014.

  1. krlngc

    Thread Starter New Member

    Dec 9, 2013
    11
    0
    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;
    Code ( (Unknown Language)):
    1.  
    2.  
    3. #include <pic.h>
    4. #include <xc.h>
    5. #include<stdlib.h>
    6. #pragma config FOSC = INTOSCIO, MCLRE = OFF, WDTE = OFF
    7. #define XTAL_FREQ = 4000000
    8.  
    9. void InitPWM();
    10.  
    11. char sinval[50]={0, 31, 62, 92, 120, 147, 171, 193, 211, 226, 238, 246,
    12. 250, 250, 246, 238, 226, 211, 193, 171, 147, 120, 92, 62, 31, 0, -31,
    13.  -62, -92, -120, -147, -171, -193, -211, -226, -238, -246, -250, -250,
    14.  -246, -238, -226, -211, -193, -171, -147, -120, -92, -62, -31};
    15.  
    16.  
    17. int flag = 0;
    18. int index=0;
    19.  
    20. int main(int argc, char** argv)
    21. {
    22. InitPWM();
    23.  
    24. while(1)
    25. {
    26. if(flag==5)
    27. {
    28.   unsigned int y_value= sinval[index]+250;      //250 added due to char's limit
    29.    
    30.    if(y_value>255)
    31.     {
    32.     int index_CCPR1L=y_value>>2;          //get 7 MSB
    33.    int index_CCP1CON=y_value<<7;        
    34.    CCPR1L = index_CCPR1L;                //designate MSB's to CCPR1L
    35.    CCP1CONbits.DC1B =index_CCP1CON>>7;   //designate 2 LSBs to CCP1CONbits.DC1B
    36.    }
    37.     else
    38.     {
    39.     CCPR1L=y_value;
    40.      }
    41.     index++;
    42.    
    43.  if(index==50)
    44.      {index=0;
    45.      CCPR1L=index_CCPR1L;
    46.      CCP1CON =index_CCP1CON>>7;
    47.     }
    48.     flag=0;
    49. }
    50. }
    51. return(EXIT_SUCCESS);
    52. }
    53.  
    54. void InitPWM()
    55. {
    56.     OSCCONbits.SCS=1;           //Internal oscillator is used for system clock
    57.     OSCCONbits.IRCF=0b110;      // Internal Oscillator Frequency 4 MHz
    58.     CCPR1L=0b00000000;           // Duty Cylce %0
    59.     CCP1CON=0b00001100;          // bit3-0 PWM Mode
    60.     TRISIO2=0;                   // CCP1 output
    61.     PR2=0b11111001;              // 4 ms = (PR +1) *4 * 250ns * TMR2 Prescale value
    62.     T2CON=0b00000111;            // Timer2 is on , Prescale 1:16
    63.     PIE1bits.TMR2IE=1;           // Enable TMR2 PR2 match
    64.     INTCONbits.PEIE=1;           // Enable Peripherial Interrupt
    65.     INTCONbits.GIE=1;            // Enable Global Interrupt
    66. }
    67.  
    68. void interrupt Interrupt()
    69. {
    70. if (TMR2IF)
    71. {
    72.     flag++;
    73.     TMR2IF=0;
    74. }
    75. }
    76.  
    77.  
    78.  
     
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,394
    1,606
    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:
    Code ( (Unknown Language)):
    1.  
    2.    CCP1CONbits.DC1B = value & 0b11 // least sig 2 bits
    3.    CCPR1L = value >> 2;                 // least sig 2 bits
    4.  
     
  3. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    This page;
    http://www.romanblack.com/onesec/Sine1kHz.htm

    has a 50 entry sine table, that is also 2nd harmonic compensated so it removes the 2nd harmonic distortion caused by using the PWM module.

    [​IMG]

    The C source code in the linked ZIP file on that page has the sine table, and PWM code etc.
    :)
     
Loading...