microcontroller - PIC24FJ64GA002 中的 PWM 设置
问题描述
美好的一天,我正在使用 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),我的预分频器值为 <0,1>。我知道是 OC1R 引脚给出了周期为高的周期,但在数据表中,他们将其称为引脚,但是他们没有给出它是什么引脚(即 A0、A1、R15 等)。我也可以找到很少的示例代码来解释如何很好地编码。如果有人是某种帮助的PIC专家,将不胜感激!MCU 的数据表可在https://www.microchip.com/en-us/product/PIC24FJ64GA002下载。
解决方案
这是一个使用 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 周期无关。我提到这个是因为它真的让我很困惑。
推荐阅读
- html - Chrome 现在为表格单元格的背景图像添加了右边距
- javascript - IntlDateFormatter to date() 格式化字母
- python - 计算单词中的音节,.endwith 函数的问题
- tensorflow - tensorflow如何通过深度学习模型计算?
- haskell - 无法将类型 'Int' 与 '(a0, b0, c0)' 匹配 - `quickBatch` 的触发器期望什么?
- mysql - MySQL多子查询优化
- c# - ASP.NET MVC 使用 LINQ 从数据库中获取不同的值
- ios - 来自 Tracker Network API (SWIFT) 的 JSON
- excel - 使用 VBA 刷新 Excel 以查看共享文件上的其他用户更改
- php - 使用 PHP 将文件上传到服务器上的不同磁盘/目录