4.配置系统时钟思路及方法

news2024/11/25 2:54:13

 前言:

         比起之前用过的三星的猎户座4412芯片,STM32F4的系统时钟可以说是小巫见大巫,首先我们需要清晰时钟产生的原理:几乎大多数的芯片都是由晶振产生一个比较低频的频率,然后通过若干个PLL得到单片机能承受的频率(作为主频),再通过其他手段将PLL出来的频率降频分给其他外设使用。一个时钟树一般先对复杂,我们先调出主频(及编程好时钟源、PLL倍频这一部分)其他的之后再说,如此编程才不会太复杂。

        实际上这个一般厂家会给一个配置文件的,但是如果要自己做些超频之类的操作,就要彻底掌握时钟树的配置了,见人见智,追求技术的这个内容是逃不掉的。

        编程思路:1.PLL倍频因子配置 2..PLL时钟源激活和切换(上电后单片机会选择一个默认的时钟源,可能是晶振也可能是内部RC电路产生的频率) 3.切换系统时钟

时钟资源概览:

        下面先看一下我们这个F4的系统时钟资源,查看手册可知系统复位后是默认选择HSI这个内部RC电路产生的时钟作为这个单片机的系统时钟,但是我们要的是PLL产生的时钟。

        下面看手册PLL配置的说明(可以把时钟树截图出来作参考,不过主要编程还是靠手册的文字描述),可知RCC_PLLCFGR 可以用来配置PLL (PLLI2S可以先不管,先搞出主频再说),那就配置它吧。寄存器就不放出来了,自己看手册,这里给出寄存器各个位的配置值及解释

RCC_PLLCFGR寄存器配置

可见:
PLL = VCO / PLLP
VCO = PLL时钟源*(PLLN / PLLM)
一共涉及P / N / M 三个因子,以及PLL时钟源。
        PLL就是我们要选的系统时钟,PLL = 168M,如果PLLP选的是2,那么VCO就得是168*2 = 336 。VCO是336,我们的PLL时钟源如果选的是外部晶振(探索者这个开发板上晶振是8M),那么PLLN/PLLM就得等于 VCO / PLL时钟源 = 336 / 8 = 42 ,所以PLLN除以PLLM必须是等于42,PLLN配置为336(可以在192和432这个数值间任意取),则PLLM配置为 336 / 42 = 8 .分频因子就搞定了。
下面开始配置 RCC_PLLCFGR
bit[5:0]:    设置PLLM为8,即0x8<<0
bit[14:6]:  设置PLLN为336,即336<<6
bit[17:16]:设置PLLP为2,即0<<16
bit[22]:     设置PLL和PLLI2S时钟源,设为1<<22,选择HES晶振
bit[27:24]:设置USB OTG之类的时钟,随便设一个,0x7<<24
其他使用默认值,编程如下:
RCC->PLLCFGR = 0x24003010 ;//复位值
RCC->PLLCFGR = 0x7<<24 | 1<<22 | 0<<16 | 336<<6 | 0x8<<0 ;
这样PLL就配置好了,PLL的时钟源我们选择的是HES,它还没有激活,所以 在PLL配置这一步之前,还需要将HSE激活

RCC_CR寄存器配置

查看手册HSE部分,可知要换时钟源要操作RCC_CR寄存器,时钟中断我们不需要。
同样,配置寄存器RCC_CR:(真真苦力活~)
bit[0]:    HSI的开关,这个呢暂时还不能关闭,要让HSE生效之后才能关闭,不然单片机一个时钟都没有没法工作。
bit[1]:    HSI的状态 1是ok,0是不ok
bit[16]:  HSE的开关,置为1<<16,打开
bit[17]:  HSE的状态,它就绪之后才能配置PLL,配置完PLL才能切换系统时钟(HSI时钟---->>PLL时钟)
bit[18]:  HSE时钟旁路,这个要关掉,因为我们要用的是HSE晶振,配置为0<<18
bit[24]:  PLL的开关,这个还没配置好之前要关掉
bit[25]:PLL是否稳定的标志
其他不管,RCC->CR复位时的默认值是 让HSI正常工作的,其他都是0,所以不改动它原有的,在它原有的值基础上进行幅值
1.配置使得HSE开始工作:
RCC->CR | = 1<<16;
u16 retry=0;//这个只是提供短暂延时的变量
while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循环后说明HSE ok了
if(retry==0X1FFF)status=1;    //当然如果超过了一定时间也会跳出,表示HSE无法就绪

2.打开PLL并等待其稳定

RCC->CR|=1<<24;			//打开主PLL
while((RCC->CR&(1<<25))==0);//等待PLL准备好 

使PLL倍频出很高的频率

有了上面的东西,我们就可以使PLL倍频出很高的频率了,结合上面两个寄存器:

RCC->PLLCFGR = 0x7<<24 | 1<<22 | 0<<16 | 336<<6 | 0x8<<0 ;//配置PLL倍频因子

RCC->CR | = 1<<16;//激活HSE晶振
u16 retry=0;//这个只是提供短暂延时的变量
while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循环后说明HSE ok了
if(retry==0X1FFF)status=1; 

else{//激活HSE完成了

		RCC->CR|=1<<24;			//打开主PLL
		while((RCC->CR&(1<<25))==0);//PLL稳定


}

现在PLL理论上已经有了晶振倍频后的频率了,下面切换PLL作为系统时钟:

切换PLL作为系统时钟

查看手册,知道RCC_CFGR是管这个事的:再一波嘎嘎配置

bit[1:0]:0x2<<0        切换PLL作为系统时钟

bit[3:2]:这两个位可以读出是否切换完成,如果读出来是0x2就是切换成PLL成功

bit[7:4]:这四个位是配置AHB分频的,我记得是不分频的,设为0000 即0x0<<4

bit[12:10]: 这三个位是配置APB1分频的 设为4分频,即0x5<<10

bit[15:13]:这三个位是配置APB2分频的 设为2分频,即0x4<<13

bit[20:16]:这五个位是配置RTC分频的 可以先随便设一个设为HSE/2,即0x2<<16

其他不用管


 

RCC_CFGR = 0;//清零

RCC_CFGR = 0x2<<16 | 0x4<<13 | 0x5<<10 | 0x0<<4 | 0x2<<0 ;//切换PLL为系统时钟并且设置其他分频

while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作为系统时钟成功. 

这样,综合上面所有的代码就是:

    u16 retry=0;//这个只是提供短暂延时的变量
    u8 status=0;   
    
//按照上面的分析思路,编程流程就是:

//1.配置PLL倍频因子
    RCC->PLLCFGR = 0x7<<24 | 1<<22 |0<<16 |336<<6 |0x8<<0 ;

//2.激活HSE晶振
    RCC->CR |= 1<<16;
    while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循环后说明HSE ok了

    if(retry==0X1FFF)status=1;
    else{
    //激活HSE完成了
     
//3.打开PLL等待PLL输出稳定
     RCC->CR|=1<<24;			
     while((RCC->CR&(1<<25))==0);

//4.切换PLL输出为系统时钟
     RCC->CFGR = 0;//清零
     RCC->CFGR =0x2<<16 |0x4<<13 | 0x5<<10 | 0x0<<4 |0x2<<0;//切换PLL为系统时钟并且设置其他分频
     while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作为系统时钟成功.现在主频是168M了
    }

验证测试:

下面可以用串口来打印,验证是不是设置完成。

可见是ok了的~说明上面的系统时钟配置没问题。main函数

疑难杂症:

如果你的整个main函数是这样的:是配置完时钟后也是没法正常工作的

#include "sys.h"
#include "usart.h" 
#include "delay.h" 

u16 myconut;
//systick中断服务函数,使用OS时用到
void SysTick_Handler(void)
{	
    myconut++;
    if(myconut>=1000){
        myconut=0;
        printf("hello\r\n");
    }

}

int main(void)
{ 
	u8 t=0;

    
    u16 retry=0;//这个只是提供短暂延时的变量
    u8 status=0;
    

    
//按照上面的分析思路,编程流程就是:

//1.配置PLL倍频因子
    RCC->PLLCFGR = 0x7<<24 | 1<<22 |0<<16 |336<<6 |0x8<<0 ;

//2.激活HSE晶振
    RCC->CR |= 1<<16;
    while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循环后说明HSE ok了

    if(retry==0X1FFF)status=1;
    else{
    //激活HSE完成了
     
//3.打开PLL等待PLL输出稳定
     RCC->CR|=1<<24;			
     while((RCC->CR&(1<<25))==0);

//4.切换PLL输出为系统时钟
     RCC->CFGR = 0;//清零
     RCC->CFGR =0x2<<16 |0x4<<13 | 0x5<<10 | 0x0<<4 |0x2<<0;//切换PLL为系统时钟并且设置其他分频
     while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作为系统时钟成功.现在主频是168M了
    }


	delay_init(168);		//初始化延时函数
    
    NVIC_SetPriorityGrouping(2);
    SysTick_Config(168000);//1ms中断一次
    NVIC_EnableIRQ(SysTick_IRQn);
    
	uart_init(84,115200);	//串口初始化为115200
	while(1)
	{

	}
}

原因是缺少了这样几行关于CPU的代码:将它加在时钟配置代码的上方即可正常运行了

    	FLASH->ACR|=1<<8;		//指令预取使能.
		FLASH->ACR|=1<<9;		//指令cache使能.
		FLASH->ACR|=1<<10;		//数据cache使能.
		FLASH->ACR|=5<<0;		//5个CPU等待周期. 

        正点原子是把它放在时钟配置里的,我也不知道为啥,但是我觉得它和时钟配置是没什么关系的,应该是另一部分的知识。正点原子时钟配置中还有这样两句关于电源的代码,我实测去掉也是可以的,不过应该还是加上比较好,但是时钟配置的部分手册没有提到,我也就没有在上面说,以免它出现的很突兀。同样要加的话加在时钟配置代码之前即可。

		RCC->APB1ENR|=1<<28;	//电源接口时钟使能
		PWR->CR|=3<<14; 		//高性能模式,时钟可到168Mhz

完事了~系统时钟就是这样配置啦,这个算是简单的,像能跑linux的那种芯片,就得依靠厂家给的来写或者修改了,自己写的总有不到位的地方~

整个main.c代码如下:

#include "sys.h"
#include "usart.h" 
#include "delay.h" 
//ALIENTEK 探索者STM32F407开发板 实验0
//新建工程实验  
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司
u16 myconut;
//systick中断服务函数,使用OS时用到
void SysTick_Handler(void)
{	
    myconut++;
    if(myconut>=1000){
        myconut=0;
        printf("hello\r\n");
    }

}

int main(void)
{ 
	u8 t=0;
    //plln,pllm,pllp,pllq
	//Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz
    
    
    u16 retry=0;//这个只是提供短暂延时的变量
    u8 status=0;
    
    //CPU相关的初始化
    FLASH->ACR|=1<<8;		//指令预取使能.
    FLASH->ACR|=1<<9;		//指令cache使能.
    FLASH->ACR|=1<<10;		//数据cache使能.
    FLASH->ACR|=5<<0;		//5个CPU等待周期. 
    //电源相关的初始化
    RCC->APB1ENR|=1<<28;	//电源接口时钟使能
    PWR->CR|=3<<14; 		//高性能模式,时钟可到168Mhz
    
//按照博客的分析思路,系统时钟配置的编程流程就是:

//1.配置PLL倍频因子
    RCC->PLLCFGR = 0x7<<24 | 1<<22 |0<<16 |336<<6 |0x8<<0 ;

//2.激活HSE晶振
    RCC->CR |= 1<<16;
    while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循环后说明HSE ok了

    if(retry==0X1FFF)status=1;
    else{
    //激活HSE完成了
     
//3.打开PLL等待PLL输出稳定
     RCC->CR|=1<<24;			
     while((RCC->CR&(1<<25))==0);

//4.切换PLL输出为系统时钟
     RCC->CFGR = 0;//清零
     RCC->CFGR =0x2<<16 |0x4<<13 | 0x5<<10 | 0x0<<4 |0x2<<0;//切换PLL为系统时钟并且设置其他分频
     while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作为系统时钟成功.现在主频是168M了
    }


	delay_init(168);		//初始化延时函数
    
    NVIC_SetPriorityGrouping(2);
    SysTick_Config(168000);//1ms中断一次
    NVIC_EnableIRQ(SysTick_IRQn);
    
	uart_init(84,115200);	//串口初始化为115200
	while(1)
	{

	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1319845.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023_Spark_实验二十八:Flume部署及配置

实验目的&#xff1a;熟悉掌握Flume部署及配置 实验方法&#xff1a;通过在集群中部署Flume&#xff0c;掌握Flume配置 实验步骤&#xff1a; 一、Flume简介 Flume是一种分布式的、可靠的和可用的服务&#xff0c;用于有效地收集、聚合和移动大量日志数据。它有一个简单灵活…

LibreNMS:从docker出发

引言 LibreNMS 是一个免费开源的网络监控和自动化工具&#xff0c;用于监视网络设备、服务器和应用程序的性能和状态。它提供了一个集中的管理平台&#xff0c;帮助管理员实时监控和管理整个网络基础设施。 以下是 LibreNMS 的一些主要特点和功能&#xff1a; 自动发现&#…

20、清华、杭州医学院等提出:DA-TransUNet,超越TranUNet,深度医学图像分割框架的[皇帝的新装]

前言&#xff1a; 本文由清华电子工程学院、杭州医学院、大阪大学免疫学前沿研究所、日本科学技术高等研究院信息科学学院、东京法政大学计算机与信息科学专业共同作者&#xff0c;于2023年11月14号发表于arXiv的《Electrical Engineering and Systems Science》期刊。 论文&…

【Python基础】生成器

文章目录 [toc]什么是生成器生成器示例生成器工作流程生成器表达式send()方法和close方法send()方法close()方法 什么是生成器 在Python中&#xff0c;使用生成器可以很方便地支持迭代器协议生成器通过生成器函数产生&#xff0c;通过def定义&#xff0c;但不是通过return返回…

酷雷曼再获“国家高新技术企业”认定

2023年12月8日&#xff0c;《对湖北省认定机构2023年认定报备的第五批高新技术企业拟进行备案的公示》正式发布&#xff0c;酷雷曼武汉同创蓝天科技有限公司成功获评“国家高新技术企业”认定。 屡获权威认定&#xff0c;见证硬核实力 被评定为高新技术企业是我国企业最高荣誉…

武汉小程序开发全攻略:从创意到上线,10个必备步骤详解

在当前数字化时代&#xff0c;小程序已经成为企业营销和服务的重要工具。特别是在武汉这样的创新型城市&#xff0c;小程序开发更是备受青睐。本文将为您详细解读武汉小程序开发的全攻略&#xff0c;从创意到上线的10个必备步骤。 步骤一&#xff1a;确定小程序类型和功能定位…

DSP捕获输入简单笔记

之前使用stm32的大概原理是&#xff1a; 输入引脚输入一个脉冲&#xff0c;捕获1开始极性捕获&#xff0c;捕获的是从启动捕获功能开始计数&#xff0c;捕获的是当前的计数值&#xff1b; 例如一个脉冲&#xff0c;捕获1捕获上升沿&#xff0c;捕获2捕获下降沿&#xff1b;而两…

mysql自动安装脚本(快速部署mysql)

mysql_install - 适用于生产环境单实例快速部署 MySQL8.0 自动安装脚本 mysql8_install.sh&#xff08;执行前修改一下脚本里的配置参数&#xff0c;改成你自己的&#xff09;&#xff08;博客末尾&#xff09; my_test.cnf&#xff08;博客末尾&#xff09;&#xff08;这个…

Linux性能优化常做的一些事情

Linux性能优化是一个广泛的主题&#xff0c;涉及多个方面。以下是一些常见的Linux性能优化建议&#xff1a; 硬件和系统配置&#xff1a; 使用SSD替代HDD。确保系统有足够的RAM。使用多核CPU。配置合适的网络硬件和带宽。 磁盘I/O性能&#xff1a; 使用RAID来提高I/O性能。使用…

WordCloud—— 词云

【说明】文章内容来自《机器学习入门——基于sklearn》&#xff0c;用于学习记录。若有争议联系删除。 wordcloud 是python的第三方库&#xff0c;称为词云&#xff0c;也成文字云&#xff0c;可以根据文本中的词频以直观和艺术化的形式展示文本中词语的重要性。 依赖于pillow …

物联网对接使用蓝牙还是WiFi,应该如何选择?

蓝牙是一种无线技术协议&#xff0c;可促进连接设备之间短距离的数据交换。它依赖于物理邻近性并使用2.400至2.485 GHz之间的UHF&#xff08;超高频&#xff09;无线电波。蓝牙旨在创建个人区域网络&#xff08;PAN&#xff09;并在笔记本电脑、智能手机和外围设备等计算设备之…

虚幻学习笔记18—C++委托(多播)和事件

一、前言 委托分单播和多播&#xff0c;多播就是可以绑定多个回调函数&#xff0c;然后一次性执行。这样也可以理解为啥多播没有返回值&#xff0c;多个回调函数执行后返回哪一个都是问题啊。而事件呢官方官方文档说法是“对于事件而言&#xff0c;只有定义事件的类才能调用 Br…

055:vue工具 --- 人民币小写转化为大写

第055个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

2023年国赛高教杯数学建模D题圈养湖羊的空间利用率解题全过程文档及程序

2023年国赛高教杯数学建模 D题 圈养湖羊的空间利用率 原题再现 规模化的圈养养殖场通常根据牲畜的性别和生长阶段分群饲养&#xff0c;适应不同种类、不同阶段的牲畜对空间的不同要求&#xff0c;以保障牲畜安全和健康&#xff1b;与此同时&#xff0c;也要尽量减少空间闲置所…

读取小数部分

1.题目描述 2.题目分析 //假设字符串为 char arr[] "123.4500"; 1. 找到小数点位置和末尾位置 代码如下&#xff1a; char* start strchr(arr, .);//找到小数点位置char* end start strlen(start) - 1;//找到末尾位置 如果有不知道strchr()用法的同学&#xf…

Html+单页面引入element以及Vue框架引用地址报错(unpkg.com国内无法访问可代替方案)

问题 单页面引入element以及vue 地址报错&#xff0c;请求超时 使用的引用地址是官网上提供&#xff0c;但是没解决问题 一、原因&#xff1a; unpkg也没有幸免于难&#xff0c;也被墙了&#xff0c;unpkg上的相关资源都不能访问&#xff0c;才导致项目资源加载不出。 二、…

linux gdb反汇编定位问题

日前解决一现网问题遇到补丁加载未生效现象&#xff0c;想要验证流程是否走进补丁代码&#xff0c;由于补丁函数和原函数名称一样&#xff0c;且修改代码较少&#xff0c;通过普通gdb方法难以看出是否走进补丁&#xff0c;但可用gdb反汇编方法来验证。 gdb该进程&#xff0c;之…

cdr格式怎么打开?cdr文件查看工具CDR Viewer功能介绍

CDRViewer Pro for Mac是一款专业的矢量图形文件查看器&#xff0c;主要用于打开、浏览和查看CorelDRAW&#xff08;CDR&#xff09;文件。以下是该软件的主要功能和特点&#xff1a; CDR文件支持&#xff1a;CDRViewer Pro可以快速加载和显示CorelDRAW&#xff08;CDR&#x…

python之双链表

双链表简单讲解 双向链表&#xff08;doubly linked list&#xff09;是一种链式数据结构&#xff0c;它的每个节点包含两个指针&#xff0c;一个指向前一个节点&#xff0c;一个指向后一个节点。与单向链表相比&#xff0c;双向链表可以在任何位置进行插入和删除操作&#xf…

MDC硬件笔记

学习资源来自华为 MDC210 80pin低速信号接口 4832pin 低速连接器的可插拔次数≤20 MiniFakra 视频接口 MiniFakra 视频连接器的可插拔次数≤ 25 次。 车载以太接口 1、2是100兆&#xff0c;3、4是1000兆 MTB300转接盒 前后面板接口总览&#xff1a; 1 低速接口1 40个…