这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取逻辑分析仪】+STC32G12K128不同时钟源的精度表现

共5条 1/1 1 跳转至

【换取逻辑分析仪】+STC32G12K128不同时钟源的精度表现

专家
2024-11-14 19:50:50   被打赏 45 分(兑奖)     打赏

前面介绍过STC32G12K128的时钟系统使用的几种时钟源。接下来,我使用不同的时钟源测试时钟的精度,思路是,使用不同的时钟源,利用定时器计数,在GPIO口输出脉冲信号,然后测量脉冲信号的周期,看看差异以及与预想的是否一致来做比较。对于使用外部晶振的情况,因为受控于外部晶振的精度,所以不作为本次测试的内容。

下面是测试的三种分支。

测试代码:

/*************  功能说明    **************

 

使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。

 

edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。

 

切换时钟源,分别是默认IRC主频,主频24分频,PLL 96M 16分频,内部32K IRC。

 

下载时, 选择时钟 24MHz (用户可自行修改频率).

 

******************************************/
 
#include "STC32G.h"
 
#include "stdio.h"
#include "intrins.h"
 
typedef  unsigned char u8;
typedef  unsigned int u16;
typedef  unsigned long u32;
 
#define MAIN_Fosc        24000000UL
#define Timer4_Reload   (MAIN_Fosc / 5000)      //Timer 4 中断频率, 5000次/秒
 
/****************************** 用户定义宏 ***********************************/
 
/*****************************************************************************/
 
/*************  本地常量声明    **************/
 
#define CKMS            0x80
#define HSIOCK          0x40
#define MCK2SEL_MSK     0x0c
#define MCK2SEL_SEL1    0x00
#define MCK2SEL_PLL     0x04
#define MCK2SEL_PLLD2   0x08
#define MCK2SEL_IRC48   0x0c
#define MCKSEL_MSK      0x03
#define MCKSEL_HIRC     0x00
#define MCKSEL_XOSC     0x01
#define MCKSEL_X32K     0x02
#define MCKSEL_IRC32K   0x03
 
#define ENCKM           0x80
#define PCKI_MSK        0x60
#define PCKI_D1         0x00
#define PCKI_D2         0x20
#define PCKI_D4         0x40
#define PCKI_D8         0x60
 
 
void    Timer4_init(void);
 
 
/*************  本地变量声明    **************/
u8 mode = 0;
 
/*************  本地函数声明    **************/
void  delay_ms(u8 ms);
void  MCLK_Sel(void);
 
/********************* 主函数 *************************/
void main(void) {
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度
 
    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0xff;   P6M0 = 0xff;   //设置为漏极开路(实验箱加了上拉电阻到3.3V)
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
 
    EA = 1;     //打开总中断
    
    Timer4_init();
    
    //MCLK_Sel();
    while(1) {
        if (P20 == 0) {
            delay_ms(20);
            if (P20 == 0) {
                P65=0;
                while(P20 == 0);
                P65=1;
                
                mode = (mode+1)%4;
                MCLK_Sel();
                
                if (mode==0) {
                    P60=1;
                    P61=1;
                } else if (mode==1) {
                    P60=0;
                    P61=1;
                } else if (mode==2) {
                    P60=1;
                    P61=0;
                } else if (mode==3) {
                    P60=0;
                    P61=0;
                }
            }
        }
    }
}
 
//========================================================================
// 函数: void MCLK_Sel(void)
// 描述: 系统时钟设置函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2020-7-29
// 备注: 
//========================================================================
void MCLK_Sel(void) {
    if(mode == 0) {
        HIRCCR = 0x80; //启动内部 IRC
        while (!(HIRCCR & 1)); //等待时钟稳定
        CLKDIV = 0;
        CLKSEL = 0x00; //选择内部 IRC ( 默认 )
    
    } else if(mode == 1) {
        HIRCCR = 0x80; //启动内部 IRC
        while (!(HIRCCR & 1)); //等待时钟稳定
        CLKDIV = 24;   //MCLK/24
        CLKSEL = 0x00; //选择内部 IRC ( 默认 )
    
    } else if(mode == 2) {
        CLKSEL &= ~CKMS;            //选择PLL的96M作为PLL的输出时钟
        USBCLK |= PCKI_D2;          //输入时钟2分频(选择PLL输入时钟分频,保证输入时钟为12M)
        //启动PLL
        USBCLK |= ENCKM;            //使能PLL倍频
        delay_ms(1);                //等待PLL锁频
        CLKDIV = 16;                //主时钟选择高速频率前,必须先设置分频系数,否则程序会当掉
 
        CLKSEL &= ~MCKSEL_MSK;
        CLKSEL &= ~MCK2SEL_MSK;
        CLKSEL |= MCKSEL_HIRC;      //选择内部高速IRC作为主时钟
        CLKSEL |= MCK2SEL_PLLD2;    //选择PLL输出时钟2分频后的时钟作为主时钟
    
    } else if(mode == 3) {
        IRC32KCR = 0x80; //启动内部 32K IRC
        while (!(IRC32KCR & 1)); //等待时钟稳定
        CLKDIV = 0x00; //时钟不分频
        CLKSEL = 0x03; //选择内部 32K
    }
}
 
//========================================================================
// 函数: void Timer4_init(void)
// 描述: timer4初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void Timer4_init(void) {
        T4R = 0;    //停止计数
 
    #if (Timer4_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
        #error "Timer4设置的中断过快!"
 
    #elif ((Timer4_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
        ET4 = 1;    //允许中断
        T4_CT = 0;  //定时
        T4CLKO = 0; //不输出时钟
 
        #if (Timer4_Reload < 65536UL)
            T4x12 = 1;    //1T mode
            T4H = (u8)((65536UL - Timer4_Reload) / 256);
            T4L = (u8)((65536UL - Timer4_Reload) % 256);
        #else
            T4x12 = 0;    //12T mode
            T4H = (u8)((65536UL - Timer4_Reload/12) / 256);
            T4L = (u8)((65536UL - Timer4_Reload/12) % 256);
        #endif
 
        T4R = 1;    //开始运行
 
    #else
        #error "Timer4设置的中断过慢!"
    #endif
}
 
//========================================================================
// 函数: void timer4_int (void) interrupt TIMER4_VECTOR
// 描述:  timer4中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer4_int(void) interrupt 20 {
    P67 = ~P67;
    P27 = P67;
}


代码中使用了STC原厂提供的改变时钟源的代码。

1、使用内部高精度 IRC不分频

图片19.png 

测出的定时周期为198.456us,理论值应该是200us误差为0.772%

2、使用内部高精度 IRC24分频

图片20.png 

测出的定时周期为4.783ms,理论值应该是4.8ms,误差约0.354%。

 

3、使用PLL时钟,16分频

图片21.png

测出的定时周期为1.585ms,理论值应该是1.67ms,误差为5.090%。

4、使用内部 32KHz 的 IRC不分频

图片22.png

测出的定时周期为135.139ms,理论值应该是152.58ms,误差约为11.431%

从以上的测试结果上看,使用内部有RC构成的32.768KHz的时钟源,误差是最大的。其次是内部PLL输出,也挺大,达到5%。总体来说内部高精度IRC时钟还是比较靠谱的,误差很小,不到1%。

通过这次测试,对于单片机的时钟源的选择上的相关知识有了实际认识。涉及数据计算的部分,理解可能还有不到位的地方,期待大佬指正。 

测试工程包:STC32时钟源.zip

 



专家
2024-11-28 14:15:26     打赏
2楼

这个坛主确实有想法,我们在工程中也碰到了,最后选择了外部时钟。


专家
2024-11-29 21:08:13     打赏
3楼

没有准确的时钟,定时器之类的处理就不准了,普通软件也许问题不大,工业用、车用、商用的,可能会造成严重后果。


助工
2024-11-29 22:27:38     打赏
4楼

蓝牙蘋偏,好像也是调的时钟


院士
2024-12-03 15:24:28     打赏
5楼

5%的精度 是串口通讯的官方临界值了。

不过,我倒是没有试过


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]