历史上的今天
返回首页

历史上的今天

今天是:2024年10月18日(星期五)

正在发生

2021年10月18日 | 看懂时钟树——掌握系统时钟配置

2021-10-18 来源:eefocus

——基于STM32F107VCT6的理解

1、HIS(内部高速时钟:8MHZ)

内部高速时钟是芯片自带的时钟,芯片自带时钟有两个HIS和LSI(内部低速时钟:40kHZ),内部时钟是RC振荡器产生的,不够稳定。一般不长时间作为系统时钟使用,一般做备用,或在切换时使用。


2、HSE(外部高速时钟:3-25MHZ)

STM32提供两组外部时钟接口,HSE和LSE(外部低速时钟)。外部时钟的大小由外部所接晶振确定(本文HSE=25MHZ,LSE=32.768kHZ),所以较为准确。


3、时钟树看图引导

从图中可知SYSCLK(系统时钟)的来源可以是SHE、SHI和PLLCLK(分频器1),这里通过SW(两位二进制数00、01、10、11)来选择,具体可参考《STM32F10xxx参考手册》第88页,CSS的作用是用来检测HSE是否正常的。HSE和SHI都是固定不变的(硬件不变的情况下),所以想要设置不同的时钟频率出来一般选择PLLCLK作为系统时钟。PLLCKL的时钟源有3中不同的情况:(1)SHI经过2分频,经过PLLSCR选择(一位二进制数:0选择图中上面的路线,1选择下面路线);(2)SHE经过PREDIV1SCR选择(0选择上面路线,1选择下面路线),在经过PREDIV1(分频器1),再经过PLLSCR选择;(3)SHE经过PREDIV2分频,进入PLL2MUL倍频,经过PREDIV1SCR选择(0选择上面路线,1选择下面路线),在经过PREDIV1(分频器1),再经过PLLSCR选择。三种情况如下:

对于情况(1)和(2)产生的的时钟频率相对较少,有多种的情况都不能产生,而情况(3)则有多种选择,不能产生的频率,也可以产生一个误差小于0.1MZH与目标频率相近的评率。本文采用(3)这条路线。


4、设计步骤

(1)、切换内部时钟:SHI使能(SHION写1)、等待SHI稳定(SHIDRY被硬件置1)、系统时钟切换为内部时钟(SW写00)、等待切换成功(SWS被硬件置00);


说明:若某条线路被作为了SYSCLK,则改线路的所有的配置都不能被更改,只能暂时切换到其他路线。SHI只有被使能了才能切换成功。


(2)、配置相关分频、倍频系数。关闭PLL2,PLL使能(PLLON、PLL2ON写0)选择PREDIV2、PREDIV1的分频系数,选着PLLMUL2、PLLMUL的倍频系数,PREDIV1SCR、PLLSCR的时钟源;打开SHE(SHEON写1),等待SHE稳定(SHERDY被硬件写1),打开PLL2,PLL使能(PLLON、PLL2ON写1),等待准备就绪(PLLRDY、PLL2RDY被硬件写1);


(3)、SYSCLK切换成PLLCLK。SYSCLK由SHI切换成PLLCLK(SW写10),等待切换成功(SWS被置为10)


5、程序设计(系统时钟设置子函数)

方案一:通过运算得到与目标频率最相近的分频、倍频方案,并进行设置。


优点:只要改变带入参数的类型,可计算产生小数的频率;


缺点:每次都要进行计算,运算量大,要时间计算;


//1、寄存器的声明定义(只声明用到的)

#define RCC_CR       *(uint32_t *)0x40021000

#define RCC_CFGR     *(uint32_t *)0x40021004

#define RCC_CFGR2    *(uint32_t *)0x4002102c

 

/**********************************

//重设系统时钟函数

//可设置范围:4-72MHZ

//带入参数:  需要设置的系统时钟频率

//带入参数类型:int

//返回值:实际设置的成的系统时钟频率

//注意事项:

//1、低于4MHZ的不能设置,程序在

// while((RCC_CR & 0x0a000000) != 0x0a000000 );死循环

//2、高于72MHZ系统时钟设置为72MHZ

***********************************/

double ResetSysClK(int Sysclk_Value)

{

unsigned char PLLMUL,PLLMUL2,M1,M2,D1,D2;

unsigned int DIV1,DIV2;

double clk_set,clk_temp,abs_clk_temp,abs_clk_min = 72.0;

float    MUL[7]       = {4,5,6,7,8,9,6.5};

float    MUL2[9]      = {8,9,10,11,12,13,14,16,20};

unsigned int MUL_Code[7]  = {2,3,4,5,6,7,13};

unsigned int MUL2_code[9] = {6,7,8,9,10,11,12,14,15};

for(M1 = 0;M1 < 7;M1++) //PLLMUL[8]

for(M2 = 0;M2 < 9;M2++)//PLL2MUL

for(D1 = 1; D1 < 17;D1++)//PREDIV1[16]

for(D2 = 1;D2 < 17 ;D2++)//PREDIV1[16]

{

//计算当前组合的时钟频率

clk_temp = (25.0*MUL[M1]*MUL2[M2]) / ((double)D1*(double)D2);

//时钟频率在1-72MZH的组合计进入判断

if(  clk_temp<=72.0 && clk_temp >=1.0 )

{

//计算当前组合与想要得到的时钟频率差

abs_clk_temp = Sysclk_Value - clk_temp;

//若当前组合产生的时钟频率就是想要的时钟频率

//则不用继续遍历后面的组合,跳出所有循环

if(abs_clk_temp == 0.0)

{

clk_set = clk_temp;

PLLMUL  = M1;

PLLMUL2 = M2;

DIV1    = D1;

DIV2 = D2;

M1 = M2 = 10;

D1 = 20;

break;//只能跳出最小的循环

}

if(abs_clk_temp < 0.0)

abs_clk_temp = (-abs_clk_temp);

//遍历所有组合找出时钟频率组合与目标时钟频率相差最小的组合

if(abs_clk_temp < abs_clk_min)

{

//保留当前更合适的组合

abs_clk_min = abs_clk_temp;

clk_set = clk_temp;

PLLMUL  = M1;

PLLMUL2 = M2;

DIV1    = D1;

DIV2 = D2;

}

}

}

//HSI时钟使能

RCC_CR = ((RCC_CR | 0x00000001));

//延时直到HSI准备就绪

  while((RCC_CR & 0x00000002) == 0);

//切换内部时钟HSI

RCC_CFGR = (RCC_CFGR & 0xfffffffc);

while((RCC_CFGR & 0x0000000c) != 0);

//HSE使能(打开)

RCC_CR = (RCC_CR & 0xfffeffff)|0x00010000;

while((RCC_CR & 0x00020000) != 0x00020000);

//关闭PLLON和PLL2ON

RCC_CR = (RCC_CR & 0xf0ffffff);

//设置MUL的倍率、PLLSRC(选择PREDIV1输出作为PLL输入时钟)

RCC_CFGR = (RCC_CFGR&0xffc1ffff)|0x00010000|(MUL_Code[PLLMUL]<<18);

//设置MUL2、DIV2、DIV1、PREDIV1SRC(PLL2作为PREDIV1的时钟源)

RCC_CFGR2 = (RCC_CFGR2 & 0xfffef000)|0x00010000|( MUL2_code[PLLMUL2]<<8)|( (DIV2-1)<<4 )|(DIV1-1);

//PLL、PLL2使能

RCC_CR |= 0x05000000;

/* Wait till PLL2 and PLL is ready */

  while((RCC_CR & 0x0a000000) != 0x0a000000 );

/* Select PLL as system clock source */

  RCC_CFGR |= 0x00000002;    

  /* Wait till PLL is used as system clock source */

  while ((RCC_CFGR & 0x00000008) != (uint32_t)0x08);  

return clk_set;

}

 


方案二:预先将能4-72MHZ的整数频率的最佳方案计算出来,放入数组。


优点:可以直接通过查表得到分频倍频信息,不用计算运行时间短;


缺点:只能输入只能是4-72的整数。代码量较多。


#define *RCC_CR       (uint32_t *)0x40021000

#define *RCC_CFGR     (uint32_t *)0x40021004

#define *RCC_CFGR2    (uint32_t *)0x4002102c

 

//对应位的编码数组

//其二进制码经过位移合并到相应位就可以了

//顺序:MUL_Code、MUL2_Code、DIV1_Code、DIV2_Code

int data[69][4] = {

{2,      7,      14,     14,},

{2,      6,      9,      15,},

{2,      7,      9,      14,},

{5,      7,      14,     14,},

{2,      6,      9,      9,},

{2,      7,      9,      9,},

{2,      6,      4,      15,},

{2,      9,      9,      9,},

{2,      7,      4,      14,},

{2,      11,     9,      9,},

{2,      12,     9,      9,},

{2,      7,      3,      14,},

{2,      6,      4,      9,},

{5,      12,     8,      15,},

{2,      7,      4,      9,},

{7,      11,     10,     13,},

{2,      6,      3,      9,},

{4,      12,     9,      9,},

{2,      9,      4,      9,},

{7,      7,      7,      10,},

{2,      10,     4,      9,},

{2,      6,      1,      15,},

{2,      11,     4,      9,},

{4,      7,      4,      9,},

{2,      12,     4,      9,},

{3,      11,     3,      13,},

{2,      7,      1,      14,},

{2,      11,     2,      13,},

{2,      6,      4,      4,},

{4,      9,      4,      9,},

{5,      12,     5,      11,},

{2,      12,     3,      9,},

{2,      7,      4,      4,},

{5,      9,      3,      12,},

{7,      11,     6,      10,},

{4,      11,     4,      9,},

{2,      6,      1,      9,},

{2,      14,     2,      12,},

{4,      12,     4,      9,},

{3,      9,      1,      15,},

{2,      9,      4,      4,},

{2,      7,      1,      9,},

{7,      7,      3,      10,},

{13,     11,     2,      14,},

{2,      10,     4,      4,},

{5,      12,     4,      9,},

{2,      6,      0,      15,},

{3,      15,     6,      6,},

{2,      11,     4,      4,},

{3,      12,     2,      10,},

{4,      7,      4,      4,},

{2,      9,      1,      9,},

{2,      12,     4,      4,},

{5,      11,     3,      9,},

{3,      11,     1,      13,},

{4,      9,      1,      13,},

{2,      7,      0,      14,},

{4,      11,     1,      15,},

{2,      11,     2,      6,},

{5,      7,      4,      4,},

{2,      14,     4,      4,},

{2,      11,     1,      9,},

{4,      9,      4,      4,},

{3,      12,     1,      12,},

{5,      12,     2,      11,},

{5,      11,     2,      10,},

{2,      12,     1,      9,},

{5,      11,     1,      15,},

{4,      10,     4,      4,},

};

//实际设置成功的频率数组

//与上面一一对应

float set_clk[69]={

4.000000,       5.000000,       6.000000,       7.000000,       

8.000000,       9.000000,       10.000000,      11.000000,      

推荐阅读

史海拾趣

Arco Electronics公司的发展小趣事

近年来,电子行业面临着技术更新换代快、市场竞争激烈等挑战。Arco Electronics公司敏锐地捕捉到了这些变化,及时调整了公司的战略方向。公司加大了对新兴技术的研发投入,如物联网、人工智能等领域,以保持技术上的领先地位。同时,公司还通过优化生产流程、提高产品质量等方式来降低成本,增强市场竞争力。

台湾町洋(dinkle)公司的发展小趣事

为了进一步扩大市场份额,町洋开始进军国际市场。公司凭借其优质的产品和服务,逐渐在欧美等发达国家和地区打开了市场。为了更好地服务全球客户,町洋在全球设立了多个贸易与服务机构,构建了完善的销售网络和售后服务体系。

芯联(CHIPLINK)公司的发展小趣事

在芯片短缺的大背景下,一家名为芯联集成的公司凭借其敏锐的市场洞察力和快速响应能力,迅速调整战略,专注于车规级IGBT芯片和模组的代工生产。公司凭借高效的生产能力和严格的质量控制,迅速获得了多家头部新能源车企的认可,成为他们的合作伙伴。这一举措不仅帮助芯联集成度过了行业低谷,还使其在短时间内实现了跨越式发展。

Cedrat Technologies公司的发展小趣事

Cedrat Technologies深知技术创新的重要性,因此一直致力于打造一支跨学科的研发团队。这支团队由材料科学、机械工程、电子工程等多个领域的专家组成,他们共同致力于智能材料机电产品的研发和应用。通过多年的努力,团队在微型纳米定位、阻尼、振动产生等领域取得了显著成果,为公司的快速发展提供了强大的技术支撑。

Caliber公司的发展小趣事

Caliber公司自创立之初,便以技术创新为核心竞争力。在电子行业的早期,该公司敏锐地捕捉到市场对高性能计算芯片的需求,投入大量资源进行研发。经过数年的努力,Caliber成功推出了一款具有划时代意义的芯片产品,以其出色的性能和稳定性赢得了市场的广泛认可。这一创新不仅为Caliber带来了巨大的商业成功,也为整个电子行业的发展注入了新的活力。

DYMO公司的发展小趣事

近年来,DYMO公司越来越注重环保和可持续发展。公司采用环保材料制造产品,并推广循环使用和回收计划。此外,DYMO公司还积极参与各种环保活动,致力于减少生产过程中的碳排放和废弃物排放。这些举措不仅提高了DYMO公司的社会形象,也为其未来的发展奠定了更加坚实的基础。

问答坊 | AI 解惑

自己待完善的技术工作经验体系

1、电子技术资料尽量看西方英文原版的      理由:电子技术发源于西方,那边的人对许多电路问题有很深的认识,研究的很细,条理很清晰,对产品开发的指导性强。尽管国内也有人在研究,但有真正指导生产意义的刊物太少,市面上 ...…

查看全部问答>

请问为啥pc不能引导ce。image section doesn't fit in allocated block

下载了VM虚拟机。和研博loadcepc 【2.2】 和nk.bin 【2.2】 把虚拟硬盘格成FAT格式 把研博的DOS引导部分解压到c:把loadcepc和nk.bin复制到c: 硬盘开机 看到研博的开机画面了 大概到百分90的时候 出现错误   Error   image ...…

查看全部问答>

基于proteus的喇叭的应用实例或单片机实现的音乐贺卡

单片机实现类似音乐贺卡的功能,自己选择一段音乐用单片机驱动喇叭播放出来,…

查看全部问答>

ClearCommError问题

COMSTAT ComStat ClearCommError(m_hCom,&dwErrorFlags,&ComStat); 这个函数用于清除硬件错误和获取状态(我是的重叠操作) 我WriteFile后,ReadFile前怎么这个结构的cboutbuf永远是0,为什么不是我写入的字节 单步调试N此不知为何?恭请高手解 ...…

查看全部问答>

急~,linux高手,帮我解决在linux上安装ADS??

   linux高手,帮我解决在linux上安装ADS,我用的是red hat .25 的,在那里有下支持linux  ads的!!谢谢了!没用的话,谁能告诉我,在linux下有什么样的ARM编译器!!!…

查看全部问答>

请问有人做过GPU?

有没有人设计过GPU?我想看看这方面的资料,可不可以告知一下,或者给个资料的地址也可以! 谢谢! 只要资料好,分不够可以加分!…

查看全部问答>

at88sc0104加密芯片里的一段代码,请高手指点啊

这是初始化的一段代码,我初始化后,再往芯片发送随机数就不成功,我怀疑是初始化后熔断了熔丝造成的, 熔丝代码: ucData[0]= (uchar)CM_FAB;         ucReturn = cm_BurnFuse(ucData[0]);         i ...…

查看全部问答>

机顶盒界面开发咨询

请问各位大侠如何做比较酷的机顶盒界面(比如说立体按钮)? 用C或C++. 只能自己画吗? 有什么注意的地方? 谢谢了 …

查看全部问答>

STM8与51核变更定义区域比较(转贴)

                        stm8与51核变量定义区域比较: 1)idata与@tiny:   熟悉51核的都知道,idata是定义内部ram地址的,而stm8的@tin ...…

查看全部问答>