|
|
View previous topic :: View next topic |
Author |
Message |
jmb1539
Joined: 29 Mar 2010 Posts: 11
|
Measure Duty Cycle of 22kHz PWM |
Posted: Sat Apr 30, 2011 9:56 am |
|
|
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
|
|
Posted: Sun May 01, 2011 3:42 pm |
|
|
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. |
|
|
|
|
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
|