PIC振荡器配置与时钟切换

发布者:诚信与爱最新更新时间:2018-07-30 来源: eefocus关键字:PIC  振荡器配置  时钟切换 手机看文章 扫描二维码
随时随地手机看文章

单片机编程就是C语言+寄存器设置。 
以前对PIC振荡器的配置都是拿来主义,把别人的代码拿过来用就行了。这两天特意研究下振荡器的配置与时钟切换。在mplab IDE和C30编译器下,针对PIC24FJxx系列单片机完成的测试。 
配置振荡器最主要的目的就是为了设置机械时钟Fosc,此时钟给CPU和外设提供时钟源。但为了降低功耗又不中断外设正常通信,此系列PIC保证CPU与外设的时钟同步情况下,增加了打盹模式,用于降低CPU运行时钟速度,以达到节能效果。 
个人是这么理解的,CPU时钟就是代码运行时钟,决定代码运行速度;外设时钟就是中断、定时器、输入捕捉、输出比较、UART、SPI等外设的时钟源。 
时钟框图(From:datasheet) 
在时钟框图中可看出,由四个振荡器提供时钟源,包括两个外部振荡器(主振荡器、辅助振荡器)和两个内部振荡器(FRC振荡器——快速RC、LPRC振荡器——低功耗RC)。 
时钟模式共11种: 
1. XT——1M到4M的石英晶体振荡器(主振荡器) 
2. HS——超过4M的石英晶体振荡器(主振荡器) 
3. EC——低于1M的陶瓷振荡器(主振荡器) 
4. XTPLL——带PLL模块的主振荡器(主振荡器) 
5. HSPLL——带PLL模块的主振荡器(主振荡器) 
6. ECPLL——带PLL模块的主振荡器(主振荡器) 
7. FRCPLL——带后分频器和PLL模块的快速RC振荡器(内部振荡器) 
8. FRCDIV——带后分频器的快速RC振荡器(内部振荡器) 
9. FRC——快速RC振荡器(内部振荡器) 
10. LPRC——低功耗RC振荡器(内部振荡器) 
11. SOSC——辅助振荡器(辅助振荡器) 
注:①PLL模块是一个锁相环(Phase Lock Loop)倍频器,可提高4倍频率,②这里共有11时钟模式,在配置时,有一个保留模式,但无HSPLL模式

一. 振荡器配置

一般为了减少外围电路,采用内部振荡器,其时钟频率最高可达32M。如果需要严格的时钟频率,而内部振荡器又无法匹配上,那才考虑外部振荡器。所以一般按以下步骤来配置(后面对应寄存器名): 
1. 是否使用主振荡器——配置位CW2的POSCMD1:POSCMD0 
2. 选择初始振荡器,即时钟模式——配置位CW2的FNOSC2:FNOSC0 
3. 配置OSCO引脚功能,在EC和非主振荡器时钟模式下,不占用此引脚,可配置成Fosc/2时钟输出CLKO,或普通I/O口RA3——配置位CW2的OSCIOFCN 
4. 【不使用SOSC模式可忽略此步】配置SOSC辅助振荡器使能位——OSCCON的SOSCEN 
5. 【不使用FRCPLL、FRCDIV模式可忽略此步】配置FRC后分频比——CLKDIV的RCIDV2:RCDIV0 
6. 【不使用打盹模式可忽略此步】配置CPU与外设的时钟比——CLKDIV的DOZE2:DOZE0 
7. 【不使用打盹模式可忽略此步】配置中断是否影响打盹使能位(DOZEN)——CLKDIV的RIO 
8. 【不使用打盹模式可忽略此步】使能打盹模式——CLKDIV的DOZEN 
9. 【不调节FRC振荡器频率,应忽略此步】校准FRC振荡器频率——OSCTUN的TUN5:TUN0 
(四个寄存器位组成参考文章末尾)

在不使用时钟切换的模式下,以上9步就可解决振荡器的配置问题。上面涉及到4个寄存器CW2、OSCCON、CLKDIV和OSCTUN,要配置他们可不是直接使用“_SOSCEN = 1;”或“OSCCONbits.SOSCEN = 1;”那样简单。CLKDIV和OSCTUN两个寄存器可按前面的方式进行配置,而CW2与OSCCON需要通过其他方式进行配置: 
1)CW2——两种方法 
可通过IDE自带配置位界面(Configure->Configuration Bits…)直接选择 
或在#include包含文件位置后,使用代码_CONFIG2(value),value为配置数值,如: 
_CONFIG2(POSCMOD_NONE & FNOSC_FRCPLL & OSCIOFNC_ON & FCKSM_CSECME) 
2)OSCCON——也有两种方法 
首先说明下,OSCCON是个核心寄存器,不是可以随便编辑的,用了两把锁把它的高低字节分别锁起来了。所以要编辑它,必须先解锁。高字节OSCCON<15:8>写序列为:连续将78h和9Ah写入高字节进行解锁,立即写入需要的数值。低字节OSCCON<7:0>写序列为:连续将46h和57h写入低字节进行解锁,立即写入需要的数值。 
因此,要先区分所编辑位属于OSCCON高字节还是低字节,再按要求进行解锁和写入。 
第一种方法,使用内置函数,__builtin_write_OSCCONH(value)来配置OSCCON高字节,和__builtin_write_OSCCONL(value)来配置OSCCON低字节。使用内置函数,不需要考虑解锁,编译成汇编代码已经包含了解锁序列,见下图(参考C30编译器的帮助文件hlpMPLABC30.chm) 
写入OSCCON的内置函数 
第二种方法,直接使用汇编语言,嵌套在C语言中。发现C30不支持#asm和#endasm的多行汇编,就使用单行嵌入“asm(instruction);”,望知道的大侠告诉一声(谢谢^_^)。

    asm("mov #OSCCONH, w1");

    asm("mov #0x78, w2");

    asm("mov #0x9A, w3");

    asm("mov #0x00, w4"); //0x00 is the value will write to OSCCONH

    asm("mov.b w2, [w1]");

    asm("mov.b w3, [w1]");

    asm("mov.b w4, [w1]");


    asm("mov #OSCCONL, w1");

    asm("mov #0x46, w2");

    asm("mov #0x57, w3");

    asm("mov #0x01, w4"); //0x01 is the value will write to OSCCONL

    asm("mov.b w2, [w1]");

    asm("mov.b w3, [w1]");

    asm("mov.b w4, [w1]");


相信用C语言写程序的人都会选内置函数。 

以下是个完整的代码,使用FRCPLL时钟模式,Fosc=32M,用定时器T1开关LED灯,实现每3s切换一次状态:


#include


_CONFIG1(JTAGEN_OFF & GCP_OFF & FWDTEN_OFF)

_CONFIG2(POSCMOD_NONE & FNOSC_FRCPLL & OSCIOFNC_ON) // clock mode:FRCPLL, OSCO/RA3 functions as port I/O


typedef char BYTE;

typedef unsigned int WORD;

typedef unsigned long int DWORD;


#define LED_TRIS        _TRISA3

#define LED_ON()        _LATA3 = 1

#define LED_OFF()       _LATA3 = 0

#define LED_TRIGGER()   _LATA3 = ~_LATA3


#define TIME_TEN_MICROSECOND    300


WORD ledTriggerCount = 0;


void IC_Initialize(void)

{

    /*Oscillator configuration :32M FRCPLL*/

    __builtin_write_OSCCONL(0x00);

    CLKDIVbits.RCDIV = 0b000; //FRC postscaler divide by 1, is 8M


    /*enable DOZE mode*/

    //CLKDIVbits.DOZE = 0b001; 

    //CLKDIVbits.DOZEN = 1; //enable DOZE bit


    /*initialize T1*/

    T1CONbits.TCS = 0; // internal clock

    T1CONbits.TGATE = 0; //disable Gated time accumulation

    T1CONbits.TCKPS = 0b01; //prescale =1:8, T1 = 2*8/fosc = 0.5us

    T1CONbits.TON =0;

    TMR1 = 0;

    PR1 = 20000; // time on a cycle is 10us

    _T1MD = 0; //default value, enable clock source to T1

    _T1IP = 7; //highest priority

    _T1IF = 0;

    _T1IE = 1; //enable T1 interrupt

}


int main(void)

{

    IC_Initialize();

    LED_TRIS =0;

    LED_ON();

    T1CONbits.TON =1; //T1 start

    while(1);


    return 0;

}


void __attribute__ ((__interrupt__, no_auto_psv)) _T1Interrupt(void)

{

    if(++ledTriggerCount == TIME_TEN_MICROSECOND){

        ledTriggerCount = 0;

        LED_TRIGGER();

    }

    _T1IF = 0;

}


二. 时钟切换


时钟切换按正常逻辑来理解,应该是告诉我一个新时钟模式,然后我切换过去就好了。对,就是这么简单。具体地寄存器操作步骤,看下面: 

1. 开启时钟切换功能,FCKSM1位必须清零——CW2的FCKSM1:FCKSM0 

2. 配置新时钟模式——OSCCON的NOSC2:NOSC0 

3. 开始切换——OSCCON的OSWEN 

三步完成时钟切换,但有四点要注意: 

1)主振荡器下的三个子模式(XT、HS和EC)是由配置位决定,他们之间无法切换的。这好理解,你用一台发电机给工厂发电,你要切换发电机,在不断电的情况下不好办吧,得先断电后再切换。这里要切换就要重新烧录程序并设置配置位 

2)使能PLL的主振荡器与FRCPLL之间也不能直接切换,但可通过先中转到FRC下再切换 

3)涉及到引脚或分频类的,要注意设置好,参考datasheet,这里不再赘述 

4)OSCCON的COSC2:COSC0可读出当前时钟模式,在切换前可先判断当前时钟模式 

下面实例代码,在FRCPLL(Fosc=32M)和FRC(Fosc=8M)模式之间循环切换,通过LED呈现状态结果。在FRCPLL模式下,LED亮2s,灭2s,然后切换到FRC模式下,亮8s,灭8s,再切换到FRCPLL模式下,如此循环:


#include


_CONFIG1(JTAGEN_OFF & GCP_OFF & FWDTEN_OFF)

_CONFIG2(POSCMOD_NONE & FNOSC_FRCPLL & OSCIOFNC_ON & FCKSM_CSECME) // OSCO/RA3 functions as port I/O, enable clock switch


typedef char BYTE;

typedef unsigned int WORD;

typedef unsigned long int DWORD;


#define LED_TRIS        _TRISA3

#define LED_ON()        _LATA3 = 1

#define LED_OFF()       _LATA3 = 0

#define LED_TRIGGER()   _LATA3 = ~_LATA3


#define TIME_TEN_MICROSECOND    200


WORD ledTriggerCount = 0;

BYTE  oscillatorSwitchCount = 0;


void IC_ClockSwitch(BYTE newOSC)

{

    _T1IE = 0; //disable all interrupts before switching    

    __builtin_write_OSCCONH(newOSC); //set new oscillator mode

    __builtin_write_OSCCONL(0x01);  //enable oscillator switch


    while(OSCCONbits.OSWEN); //waiting for a successful clock transition

    _T1IE = 1; //enable interrupt after switched

}


void IC_Initialize(void)

{

    //Oscillator configuration :32M FRCPLL

    CLKDIVbits.RCDIV = 0b000; //FRC postscaler divide by 1, input 4*PLL is 8M

    CLKDIVbits.DOZE = 0b001; //1:2, CPU clock:16M

    CLKDIVbits.DOZEN = 1; //enable DOZE bit


    //initialize T1

    T1CONbits.TCS = 0; // internal clock

    T1CONbits.TGATE = 0; //disable Gated time accumulation

    T1CONbits.TCKPS = 0b01; //prescale =1:8, T1 = 2*8/fosc = 0.5us

    T1CONbits.TON =0;

    TMR1 = 0;

    PR1 = 20000; // time on a cycle is 10us

    _T1MD = 0; //default value, enable clock source to T1

    _T1IP = 7; //highest priority

    _T1IF = 0;

    _T1IE = 1; //enable T1 interrupt


}


int main(void)

{

    IC_Initialize();


    LED_TRIS =0;

    LED_ON();

    T1CONbits.TON =1; //T1 start

    while(1);


    return 0;

}


void __attribute__ ((__interrupt__, no_auto_psv)) _T1Interrupt(void)

{

    if(++ledTriggerCount == TIME_TEN_MICROSECOND){

        ledTriggerCount = 0;

        LED_TRIGGER();

        if(++oscillatorSwitchCount == 2){

            oscillatorSwitchCount = 0;

            IC_ClockSwitch(~OSCCONbits.COSC&0x01);//switch clock mode between FRCPLL and FRC

        }

    }

    _T1IF = 0;

}


里面的代码“IC_ClockSwitch(~OSCCONbits.COSC&0x01);”与下面代码功能一样:


if(OSCCONbits.COSC == 0b001)

    IC_ClockSwitch(0x00); //FRCPLL -> FRC

else

    IC_ClockSwitch(0x01); //FRC -> FRCPLL

CW2

OSCCON

CLKDIV

OSCTUN


关键字:PIC  振荡器配置  时钟切换 引用地址:PIC振荡器配置与时钟切换

上一篇:Pic18F25K80 16位模式下的定时器0配置
下一篇:PIC单片机延时问题

推荐阅读最新更新时间:2024-03-16 16:10

PIC单片机之PIC16F884
buck电路 这是一个降压电路,SW 在此处通入PWM ,进行降压的主要工作,Vout分压后,最高不超过芯片工作电压 (5V 也行 )输入到PIC AN1口,进行AD转换, 将转换的结果在1602上显示出来。如果电压不是想要的电压 程序便改变PWM的占空比,以达到需要的值。 主要环节在1602 的初始化 写数据 和写指令 以及 PIC的AD启动工作模块,程序如下 #include __CONFIG(0x201A); #define uint unsigned int #define uchar unsigned char #define rs RC4 //数据命令 #define en
[单片机]
<font color='red'>PIC</font>单片机之<font color='red'>PIC</font>16F884
PIC单片机】-- 介绍和基本I/O–按钮和LED
00 写在前面 该系列的文章,源自于担任过PIC单片机课程的助教,主要向学弟们讲解了几节实验课的内容。在此记录上课的一些知识。 本系列文章主要介绍的内容: 实验1–介绍和基本I/O–按钮和LED(学习嵌入式的第一步就是点一个灯,就像学习编程语言的第一步都是写一个“hello world”代码) 实验2–MPLAB+PICkit 3+LCD+I/O(这次主要是介绍液晶显示屏的使用,很多时候我们系统的调试都需要用到,比如做一个测温系统,那我们就可以通过液晶显示屏,显示传感器采集的数值,然后再通过软件来做进一步的处理) 实验3–ADC(这个是模数转化实验,就是之前模数电学习那些知识的一个综合运用) 实验4–串行通信–
[单片机]
【<font color='red'>PIC</font>单片机】-- 介绍和基本I/O–按钮和LED
51,PIC,AVR单片机的对比
1. 传统51 传统51,我想我就不多说了,适合菜鸟入门,容易上手,价格一般(从性价比方面说)。 缺点:解密容易(传统51说:谁让咱出道早呢,大家都研究我,哎!哭......)一般功能也有,, 但AD、eeprom等功能要靠扩展,增加硬件和软件负担。 IDE环境推荐 keil。 2. PIC PIC的好处就是各个型号的兼容性强,学好了PIC16f877a,16系列的就OK了,别的型号要用的时候拿出2分钟看看数据手册就行了。12系列,16系列,18系列也是充分的向下兼容。功能全,型号多,适于选型分析,抗干扰能力强 缺点:解密容易(pic说:我出道也很早啊,人家也研究我不少年了,我和奥尼
[单片机]
PIC16F877 I/O口特色
1.PORTA 总共有6个位(RA0~RA5),PORTA端口模块有3个特殊的寄存器:端口数据寄存器PORTA,端口方向控制寄存器TRISA,A/D转换控制寄存器ADCIN1;PORTA端口各引脚的所复合的功能相同,各引脚的内部结构也不一致。对三个寄存器的设置可控制PORTA端口作为数字I/O端口的应用,而系统重置后,PORTA自动成为模拟输入状态,可读取模拟输入讯号; PORTB 是8位宽度的数字I/O端口(RB0~RB7),一般只有RB6和RB7两个引脚存在复用功能,它们在芯片编程烧写和在线调试时,RB6作为编程串行时钟引脚PGC,RB7作为编程串行数据引脚PGM,这是一种特殊模式的功能复用类型,它不可能出现在芯片正常工作时。P
[单片机]
PIC的单片机功耗问题
最近一周一直在做pic单片机功耗问题。由于项目使用电池供电,所以功耗问题显得非常重要。根据数据手册以及网络上的资料,影响单片机功耗主要由以下几个因素: 1:所有I/O引脚保持为高阻输入高点平或低电平 2:关闭比较器和CVref(可编程偏上参考电压)、WTD、T1OSC、BOR(欠压复位)等 3:PORTB片内弱上拉 4:所有不用的模块全部关闭,在用到时再打开 5:MCLR引脚必须处于逻辑高电平 PIC单片机在执行SLEEP指令后进入睡眠省电模式。进入SLEEP模式后,主振荡停止,如果看门狗在烧写时打开了,看门狗定时器将被清并保持运行。I/O口,周边模块和内部RAM将保持原来状态,所以如果要求睡眠后有很低功耗,应该在进入SL
[单片机]
PIC单片机的快速入门指南
  PIC16F616是一款14引脚、8位的CMOS单片机。采用精简指令集,仅有35条指令,由于采用了数据总线和指令总线分离的哈佛总线结构,使得除少量指令不是单周期之外,大部分的指令都是单周期指令。这样有利于提高单片机的运行速度和执行效率。   PIC16F616这款单片机供电电压可以在2V到5.5V之间,内部集成了一个RC振荡器,频率可以配置成8MHZ或者4MHZ,也可以用外部晶振提供时钟。内部集成有AD转换、比较器等硬件模块,还具有上电复位、欠压复位、看门狗、代码保护等功能。三个定时器、PWM发生器等可以由用户编程。下面我来一一介绍关于PIC单片机的这些模块和功能。   1.存储器   PIC16F616分为程序存储其
[单片机]
PIC单片机】-- 中断、定时器相关知识
00 写在前面 该系列的文章,源自于担任过PIC单片机课程的助教,主要向学弟们讲解了几节实验课的内容。在此记录上课的一些知识。 本系列文章主要介绍的内容: 实验1–介绍和基本I/O–按钮和LED(学习嵌入式的第一步就是点一个灯,就像学习编程语言的第一步都是写一个“hello world”代码) 实验2–MPLAB+PICkit 3+LCD+I/O(这次主要是介绍液晶显示屏的使用,很多时候我们系统的调试都需要用到,比如做一个测温系统,那我们就可以通过液晶显示屏,显示传感器采集的数值,然后再通过软件来做进一步的处理) 实验3–ADC(这个是模数转化实验,就是之前模数电学习那些知识的一个综合运用) 实验4–串行通信–UA
[单片机]
【<font color='red'>PIC</font>单片机】-- 中断、定时器相关知识
PIC单片机实现音乐播放的实例程序
PIC单片机实现音乐播放的实例程序 ******************************** * PIC单片机实现音乐播放 * ******************************** 源程序: 以下程序要用二个定时器资源,凡是有二个定时器的PIC单片机均可实现,该范例需要的MCU是MICROCHIP PIC16C62 INCLUDE "D:PICP16XX.EQU" ;该文件在MICROCHIP光盘中可找到 ;************************************************** #define BeepOut RC,4 ;**********************
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved