-
4个外部和内部振荡器选项
-
片上锁相环,可基于选定的内部和外部振荡器升高内部工作频率
-
在各种时钟源之间进行动态时钟切换
-
用于节省系统功耗的打盹模式
-
故障保护时钟监视器FSCM,可检测时钟故障 ,并允许完全地恢复和关闭应用
时钟控制寄存器OSCCON -
用于时钟源选择的非易失性配置位 FOSCSEL FOSC–主振荡器选择的系统配置寄存器
-
Fcy(工作频率)=Fosc(振荡频率)/2
2.FRC振荡器
FRC是DSC内部高速RC振荡器,标称振荡频率为7.37MHz,并可以通过软件修改FRC时钟分频比1:2~1:256以调节FRC频率。
例程1使用FRC作为振荡器,并使用OSCI和OSC0引脚
#include <xc.h>
_FOSCSEL(FNOSC_FRC &IESO_OFF); //使用默认的FRC,7.37MHz
_FOSC(FCKSM_CSDCMD &OSCIOFNC_ON & IOL1WAY_ON &POSCMD_NONE); //禁止时钟切换,禁止引脚多次配置,禁止主振荡器
_FICD(JTAGEN_OFF &ICS_PGD2);//在线编程禁止
void DELAY1(unsigned int);
int main(void)
{ TRISA=0xFFF3; //RA2,RA3为输出
LATAbits.LATA2=1;
Nop();
LATAbits.LATA3=1;
DELAY1(1);
while(1)
{ DELAY1(1000); //标准FRC 延时1000ms
LATAbits.LATA2=~LATAbits.LATA2;
Nop();
LATAbits.LATA3=~LATAbits.LATA3;
};
return(0);
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 255; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}
#include <xc.h>
//使用带后分频的FRC 并使用OSC1和OSCO引脚
_FOSCSEL(FNOSC_LPRCDIVN &IESO_OFF); //使用默认的FRC,7.37MHz
_FOSC(FCKSM_CSDCMD &OSCIOFNC_ON & IOL1WAY_ON &POSCMD_NONE); //禁止时钟切换,禁止引脚多次配置,禁止主振荡器
_FICD(JTAGEN_OFF &ICS_PGD2);//在线编程禁止
void DELAY1(unsigned int);
int main(void)
{ //CLKDIV:时钟分频比寄存器控制打盹模式,并选择PLL预分频比、PLL分频比和FRC后分频比
CLKDIVbits.FRCDIV=0b010;//FRC被4分频000-111即1至256分频
while(OSCCONbits.COSC !=0b111);//等待时钟稳定
TRISA=0xFFF3; //RA2,RA3为输出
LATAbits.LATA2=1;
Nop();
LATAbits.LATA3=1;
DELAY1(1);
while(1)
{ DELAY1(1000); //标准FRC 延时1000ms
LATAbits.LATA2=~LATAbits.LATA2;
Nop();
LATAbits.LATA3=~LATAbits.LATA3;
};
return(0);
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 255; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}
例3 使用微调频率的FRC
#include <xc.h>
//使用带后分频的FRC 并使用OSC1和OSCO引脚
_FOSCSEL(FNOSC_FRC &IESO_OFF); //使用默认的FRC,7.37MHz
_FOSC(FCKSM_CSDCMD &OSCIOFNC_ON & IOL1WAY_ON &POSCMD_NONE); //禁止时钟切换,禁止引脚多次配置,禁止主振荡器
_FICD(JTAGEN_OFF &ICS_PGD2);//在线编程禁止
void DELAY1(unsigned int);
int main(void)
{ //OSCTUN:振荡器调节寄存器
OSCTUNbits.TUN=0b11111;//调整为最快的工作频率,理论值为8.2268MHz
TRISA=0xFFF3; //RA2,RA3为输出
LATAbits.LATA2=1;
Nop();
LATAbits.LATA3=1;
DELAY1(1);
while(1)
{ DELAY1(1000); //标准FRC 延时1000ms
LATAbits.LATA2=~LATAbits.LATA2;
Nop();
LATAbits.LATA3=~LATAbits.LATA3;
};
return(0);
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 255; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}
例4 带PLL FRC 7.37MHz 期望的总振荡频率为60MHz.使用PLL锁相电路,把比较低的FRC的7.37MHz频率,通过内部的PLL锁相电路提高到期望的振荡频率60MHz.要使用PLL,需要设置三个参数:N1=2~33 、M=2~512和N2=2 or 4 or 8 输出频率
Fosc=Fin∗M/(N1∗N2)
Fosc=Fin*M/(N1*N2)
Fosc=Fin∗M/(N1∗N2)
#include <xc.h>
_FOSCSEL(FNOSC_FRCPLL &IESO_OFF); //使用FRC启动,初始振荡器为PLL的FRC
_FOSC(FCKSM_CSDCMD &OSCIOFNC_ON & IOL1WAY_ON &POSCMD_NONE); //禁止时钟切换,禁止引脚多次配置,禁止主振荡器
_FICD(JTAGEN_OFF &ICS_PGD2); //在线编程禁止
void DELAY1(unsigned int);
int main(void) {
//CLKDIV:时钟分频比寄存器
CLKDIVbits.PLLPRE = 5; //PLL相位检测器输入分频比选择位即预分频比N1
PLLFBDbits.PLLDIV = 112; //PLLFBD 反馈分频比寄存器即M,PLL倍频比
CLKDIVbits.PLLPOST = 0; //PLL VCO输出分频比选择位即后分频比N2
while(OSCCONbits.COSC!=0b001);//等待时钟稳定
TRISA = 0xFFF3; //RA2,RA3为输出
LATAbits.LATA2 = 1;
Nop();
LATAbits.LATA3 = 1;
DELAY1(1);
while (1) {
DELAY1(1000); //标准FRC 延时1000ms
LATAbits.LATA2 = ~LATAbits.LATA2;
Nop();
LATAbits.LATA3 = ~LATAbits.LATA3;
};
return (0);
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 255; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}
3、主振荡器(XT、HS OR EC)
例 5 不带PLL的简单XT振荡器方式
只要对相应的系统配置位设置,使用满足要求的晶振,接于相应的OSCI和OSCO接口,并联2个20pf左右的电容就可以了。
#include <xc.h>
_FOSCSEL(FNOSC_PRI &IESO_OFF); //使用主振荡器
_FOSC(FCKSM_CSDCMD &OSCIOFNC_ON & IOL1WAY_ON &POSCMD_NONE); //禁止时钟切换,禁止引脚多次配置,禁止主振荡器
_FICD(JTAGEN_OFF &ICS_PGD2); //在线编程禁止
void DELAY1(unsigned int);
int main(void) {
TRISBbits.TRISB7=0;
PORTBbits.RB7=1;
while (1) {
DELAY1(1000); //在4MHz工作频率 下 延时1000ms
PORTBbits.RB7=~PORTBbits.RB7;
};
return (0);
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 284; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}
例6 带PLL的HS振荡器方式
#include <xc.h>
_FOSCSEL(FNOSC_PRIPLL &IESO_OFF); //使用带PLL主振荡器
_FOSC(FCKSM_CSDCMD &OSCIOFNC_ON & IOL1WAY_ON &POSCMD_NONE); //禁止时钟切换,禁止引脚多次配置,禁止主振荡器
_FICD(JTAGEN_OFF &ICS_PGD2); //在线编程禁止
void DELAY1(unsigned int);
int main(void) {
CLKDIVbits.PLLPRE=1;
PLLFBDbits.PLLDIV=38;//PLLFBD反馈分频比
CLKDIVbits.PLLPOST=0;
while(OSCCONbits.COSC!=0b011);
TRISBbits.TRISB7=0;
PORTBbits.RB7=1;
while (1) {
DELAY1(2000); //在7.37MHz工作频率 下 延时1000ms
PORTBbits.RB7=~PORTBbits.RB7;
};
return (0);
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 255; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}
例7 SOSC辅助振荡器
#include <xc.h>
_FOSCSEL(FNOSC_SOSC &IESO_OFF);
_FOSC(FCKSM_CSDCMD &OSCIOFNC_ON & IOL1W
_FICD(JTAGEN_OFF &ICS_PGD2); //在线编程
void DELAY1(unsigned int);
int main(void) {
//__builtin_write_OSCCONH:解锁并写其
__builtin_write_OSCCONH(0b0000100);
__builtin_write_OSCCONL(0b00000011
while(OSCCONbits.COSC!=0b100);
TRISBbits.TRISB7=0;
PORTBbits.RB7=1;
while (1) {
DELAY1(2000); //在7.37MHz工作频
PORTBbits.RB7=~PORTBbits.RB7;
};
return (0);
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 255; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}
例8 LPRC低功耗内部振荡器 用作看门狗定时器和故障保护时钟监视器的参考时钟
#include <xc.h>
_FOSCSEL(FNOSC_LPRC &IESO_OFF);
_FOSC(FCKSM_CSDCMD &OSCIOFNC_ON & IOL1WAY_ON &POSCMD_NONE); //禁止时钟切换,禁止引脚多次配置,禁止主振荡器
_FICD(JTAGEN_OFF &ICS_PGD2); //在线编程禁止
void DELAY1(unsigned int);
int main(void) {
//__builtin_write_OSCCONH:解锁并写其参数到OSCCONH
__builtin_write_OSCCONH(0b0000101);//NOSC=0b100新振荡器
while(OSCCONbits.COSC!=0b101);
TRISBbits.TRISB7=0;
LATAbits.LATA7=1;
while (1) {
DELAY1(2000); //在7.37MHz工作频率 下 延时1000ms
LATAbits.LATA7=~PORTBbits.RB7;
};
return (0);
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 255; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}
例9 时钟切换
在软件控制下,系统可以在四个时钟源之间自由切换,dsPic33F时钟切换过程带有安全锁定的时钟保障机制。
振荡器切换步骤:
#include <xc.h>
_FOSCSEL(FNOSC_FRC &IESO_OFF);
_FOSC(FCKSM_CSECMD &OSCIOFNC_OFF & IOL1WAY_ON &POSCMD_XT); //禁止时钟切换,禁止引脚多次配置,禁止主振荡器
_FICD(JTAGEN_OFF &ICS_PGD2); //在线编程禁止
_FWDT(FWDTEN_OFF);//通过用户软件使能/禁止看门狗定时器
#define _ISR1 __attribute__((interrupt,auto_psv))
#define LED _RB9
void _ISR1_INT0Interrupt(void);
void DELAY1(unsigned int);
unsigned char FLAG = 0;
int main(void) {
RCONbits.SWDTEN = 0;//禁止WDT
CORCONbits.IPL3 = 0;//cpu中断优先级小于等于7,如大于7则其他中断均被禁止
SRbits.IPL = 4;//CPUT中断优先级为4
INTCON1bits.NSTDIS = 0;//禁止中断嵌套
INTCON2bits.INT0EP = 1;//INT0为下降沿中断
IEC0bits.INT0IE = 1;//允许INT0中断
IPC0bits.INT0IP = 5;//INT0中断优先级为5
CNPU2bits.CN23PUE = 1;//RB7为弱上拉使能
_TRISB9 = 0;//LED端口设置
_TRISB7 = 1;//INT0输入口设置
while (1) {
DELAY1(1000); //在7.37MHz工作频率 下 延时1000ms
LED=~LED;
};
return (0);
}
void _ISR1_INT0Interrupt(void) {
DELAY1(30);
IFS0bits.INT0IF = 0;
if (FLAG == 0) {//只能切换一次
_PLLPRE = 0;//
_PLLPOST = 1;//
_PLLDIV = 78;//
__builtin_write_OSCCONH(0b00000011);//新振荡器为XT/PLL
__builtin_write_OSCCONL(0b01);//开始切换
while (OSCCONbits.COSC != 0b011);//等待切换完成
while (OSCCONbits.OSWEN == 1);//确认已经切换完成
while (OSCCONbits.LOCK == 0);//确认PLL已经锁定
FLAG = 1;
}
}
void DELAY1(unsigned int n) {
unsigned int j, k;
for (j = 0; j < n; j++) {
for (k = 255; k > 0; k--) {
Nop();
Nop();
Nop();
}
}
}