PIC单片机时钟详解

最近在学PIC单片机,因此尝试写一篇文章记录一下。

单片机的型号为dsPIC33FJ16GS502,编辑器为MPLAB X IDE V6.00,编译器为:VC16 V2.00,这些工具都可以在Microchip的官网上可以下载安装。

1.时钟系统框图

  首先来看一下单片机是时钟框图:

  可以看到系统的时钟源可以来自3个部分:主振荡器、内部RC振荡器、内部低功耗RC振荡器.

  而如何选择这些时钟作为系统时钟则是通过FOSCSEL寄存器的FNOSC位实现,其寄存器的功能如下:

  那如何通过代码来实现对时钟的切换呢?常用的方法是在预编译指令设置,对相应的寄存器赋值即可。

  以内部FRC振荡器为例,一行即可:

1 #pragma config FNOSC = FRCPLL           //带PLL的快速RC振荡器(FRCPLL)
  这个寄存器有什么用呢?可见用户手册:

  而如何设置寄存器的值呢?

  有两种方法:

    一种是查看用户手册;

    一种是查看对应的头文件;在默认安装的情况下,头文件的路径为:

    C:\Program Files (x86)\Microchip\xc16\v1.36\support\dsPIC33F\h\p33FJ16GS502.h

  主振荡器的XT,HS,EC都是什么模式呢?

  查看手册后可以得知:

  细心的小伙伴可能,发现了系统框图中下边还有附属时钟(Auxiliary Clock),他是不可以作为系统时钟源的,其主要的功能是供给ADC模块和PWM模块的时钟,后面会做详细的介绍。

  大概了解了系统时钟,本文下面将对每部分进行详细的讲解。

2.主振荡器

  主振荡器就是采用外部晶振作产生时钟信号,本文的外部晶振为7.3728MHz,选取主振荡器作为系统时钟,主要有两条路径:

 2.1 主振荡器方案

  路径1的配置较为简单,通过预编译指令即可,见代码:

1 // FOSCSEL
2 #pragma config FNOSC = PRI           //振荡器模式(不带PLL的XT)
3 #pragma config IESO = ON                //内部外部切换模式(使用FRC启动设备,然后自动切换到用户选择的振荡器源)
4 // FOSC
5 #pragma config POSCMD = XT            //主振荡器源(主振荡器XT) 
6 #pragma config OSCIOFNC = OFF           //OSC2引脚功能(OSC2引脚有时钟输出功能)
7 #pragma config IOL1WAY = ON             //外设引脚选择配置(只允许一次重新配置)
8 #pragma config FCKSM = CSDCMD           //时钟切换和监视器(无论时钟切换和故障保护时钟监视器被禁止)

   由此可见经过上述一系列配置,达成的效果为:禁止时钟切换,禁止故障保护始终监视器,OSC2为数字IO引脚,选择主振荡器晶振模式作为系统时钟源。

  经过上述配置Fosc = 7.3728MHz,其时钟频率由外部晶振决定。

 2.1.2 主振荡器锁相环方案

  路径2的配置过程较为麻烦,因为还需配置PLL,但是基本配置方法类似,见代码:

1 // FOSCSEL
2 #pragma config FNOSC = PRIPLL            //振荡器模式(带PLL的XT)
3 #pragma config IESO = ON                //内部外部切换模式(使用FRC启动设备,然后自动切换到用户选择的振荡器源)
4 // FOSC
5 #pragma config POSCMD = XT            //主振荡器源(主振荡器XT) 
6 #pragma config OSCIOFNC = OFF           //OSC2引脚功能(OSC2引脚有时钟输出功能)
7 #pragma config IOL1WAY = ON             //外设引脚选择配置(只允许一次重新配置)
8 #pragma config FCKSM = CSDCMD           //时钟切换和监视器(无论时钟切换和故障保护时钟监视器被禁止)

  发现其与路径1的区别只在第2行寄存值的改变,此时选择带PLL锁相环的路径故还需了解锁相环,以便计算相关频率。锁相环的框图在用户手册中如下:

  其频率的计算公式为:

  可以看到,PLL锁相环的输出与三个参数有关:PLLDIV,PLLPRE,PLLPOST。因此只要配置这三个参数即可得到我们想要的频率,常用的代码配置如下:

1     CLKDIVbits.PLLPRE = 0;//N1 = 2  7.3728MHz/2= 3.6864MHz
2     PLLFBDbits.PLLDIV = 41;//M = 43  3.6864*43 = 158.5152MHz
3     CLKDIVbits.PLLPOST = 0;//N2 = 2 158.5152/2 = 79.2576MHz

  经过上述配置,Fosc = 79.2567MHz,时钟频率范围变化较大,可以在80MHz以下按照需要配置。

  采用外部晶振作为是时钟源有着稳定性较高的优点,但是考虑的经济性,外部晶振相对与内部振荡器而言,经济性较差,故在对经济性敏感的产品中常采用内部晶振。

3.内部RC振荡器

  此款单品的内部RC振荡器为7.3728MHz,速度快,成本低。其主要有4条路径:

  四条路径的输出频率范围见表:

路径 频率(MHz)
1 <80MHz
2 0.46MHz~7.37MHz
3 0.46MHz
4 7.37Mhz

 3.1 FRC和FRCDIV16方案

  路径3,4设置比较简单,仅需设置一个寄存器即可,见代码:

1 #pragma config FNOSC = FRC             // FRC 模式
2 #pragma config FNOSC = FRCDIV16   // FRC的16分频

 3.2 FRCDIV方案

  路径2的设置也相对简单,除设置时钟选择寄存器外,还需设置FRC分频寄存器FRCDIV,寄存器与具体分频系数见图:

   具体配置见代码

1 #pragma config FNOSC = FRCDIV  

  主程序代码:

1 void FRCDIV_Init(void)
2 {
3     CLKDIVbits.FRCDIV = 0; // 1分频
4 }

 3.3 FRCPLL方案

  路径1需要经过PLL锁相环,其频率可以上升的更高,当然配置麻烦一点,见代码:

1 #pragma config FNOSC = FRCPLL           //带PLL的快速RC振荡器(FRCPLL)

  PLL配置程序:

1 void System_Colck(void)
2 { 
3     CLKDIVbits.PLLPRE = 0;//N1 = 2  7.3728MHz/2= 3.6864MHz
4     PLLFBDbits.PLLDIV = 41;//M = 43  3.6864*43 = 158.5152MHz
5     CLKDIVbits.PLLPOST = 0;//N2 = 2 158.5152/2 = 79.2576MHz
6 }

  经过上述配置,其时钟频率为79.2576MHz。

4.低功耗RC振荡器

  低功耗RC时钟一般供给看门狗定时器,上电延时定时器和故障保护定时器使用。一般不作为系统主时钟,故不再描述如何配置配置,有需要的小伙伴可以自行探索。

5.附属时钟

  附属时钟是高速10位ADC和高速PWM的时钟源,其最高可达到120MHz的频率。

  其配置相对较为简单,照着框图,写寄存器就好了,框图如下:

 

   可以看到附属时钟源的时钟来源有三个:主振荡器,主振荡器经PLL锁相环,内部RC振荡器。

  本文以内部RC振荡器为例,给出配置代码如下:

 1 /*
 2  * 函数功能:附属时钟ACLK初始化
 3  * 注意事项:附属时钟的最大输出频率为:7.37 * 16 = 117.92MHz
 4  * 参数说明:ACLK_Div:分频系数
 5  *           参数 7   6   5   4   3   2   1   0
 6  *         分频比 1   2   4   8   16  32  64  256
 7  */
 8 void ALCK_Init(unsigned char ACLK_Div )
 9 {
10     ACLKCONbits.ASRCSEL = 0 ; // Don't select any clock as ACLK input
11     ACLKCONbits.FRCSEL = 1 ; // Select FRCCLK as ACLK input
12     ACLKCONbits.ENAPLL = 1 ; // Enable Auxiliary PLL
13     ACLKCONbits.SELACLK = 1 ;// Auxiliary PLL Clock Provides the Clock sourse
14     ACLKCONbits.APSTSCLR = ACLK_Div ;// Set Divide Auxiliary colck by 1
15     while(ACLKCONbits.APLLCK != 1); // Wait for Auxiliary PLL to ready
16 }

  代码较为简单,清晰明了,不再进行解读啦。

6.总结:

  至此PIC单片机的时钟系统大部分已经解读完毕了,还有一些剩余部分,后期可能会有补充。

  本人第一篇文章,文笔青涩,如有错误,欢迎指出。未经允许,禁止转载。

 
 
posted @ 2022-09-17 21:42  巨巨巨兔  阅读(811)  评论(0)    收藏  举报