【无标题】

本文详细介绍了dsPIC33F微控制器的多种振荡器配置选项,包括FRC、XT、HS、PLL等,以及如何在不同时钟源间切换以优化功耗和性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • # 二、dsPIC33F振荡器配置与应用

    1.简介

  • 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=FinM/(N1N2)

#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();
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zzcufo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值