【问题标题】:PWM settings in PIC24FJ64GA002PIC24FJ64GA002 中的 PWM 设置
【发布时间】:2021-11-25 22:22:36
【问题描述】:

美好的一天,我正在使用 PIC24FJ64GA002 微控制器,并且正在努力让 PWM 为我想要使用的伺服系统工作。我的代码如下:

// PIC24FJ64GA002 Configuration Bit Settings

// 'C' source line config statements

// CONFIG2
#pragma config POSCMOD = NONE           // Primary Oscillator Select (Primary oscillator disabled)
#pragma config I2C1SEL = PRI            // I2C1 Pin Location Select (Use default SCL1/SDA1 pins)
#pragma config IOL1WAY = ON             // IOLOCK Protection (Once IOLOCK is set, cannot be changed)
#pragma config OSCIOFNC = OFF           // Primary Oscillator Output Function (OSC2/CLKO/RC15 functions as CLKO (FOSC/2))
#pragma config FCKSM = CSDCMD           // Clock Switching and Monitor (Clock switching and Fail-Safe Clock Monitor are disabled)
#pragma config FNOSC = FRC              // Oscillator Select (Fast RC Oscillator (FRC))
#pragma config SOSCSEL = SOSC           // Sec Oscillator Select (Default Secondary Oscillator (SOSC))
#pragma config WUTSEL = LEG             // Wake-up timer Select (Legacy Wake-up Timer)
#pragma config IESO = ON                // Internal External Switch Over Mode (IESO mode (Two-Speed Start-up) enabled)

// CONFIG1
#pragma config WDTPS = PS32768          // Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128            // WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = ON              // Watchdog Timer Window (Standard Watchdog Timer enabled,(Windowed-mode is disabled))
#pragma config FWDTEN = ON              // Watchdog Timer Enable (Watchdog Timer is enabled)
#pragma config ICS = PGx1               // Comm Channel Select (Emulator EMUC1/EMUD1 pins are shared with PGC1/PGD1)
#pragma config GWRP = OFF               // General Code Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF                // General Code Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = OFF             // JTAG Port Enable (JTAG port is disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

/*
 * File:   34660046LAB2.c
 * Author: leone
 *
 * Created on 06 September 2021, 1:27 PM
 */


   

 

   

 #include "p24FJ64GA002.h"

        #include "xc.h"

        #define _LATR15 OC1R
        
        
        
        
        int main(void) {
        
            
            T2CON = 0x8010;
            TMR2=0;
            PR2=9999;
            
            _T2IP=4;  //Default priority value
            _T2IF=0;  //Clears interrupt flag before interrupt
            _T2IE=1;  //Enables interrupt
            
            OC1CONbits.OC  = 0;        // Output compare channel is disabled
        OC1R           = 0x1388 ; // Initialize Compare Register1 with 50% duty cycle
        
        OC1CONbits.OCSIDL   = 0;     // Output capture will continue to operate in CPU Idle mode
        OC1CONbits.OCFLT    = 0;     // No PWM Fault condition has occurred (this bit is only used when OCM<2:0> = 111)
        OC1CONbits.OCTSEL   = 0;     // Timer2 is the clock source for output Compare
        OC1CONbits.OCM      = 0x6;   // PWM mode on OC, Fault pin disabled
            
            
            
            TRISBbits.TRISB15=0;
           _LATB15=0;
            while(1)
            {
                if(TMR2>OC1R)
                {
                    _LATB15=1;
                }
                else
                {
                    _LATB15=0;
                }
            }
            return 0;
        }

我将 T1CON 的周期设置为 2 ms,而 OC1R 的周期为该周期的一半,这将导致占空比为 50%。我正在使用 FRC 振荡器 (8MHz),我的预分频器值为 。我知道是 OC1R 引脚给出了周期为高的周期,但在数据表中他们将其称为引脚,但是他们没有给出它是什么引脚(即 A0、A1、R15 等)。我也可以找到很少的示例代码来解释如何很好地编码。如果有人是某种帮助的PIC专家,将不胜感激! MCU的数据表可以在https://www.microchip.com/en-us/product/PIC24FJ64GA002下载。

【问题讨论】:

    标签: microcontroller pic pwm pic24 mcu


    【解决方案1】:

    首先配置 IO 引脚用于 PWM 输出,我假设您使用 SPDIP 封装并想使用 OC1 PWM 输出引脚:

    // Unlock Registers
    __builtin_write_OSCCONL(OSCCON & 0xBF);
    // Configure Output Functions (Table 10-3)
    // Assign OC1 To Pin RP2
    RPOR1bits.RP2R = 18;
    // Lock Registers
    __builtin_write_OSCCONL(OSCCON | 0x40);
    

    有关输出引脚配置,请参阅数据表的10.4.3.2 输出映射部分。

    按照数据表的14.3 脉冲宽度调制模式部分中的步骤:

    1. 通过写入选定的定时周期寄存器 (PRy) 来设置 PWM 周期。如果您的周期为 2 毫秒,则计算 PRy 寄存器值:
    #define Fosc          ( 8000000 )
    #define PWM_PERIOD_MS ( 2 )
    #define PWM_FREQ_HZ   ( 1000 / PWM_PERIOD_MS ) // In this case 500Hz
    #define PRy_VALUE     (uint16_t) ( (( Fosc ) / ( 4 * TMRyPS * PWM_FREQ)) - 1 )
    
    // Somewhere in the init func or code assign the computed value for the period register
    PRx = PRx_VALUE;
    
    1. 通过写入 OCxRS 寄存器来设置 PWM 占空比。由于您需要 50% 的占空比,请计算 OCxRS 寄存器的值:
    #define DUTY          (50)
    #define DUTY_VALUE    (uint16_t) ( ( 4 * ( TMRyPS - 1 ) * DUTY ) / 100 )
    
    // Somewhere in the init func or code assign the computed value for the duty cycle register
    OCxRS = DUTY_VALUE;
    
    1. 将初始占空比写入 OCxR 寄存器。在 OCxRS 分配后立即将 DUTY_VALUE 分配给 OCxR 寄存器:
      OCxR = DUTY_VALUE;

    2. 如果需要,为定时器和输出比较模块启用中断。 PWM 故障引脚使用需要输出比较中断。

    3. 通过写入输出比较模式位 OCM 将输出比较模块配置为两种 PWM 操作模式之一 (OCxCON)。

     OC1CONbits.OCTSEL   = 0;     // Timer2 is the clock source for output Compare
     OC1CONbits.OCM      = 0x6;   // PWM mode on OC, Fault pin disabled
    
    1. 设置 TMRy 预分频值并通过设置 TON (TyCON) = 1 启用时基。
    T2CON = 0x0010 // Timer2 prescaler 1:8, internal clock
    T2CON.TON = 1;
    

    如果上述步骤正确完成,从现在开始,您应该可以使 PWM 正常工作。按照此处的说明修改您的代码。那就试一试,告诉我结果。

    【讨论】:

      【解决方案2】:

      这是一个使用 MPLABX v5.50 和 XC16 v1.70 构建的完整应用程序:

      /*
       * File:   main.c
       * Author: dan1138
       * Target: PIC24FJ64GA002
       * Compiler: XC16 v1.70
       * IDE: MPLABX v5.50
       *
       * Created on October 8, 2021, 1:12 PM
       *
       *                                 PIC24FJ64GA002
       *                  +-------------------:_:-------------------+
       *      ICD_VPP --> :  1 MCLR                         VDD  28 : <-- 3v3
       *              < > :  2 RA0/AN0                      VSS  27 : <-- GND
       *              < > :  3 RA1/AN1             AN9/RP15/RB15 26 : < > 
       *      ICD_PGD < > :  4 RB0/PGD1/AN2        AN6/RP14/RB14 25 : < > 
       *      ICD_PGC < > :  5 RB1/PGC1/AN3        AN7/RP13/RB13 24 : < > 
       *      PWM/OC1 < > :  6 RB2/RP2/SDA2/AN4    AN8/RP12/RB12 23 : < > 
       *              < > :  7 RB3/RP3/SCL2/AN5        RP11/RB11 22 : <*> 
       *              - > :  8 VSS                     RP10/RB10 21 : <*> 
       *              < > :  9 RA2/OSCI                     VCAP 20 : <-- 10uF
       *              < > : 10 RA3/OSCO                     VSS  19 : <-- GND
       *              < > : 11 RB4/RP4             SDA1/RP9/RB9  18 : <*> 
       *              < > : 12 RA4                 SCL1/RP8/RB8  17 : <*> 
       *          3v3 --> : 13 VDD                      RP7/RB7  16 : <*>
       *              <*> : 14 RB5/RP5/PGD3        PGC3/RP6/RB6  15 : <*> 
       *                  +-----------------------------------------+
       *                                    DIP-28
       *               * Indicates 5.0 volt tolerant input pins.
       *
       * Description:
       *  Initialize the controller to use a system oscillator of 8MHz from the on chip Fast RC oscillator.
       *  Setup the OC1 function to provide a 4KHz square wave output on GPIO pin RB2.
       * 
       * Notes:
       * See: https://stackoverflow.com/questions/69453833/pwm-settings-in-pic24fj64ga002
       * 
       */
      
      #pragma config POSCMOD = NONE, I2C1SEL = PRI, IOL1WAY = OFF, OSCIOFNC = ON
      #pragma config FCKSM = CSECMD, FNOSC = FRC, SOSCSEL = SOSC, WUTSEL = LEG
      #pragma config IESO = ON, WDTPS = PS32768, FWPSA = PR128, WINDIS = ON
      #pragma config FWDTEN = OFF, ICS = PGx1, GWRP = OFF, GCP = OFF, JTAGEN = OFF
      
      #include "xc.h"
      
      /*
       * Define the system oscillator frequency that this code will setup
       */
      #define FSYS (8000000ul)
      #define FCY  (FSYS/2ul)
      
      /*
       * Initialize this PIC
       */
      void PIC_Init(void) {   
          /* Disable all interrupt sources  */ 
          __builtin_disi(0x3FFF); /* disable interrupts for 16383 cycles */
          IEC0 = 0;
          IEC1 = 0;
          IEC2 = 0;
          IEC3 = 0;
          IEC4 = 0;
          __builtin_disi(0x0000); /* enable interrupts */
      
          CLKDIV =  0x0000; /* set for 8MHz FRC clock operations */
          AD1PCFG = 0xffff; /* Set for digital I/O */
          CMCON   = 0x0000;
      
          _NSTDIS = 1;    /* disable interrupt nesting */
          
          TRISA   = 0xFFFF;
          TRISB   = 0xFFFF;
      }
      /*
       * Initialize OC1 for PWM operation on PORTB bit RB2/RP2
       */
      void OC1_Init(void) {
          OC1CON = 0;             /* turn off OC1 */
          AD1PCFGbits.PCFG4 = 1;  /* make GPIO RB2/RP2/AN4 a digital I/O pin */
          LATBbits.LATB2 = 0;     /* make GPIO RB2/RP2/AN4 output low */
          TRISBbits.TRISB2 = 0;   /* make GPIO RB2/RP2/AN4 a digital output */
          _RP2R = 18;             /* magic number to assign OC1 to RB2, see DS39881E-page 109 */
          OC1CONbits.OCTSEL = 0;  /* Use TIMER2 clock input and prescaler settings as clock for PWM count register */
          OC1CONbits.OCM = 0b110; /* Set OC1 for PWM mode, fault shutdown disabled */
          T2CON = 0;              /* turn off TIMER2 */
          T2CONbits.TCKPS = 0b00; /* set TIMER2 prescale as 1:1 */
          T2CONbits.TCS = 0;      /* set TIMER2 clock source as FSYS/2 */
          PR2 = (FCY/4000ul)-1;   /* set PWM period to 4KHz */
          OC1RS = (PR2+1)>>1;     /* set PWM duty cycle to 50% */
          T2CONbits.TON = 1;      /* turn on TIMER2 */
      }
      /*
       * main application
       */
      int main(void) {
          
          PIC_Init();
          OC1_Init();
          /*
           * application process loop
           */
          for(;;) {
              /* poll for start of PWM period */
              if(IFS0bits.T2IF){
                  IFS0bits.T2IF= 0; /* put a breakpoint here to verify PWM timing with simulator stop watch */
                  Nop();
                  Nop();
                  Nop();
              }
          }
          return 0;
      }
      

      此代码可以在 MPLABX 仿真工具中正确运行。这几乎从来都不是真的。恕我直言,MPLABX 模拟器很垃圾。

      这是模拟会话工作的屏幕截图:

      关于 PIC24FJ64GA002 输出比较模块的重要说明是,它是早期的硅实现,较新的控制器为每个输出比较模块具有独立的周期计数寄存器。这意味着输出比较模块周期与这些控制器上的 TIMER 周期无关。我提到这个是因为它真的让我很困惑。

      【讨论】:

        猜你喜欢
        • 2015-10-06
        • 2015-03-22
        • 2020-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-03
        相关资源
        最近更新 更多