CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Measure Duty Cycle of 22kHz PWM

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jmb1539



Joined: 29 Mar 2010
Posts: 11

View user's profile Send private message

Measure Duty Cycle of 22kHz PWM
PostPosted: Sat Apr 30, 2011 9:56 am     Reply with quote

I am attempting to cature the "on-time" pulse width of a 22kHz PWM signal. The duty cycles are between 5% and 25% so i would need an RE interrupt and then 2.27usec later have a FE interrupt. This would correspond to a 5% duty cycle. I'm using the CCP1 for the RE, and the CCP2 for the FE. Are these parameters too fast for my PIC18F2620 (20MHz XTAL) to handle and perform other functions (such as toggling an output pin at 3.0kHz to 3.8kHz depending on the duty cycle of the incoming PWM?

Code:

#INCLUDE <18f2620.h>
#DEVICE  HIGH_INTS=TRUE
#DEVICE  ICD=TRUE

#INLINE

#INCLUDE <stdio.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPROTECT                //Code not protected from reading
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES NOBROWNOUT               //No brownout reset
#FUSES PUT                      //Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES DEBUG                    //Debug mode for use with ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PBADEN                   //PORTB pins are configured as analog input channels on RESET
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES MCLR                     //Master Clear pin enabled

#USE delay(clock=20MHZ)
#USE rs232(STREAM=TEST, BAUD=19200, DEBUGGER)

#USE fast_io(A)
#USE fast_io(B)
#USE fast_io(C)

#PRIORITY   ccp1, ccp2  //, timer1

///////////////////////////////////////////////////////////////////////////////
// Register Definitions
///////////////////////////////////////////////////////////////////////////////

// CCP Registers

#BYTE PIR1 = 0xF9E          // define interrupt address and bits
#BIT  TMR1IF = PIR1.0
#BIT  CCP1IF = PIR1.2
#BYTE PIR2 = 0xFA1
#BIT  CCP2IF = PIR2.0

///////////////////////////////////////////////////////////////////////////////
// PIN Definitions
///////////////////////////////////////////////////////////////////////////////

// Port A Definition

#DEFINE  MUXCNTRL    PIN_A0
#DEFINE  OUTTESTFREQ PIN_A1
#DEFINE  OUTFREQPIN1 PIN_A2
#DEFINE  OUTFREQPIN2 PIN_A3

///////////////////////////////////////////////////////////////////////////////
// Constants
///////////////////////////////////////////////////////////////////////////////

// Data Constants

#DEFINE  T0INTCNTS   2           // # of timer0 overflows to produce freq range
#DEFINE  T0INTCNTSD2 1        // Counter for 90 degree phase shift
#DEFINE  TESTFREQ    15060       // # of timer0 overflows to produce 1Hz status

#DEFINE  DC25INTNO   122         // Duty Cycle of 25% --> Out Freq of 3800 Hz
#DEFINE  DC20INTNO   110         //               20%                 3600 Hz
#DEFINE  DC15INTNO   98          //               15%                 3400 Hz
#DEFINE  DC10INTNO   84          //               10%                 3200 Hz
#DEFINE  DC05INTNO   70          //               05%                 3000 Hz
                                 // After divided down by flip flop

////////////////////////////////////////////////////////////////////////////////
// Global Variables
////////////////////////////////////////////////////////////////////////////////

int1  outTogla=0;             // State of leading out freq
int1  outToglb=0;             // State of lagging out freq
int1  outToglc=0;             // State of test freq
int1  gotCCP1=FALSE;          // CCP1 interrupt received
int1  flag1=TRUE;             // flag to update outfreq1
int1  flag2=TRUE;             // flag to update outfreq2
int1  flag3=TRUE;             // flag to update testfreq
int1  i=0;
int8  j=0;                    // Timer0 Interrupt Counter
int8  CCP1Count=0;            // CCP1 interrupt count
int16 timer0Val=70;           // Timer0 Preset Value
int16 k=0;                    // Test Freq Interrupt Counter
int16 PWMPeriod=0;            // Time between CCP1 interrupts
int16 PWMWidth=0;             // Time between CCP1 and CCP2 interrupts

///////////////////////////////////////////////////////////////////////////////
// Function Prototypes
///////////////////////////////////////////////////////////////////////////////

void  initInts(void);

////////////////////////////////////////////////////////////////////////////////
// Interrupts
////////////////////////////////////////////////////////////////////////////////

// Timer0 -- Generates time of oscillation of output frequency required to a
//           give PWM duty cycle.  T0INTCNTS is the number of interrupts
//           required for the timing of the output frequency.  TESTFREQ is a
//           health status with a 1 Hz toggle.  If the toggle stops, the uC
//           has entered an unacceptable state.

#INT_TIMER0
void timer0_isr()
{
   if(j++>=T0INTCNTS)       // check for correct number of timer interrupts
   {
      j=0;                       // reset counter for next use   
      outTogla^=1;                // toggle output frequency 1=HIGH, 0=LO
      flag1=TRUE;
   }
   else if(j==T0INTCNTSD2)
   {
      outToglb^=1;               // toggle output freq 1-HIGH, 0=LO
      flag2=TRUE;
   }
   
   if(k++>=TESTFREQ)       // check for correct number of timer interrupts
   {
      k=0;                       // reset counter for next use
     
      outToglc^=1;                // toggle output frequency 1=HIGH, 0=LO
      flag3=TRUE;
   }
   
   set_timer0(timer0Val);
}

// Timer1 -- Used to measure pulse width and period of motor PWM.  Doesn't
//           do anything except allows the timer to reset itself after interrupt
//           During input of PWM, timer1 is reset within the CCP module and
//           should never overflow.

#INT_TIMER1
void timer1_isr()
{
   
}

#INT_EXT HIGH
void ext_isr()
{
   i^=1;   
   
   output_bit(MUXCNTRL,i); //i=0 -> motor forward, i-1 ->  motor reverse
   CCP1Count=1;
   
   if(i)    // if i=1 motor is reverse, set int for forward transition
      ext_int_edge(0,H_TO_L);
   else     // if i=0 motor is forward, set int for reverse transition
      ext_int_edge(0,L_TO_H);
     
   //CCP1IF=1; //May not need this
}

// Caputure/Compare/PWM 1 Interrupt Service Routine
//    Interrupt subroutine called on signal rising-edge at CCP1 (in Capture mode)
//   

#INT_CCP1
void ccp1_isr()
{
   if (CCP1Count==1)
   {
      CCP1Count++;
   }
   else if (CCP1Count==2)
   {
      PWMPeriod=CCP_1;                  // PWM Period = 0(start) to CCP_1(end)
      gotCCP1=TRUE;
   }
   
   SET_TIMER1(0);
}
// Caputure/Compare/PWM 2 Interrupt Service Routine
//    Interrupt subroutine called on signal falling-edge at CCP2 (in Capture mode)
//   

#INT_CCP2
void ccp2_isr()
{
   PWMWidth=CCP_2;       // read CCP2 register
}

// MAIN()
//   

void main()
{
   int8  PWMDutyCycle=0;
   
   initInts();                           // initialize interrupts

   while(TRUE)                            // Start main program loop (endless)
   {
      if (gotCCP1)                     // received motion?
      {
         disable_interrupts(GLOBAL);
         PWMDutyCycle=((float)PWMWidth/(float)PWMPeriod)*100;
     
         gotCCP1=FALSE;                // clear received CCP1 int flag
         
         if(PWMDutyCycle>=25)
            timer0Val=DC25INTNO;
         else if(PWMDutyCycle>=20)
            timer0Val=DC20INTNO;
         else if(PWMDutyCycle>=15)
            timer0Val=DC15INTNO;
         else if(PWMDutyCycle>=10)
            timer0Val=DC10INTNO;
         else
            timer0Val=DC05INTNO;
      }
     
      if(flag1)
      {
         if(!i)
            output_bit(OUTFREQPIN1,outTogla);   // toggle out freq from hi/lo or lo/hi
         else
            output_bit(OUTFREQPIN2,outTogla);
         
         flag1=FALSE;
      }
      else if(flag2)
      {
         if(!i)
            output_bit(OUTFREQPIN2,outToglb);   // toggle out freq from hi/lo or lo/hi
         else
            output_bit(OUTFREQPIN1,outToglb);
         
         flag2=FALSE;
      }
     
      if(flag3)
      {
         output_bit(OUTTESTFREQ,outToglc); // toggle out test freq from hi/lo or lo/hi

         flag3=FALSE;
      }
   }
}

///////////////////////////////////////////////////////////////////////////////
// Functions
///////////////////////////////////////////////////////////////////////////////

// initInts()
//    Initialize system routine enables the controller system interrupts and
//    defines the configuration of the port bits and the Compare/Capture/PWM modules

void  initInts()
{
   set_tris_A(0xF0);                      // all inputs except A0-A2
   set_tris_B(0xFF);                      // all inputs
   set_tris_C(0xFF);                      // all inputs
   
   output_bit(MUXCNTRL,FALSE);            // set switch for forward motion
   
   setup_ccp1(CCP_CAPTURE_RE);            // CCP1 - rising edge
   setup_ccp2(CCP_CAPTURE_FE);            // CCP2 - falling edge
   setup_timer_0(T0_INTERNAL|T0_8_BIT|T0_DIV_1); // Timer0 interrupt
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);// Timer1 interrupt
   clear_interrupt(INT_TIMER0);
   clear_interrupt(INT_TIMER1);
   clear_interrupt(INT_CCP1);
   clear_interrupt(INT_CCP2);
   clear_interrupt(INT_EXT);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_CCP1);
   enable_interrupts(INT_CCP2);
   enable_interrupts(INT_EXT_L2H);           // INT0 - lo to hi
   enable_interrupts(GLOBAL);
   
   return;
}


Thanks for your time,

JuBo
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun May 01, 2011 3:42 pm     Reply with quote

Your program is too complicated to test this. Here's how I did it.

I used two PicDem2-Plus boards.

Board #1 is the signal generator board. It has a short little program that
makes the test signal. The output signal is a 22 KHz, 5% duty cycle pulse.
It comes out on pin B0. The loop is hand-tweaked, empirically, by looking
at the signal on a scope to get the correct values.
Code:

#include <16F877.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)

//==========================================
void main()
{

// Create a 2.2us pulse at a 22.0 KHz rate.
while(1)
  {
   output_high(PIN_B0);
   delay_cycles(7);
   output_low(PIN_B0);
   delay_us(42);
  }


}


Board #2 uses the CCS ex_ccpmp.c example file:
Quote:
c:\program files\picc\examples\ex_ccpmp.c

I made two edits in the file, one is to change the PIC to 18F4520, which
is in the same family as your PIC. (I don't have your exact PIC).
The other edit was done in the output line, because I wanted a bit more
precision, so I changed it to use floating point:
Code:
    printf("%3.1f us \n\r", pulse_width/5.0 );

The result in the TeraTerm window is this, and it's correct:
Quote:

2.2 us
2.2 us
2.2 us
2.2 us

I tested this with compiler vs. 4.119. The connections are:
Pin B0 on Board #1 connects to the CCP1 and CCP2 inputs on Board #2.
Also, there is a ground wire between the two boards.

The key is, get rid of the complex test program, strip it down to almost
nothing, and quickly prove that it works.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group