使用 PPS 的输入捕获映射

Input Capture mapping using PPS

我正在尝试配置 dsPIC33EP32MC204 上的输入捕捉模块 (IC1) 以将其用于占空比测量。作为输入,我想使用 RP35 引脚。为了测试配置的正确性,我设置了一个实验:我连接了一个具有 1Hz PWM 脉冲的脉冲发生器,并设置输入捕获以捕获每个上升沿。我估计这些上升沿会触发输入捕获中断,每次中断调用都会导致 LED 闪烁。不幸的是它不工作。如果有人能告诉我问题出在哪里,我将不胜感激。代码:

void Init_InputCapture(void)
{
    IC1CON1bits.ICSIDL = 0;
    IC1CON1bits.ICTSEL = 0b111;    // Peripheral clock (FP) is the clock source of the ICx
    IC1CON1bits.ICI = 0b00;        // 
    IC1CON1bits.ICM = 0b011;       //Capture mode every edge rising 
    IC1CON2bits.ICTRIG = 0;        // = Input source used to trigger the input capture timer (Trigger mode)
    IC1CON2bits.SYNCSEL = 0b00000; //IC1 module synchronizes or triggers ICx
    IC1CON2bits.IC32 = 0; // 16 bit mode only

    // Enable Capture Interrupt And Timer2
    IPC0bits.IC1IP = 1; // Setup IC1 interrupt priority level
    IFS0bits.IC1IF = 0; // Clear IC1 Interrupt Status Flag
    IEC0bits.IC1IE = 1; // Enable IC1 interrupt 
}

中断:

void __attribute__((__interrupt__, no_auto_psv)) _IC1Interrupt(void)
{
    LATBbits.LATB9 = ~LATBbits.LATB9;
    IFS0bits.IC1IF = 0; 
}

以及 main() 中的相关代码:

__builtin_write_OSCCONL(OSCCON & ~(1<<6));
RPINR7 = 0x23; ;    // IC1 mapped to RP35
__builtin_write_OSCCONL(OSCCON | (1<<6));

在设置过程中,我遵循了家庭参考手册中的说明。

您发布的代码可能更完整。对于 dsPIC 控制器,必须准确显示所有配置位的设置方式以及系统时钟的初始化方式。

这是您使用所需的最低设置代码更正的代码:

/*
 * file: main.c
 * target: dsPIC33EP32MC204
 * IDE: MPLABX v4.05
 * Compiler: XC16 v1.35
 * 
 * Description:
 *  Use Input Capture 1 module to catch a 1Hz pulse on GPIO RP35 and toggle LED on RB9.
 *
 */

#pragma config ICS = PGD2               // ICD Communication Channel Select bits (Communicate on PGEC2 and PGED2)
#pragma config JTAGEN = OFF             // JTAG Enable bit (JTAG is disabled)
#pragma config ALTI2C1 = OFF            // Alternate I2C1 pins (I2C1 mapped to SDA1/SCL1 pins)
#pragma config ALTI2C2 = OFF            // Alternate I2C2 pins (I2C2 mapped to SDA2/SCL2 pins)
#pragma config WDTWIN = WIN25           // Watchdog Window Select bits (WDT Window is 25% of WDT period)
#pragma config WDTPOST = PS32768        // Watchdog Timer Postscaler bits (1:32,768)
#pragma config WDTPRE = PR128           // Watchdog Timer Prescaler bit (1:128)
#pragma config PLLKEN = ON              // PLL Lock Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
#pragma config WINDIS = OFF             // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable bit (Watchdog timer enabled/disabled by user software)
#pragma config POSCMD = NONE            // Primary Oscillator Mode Select bits (Primary Oscillator disabled)
#pragma config OSCIOFNC = OFF           // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = OFF            // Peripheral pin select configuration (Allow multiple reconfigurations)
#pragma config FCKSM = CSECMD           // Clock Switching Mode bits (Clock switching is enabled,Fail-safe Clock Monitor is disabled)
#pragma config FNOSC = FRC              // Oscillator Source Selection (Internal Fast RC (FRC))
#pragma config PWMLOCK = ON             // PWM Lock Enable bit (Certain PWM registers may only be written after key sequence)
#pragma config IESO = OFF               // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)
#pragma config GWRP = OFF               // General Segment Write-Protect bit (General Segment may be written)
#pragma config GCP = OFF                // General Segment Code-Protect bit (General Segment Code protect is Disabled)

#include <xc.h>

/* Setup the clock to run at about 60 MIPS */
#define FOSC  (7372800L)    /* nominal fast RC frequency */
#define PLL_N1 (2L)         /* PLLPRE  CLKDIV<4:0> range 2 to 33 */
#define PLL_M  (65L)        /* PLLDIV  PLLFBD<8:0> range 2 to 513 */
#define PLL_N2 (2L)         /* PLLPOST CLKDIV<7:6> range 2, 4 or 8 */
#define FSYS (FOSC*PLL_M/(PLL_N1*PLL_N2))
#define FCYC (FSYS/2L)
/*
 * Global constant data
 */
const unsigned long gInstructionCyclesPerSecond = FCYC;
/*
 * Initialize this PIC
 */
void PIC_Init( void )
{
    unsigned int ClockSwitchTimeout;

    /*
    ** Disable all interrupt sources
    */
    __builtin_disi(0x3FFF); /* disable interrupts for 16383 cycles */
    IEC0 = 0;
    IEC1 = 0;
    IEC2 = 0;
    IEC3 = 0;
    IEC4 = 0;
    IEC5 = 0;
    IEC6 = 0;
    IEC8 = 0;
    IEC9 = 0;
    __builtin_disi(0x0000); /* enable interrupts */

    CLKDIV = 0;             /* Disable DOZE mode */

    if(!OSCCONbits.CLKLOCK) /* if primary oscillator switching is unlocked */
    {
        /* Select primary oscillator as FRC */
        __builtin_write_OSCCONH(0b000);

        /* Request switch primary to new selection */
        __builtin_write_OSCCONL(OSCCON | (1 << _OSCCON_OSWEN_POSITION));

        /* wait, with timeout, for clock switch to complete */
        for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && OSCCONbits.OSWEN;);

        /* Configure PLL prescaler, PLL postscaler, PLL divisor */
        PLLFBD=PLL_M-2; /* M=65 */
#if   PLL_N2==2
        CLKDIVbits.PLLPOST=0; /* N2=2 */
#elif PLL_N2==4
        CLKDIVbits.PLLPOST=1; /* N2=4 */
#elif PLL_N2==8
        CLKDIVbits.PLLPOST=3; /* N2=8 */
#else
#error invalid PLL_N2 paramenter
#endif
        CLKDIVbits.PLLPRE=PLL_N1-2; /* N1=2 */

        /* Select primary oscillator as FRCPLL */
        __builtin_write_OSCCONH(0b001);
        /* Request switch primary to new selection */
        __builtin_write_OSCCONL(OSCCON | (1 << _OSCCON_OSWEN_POSITION));

        /* wait, with timeout, for clock switch to complete */
        for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && OSCCONbits.OSWEN;);

        /* wait, with timeout, for the PLL to lock */
        for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && !OSCCONbits.LOCK;);

        /* at this point the system oscillator should be 119.808MHz */
    }

    /* make all inputs digital I/O */
    ANSELA = 0x00;
    ANSELB = 0x00;
    ANSELC = 0x00;

    /* Unlock PPS Registers */ 
    __builtin_write_OSCCONL(OSCCON & ~(_OSCCON_IOLOCK_MASK));

    /* map all PPS pins */
    RPINR7bits.IC1R = 35;    // Select RP35 (RB3/PGED1) as input for IC1

    /* Lock PPS Registers */
    __builtin_write_OSCCONL(OSCCON |  (_OSCCON_IOLOCK_MASK));
}
/*
 * Initialize Input Capture 1
 */
void Init_InputCapture( void )
{
    IC1CON1bits.ICSIDL = 0;
    IC1CON1bits.ICTSEL = 0b111;     // Peripheral clock (FP) is the clock source of the ICx
    IC1CON1bits.ICI = 0b00;         // 
    IC1CON1bits.ICM = 0b011;        //Capture mode every edge rising 
    IC1CON2bits.ICTRIG = 0;         // = Input source used to trigger the input capture timer (Trigger mode)
    IC1CON2bits.SYNCSEL = 0b00000;  //IC1 module synchronizes or triggers ICx
    IC1CON2bits.IC32 = 0;           // 16 bit mode only

    // Enable Capture Interrupt And Timer2
    IPC0bits.IC1IP = 4;             // Setup IC1 interrupt priority level
    IFS0bits.IC1IF = 0;             // Clear IC1 Interrupt Status Flag
    IEC0bits.IC1IE = 1;             // Enable IC1 interrupt 
}
/*
 * Interrupt Service Routine for IC1 
 */
void __attribute__((__interrupt__, no_auto_psv)) _IC1Interrupt(void)
{
    IFS0bits.IC1IF = 0; 
    LATBbits.LATB9 ^= 1;  // toggle LED
}
/*
 * Main process loop
 */
int main( void )
{
    PIC_Init();

    TRISBbits.TRISB9 = 0; // make RB9 an output
    LATBbits.LATB9 = 0;   // turn off LED

    Init_InputCapture();   

    for(;;)
    {
        /* process loop */
    }
    return 0;
}