从自己的板子STM32F407入手,参考官方的SystemInit()函数:

核心在SetSysClock()这个函数,官方默认是采用HSE(设定为8MHz)作为PLL锁相环的输入输出168MHz的SYSCLK;

/**
* @brief Setup the microcontroller system
* Initialize the Embedded Flash Interface, the PLL and update the
* SystemFrequency variable.
* @param None
* @retval None
*/
void SystemInit(void)
{
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001; /* Reset CFGR register */
RCC->CFGR = 0x00000000; /* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF; /* Reset PLLCFGR register */
RCC->PLLCFGR = 0x24003010; /* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF; /* Disable all interrupts */
RCC->CIR = 0x00000000; /* Configure the System clock source, PLL Multiplier and Divider factors,
AHB/APBx prescalers and Flash settings ----------------------------------*/
SetSysClock(); }

这里大致分析一下官方默认的SetSysClock()配置:

由于我个人采用的是STM32F407型号的芯片,因此精简一下函数;

总体思路的话:

使能HSE;

等待HSE初始化完毕,进行下一步设置;

设置HCLK、PCLK1、PCLK2的分频系数;

配置PLL,使能PLL,等待PLL初始化完毕;

选择PLL作为SYSCLK,等待SYSCLK时钟设置完毕;

/**
* @brief Configures the System clock source, PLL Multiplier and Divider factors,
* AHB/APBx prescalers and Flash settings
* @Note This function should be called only once the RCC clock configuration
* is reset to the default reset state (done in SystemInit() function).
* @param None
* @retval None
*/
static void SetSysClock(void)
{
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
__IO uint32_t StartUpCounter = , HSEStatus = ; /* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON); /* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == ) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
} if (HSEStatus == (uint32_t)0x01)
{
/* Select regulator voltage output Scale 1 mode */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS; /* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; /* PCLK1 = HCLK / 4*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; /* PCLK2 = HCLK / 1*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; /* PCLK1 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; /* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << ) | (((PLL_P >> ) -) << ) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << ); /* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON; /* Wait till the main PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == )
{
} /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS; /* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL; /* Wait till the main PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}

在官方的基础上,直接设定HSE作为SYSCLK时钟:

初始化HSE;

等待HSE初始化成功后再继续;

设置调压器电压输出级别为1以便使器件在最大频率工作;

设置HCLK、PCLK1、PCLK2分频系数;

设置HSE作为系统时钟;

void HSE_SetSysClock(void)
{
__IO uint32_t HSEStartUpStatus = ;   /* 开启HSE时钟 */
  /* 此函数从stm32f0xx_rcc.c获取,用于配置外部时钟HSE:
   *   有三个配置:RCC_HSE_OFF关闭外部HSE时钟
   *         RCC_HSE_ON开始外部HSE晶振
   *         RCC_HSE_Bypass开始HSE旁路设置
   */
   RCC_HSEConfig(RCC_HSE_ON);   /* 等待HSE开启设置成功,并获取到时钟配置状态 */
HSEStartUpStatus = RCC_WaitForHSEStartUp();   /* 若时钟配置成功 */
if(HSEStartUpStatus == SUCCESS)
{
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS; RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLK2Config(RCC_HCLK_Div1); RCC_PCLK1Config(RCC_HCLK_Div1);      /* 将SYSCLK系统时钟设置为HSE */
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);      /* 等待SYSCLK系统时钟设置成功 */
while(RCC_GetSYSCLKSource() != 0x04)
{
}
}else
{
while();
}
}

使用HSI经过PLL配置系统时钟:

使能HSI时钟;

获取HSI状态并等待HSI稳定;

设置调节器电压输出级别配置为1;

设置HCLK、PCLK1/2分频系数;

设置PLL时钟分频系数;

使能PLL并等待PLL稳定后配置PLL状态;

设置PLL作为SYSCLK时钟并等待设置完成;

void HSI_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q)
{
__IO uint32_t HSIStartUpStatus = ; /* 去初始化RCC */
RCC_DeInit(); /* 使能HSI时钟 */
RCC_HSICmd(ENABLE); /* 从RCC的CR寄存器中获取HSI配置状态 */
HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY; /* 若HSI配置成功 */
if(HSIStartUpStatus == RCC_CR_HSIRDY)
{ /* 配置调节器电压输出级别为1 */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS; /* 配置SYSCLK到HCLK的分频系数为1 */
RCC_HCLKConfig(RCC_SYSCLK_Div1); /* 配置HCLK到PCLK1/2的分频系数为2/4 */
RCC_PCLK2Config(RCC_HCLK_Div2); RCC_PCLK1Config(RCC_HCLK_Div4); /* 配置PLL参数,选用HSI作为PLL参数,同时使能PLL */
RCC_PLLConfig(RCC_PLLSource_HSI, m, n, p, q); RCC_PLLCmd(ENABLE); /* 等待PLL设置完成 */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); FLASH->ACR = FLASH_ACR_PRFTEN
| FLASH_ACR_ICEN
| FLASH_ACR_DCEN
| FLASH_ACR_LATENCY_5WS; RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while(RCC_GetSYSCLKSource() != 0x08);
}else
{
while();
}
}

HAL时钟配置分析:

与STM32标准外设库不同,HAL库来实现时钟配置需要重新适应配置方式,但是本质的寄存器调动是类似不变的,且配置的过程也和STM32标准外设库相似;

参考使用STMCube生成的代码,时钟树如图所示:

在STM32Cube中设置:

HSE设置为Crystal/Ceramic Resonator,Input Frequency设置为16MHz;

在工程中要配置的参数:

第一个HSE_VALUE参数位于stm32f0xx_hal_conf.h中,此参数与在STMCube时钟树上定义的一致,需要手动设置为实际的参数值

第二个HSE_VALUE参数位于system_stm32f0xx.c中,此参数默认为8MHz,可以通过用户程序来提供和调整;

第三个SystemCoreClock参数位于system_stm32f0xx.c中,其默认值也是8MHz,可以根据以下三种方式来更新:

    调用CMSIS函数SystemCoreClockUpdate()、

    调用HAL API函数HAL_RCC_GetHCLKFreq()、

    调用HAL_RCC_ClockConfig();

/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)16000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */ #if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000)
/*!< Default value of the External oscillator in Hz.
This value can be provided and adapted by the user application. */
#endif /* HSE_VALUE */ /** @addtogroup STM32F0xx_System_Private_Variables
* @{
*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock there is no need to call the 2 first functions listed above, since SystemCoreClock variable is updated automatically.
*/
uint32_t SystemCoreClock = ;

实际的时钟配置函数如下图:

使用了三个参数来配置:

RCC_OscInitStruct用来配置外部时钟参数,这里设置晶振类型为HSE、设置HSE的状态为开启状态、不使用PLL;

RCC_ClkInitStruct用来配置系统时钟内的参数(如Sys CLK、HCLK、PCLK1),这里设置要配置的时钟类型为HCLK、SYSCLK、PCLK1,选择HSE时钟作为SYSCLK的时钟源,并设置系统时钟SYSCLK分频系数为0、HCLK的分频系数为4;

PeriphClkInit用来配置外设时钟的时钟源,这里设置USART1/2的时钟源为PCLK1;

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {}; /** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
} HAL_SYSTICK_Config(SystemCoreClock / );
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
HAL_NVIC_SetPriority(SysTick_IRQn, , );
}

这里加入了对SysTick的时钟配置,参考HAL库本身的设置:

HAL_SYSTICK_Config()用来配置使能和配置SysTick寄存器;

HAL_SYSTICK_CLKSourceConfig()选择AHB时钟(或AHB时钟除以8)作为SysTick时钟源;

HAL_NVIC_SetPriority()配置SysTick_IRQn的中断优先级为0,默认为最高;

STM32F072从零配置工程-自定义时钟配置详解的更多相关文章

  1. 在Tomcat中配置404自定义错误页面详解

    这篇文章主要介绍了在Tomcat中配置404自定义错误页面全解,需要的朋友可以参考下 一直使用tomcat,今天想到一个问题,自定义404错误页面, 为了获得很好的用户感受,是不应当向用户暴露404这 ...

  2. SpringBoot01 InteliJ IDEA安装、Maven配置、创建SpringBoot项目、yml属性配置、多环境配置、自定义properties配置

    1 IntelliJ IDEA 安装 下载地址:点击前往 注意:需要下载专业版本的,注册码在网上随便搜一个就行啦 2 MAVEN工具的安装 2.1 获取安装包 下载地址:点击前往 2.2 安装过程 到 ...

  3. GPIO 配置之ODR, BSRR, BRR 详解

    STM32 GPIO 配置之ODR, BSRR, BRR 详解 用stm32 的配置GPIO 来控制LED 显示状态,可用ODR,BSRR,BRR 直接来控制引脚输出状态. ODR寄存器可读可写:既能 ...

  4. STM32 GPIO 配置之ODR, BSRR, BRR 详解

    STM32 GPIO 配置之ODR, BSRR, BRR 详解 用stm32 的配置GPIO 来控制LED 显示状态,可用ODR,BSRR,BRR 直接来控制引脚输出状态. ODR寄存器可读可写:既能 ...

  5. centos7.2环境nginx+mysql+php-fpm+svn配置walle自动化部署系统详解

    centos7.2环境nginx+mysql+php-fpm+svn配置walle自动化部署系统详解 操作系统:centos 7.2 x86_64 安装walle系统服务端 1.以下安装,均在宿主机( ...

  6. BaseAdapter自定义适配器——思路详解

    BaseAdapter自定义适配器——思路详解 引言: Adapter用来把数据绑定到扩展了AdapterView类的视图组.系统自带了几个原生的Adapter. 由于原生的Adapter视图功能太少 ...

  7. Nginx安全相关配置和nginx.conf中文详解

    一.centos下redis安全相关 1.背景 在使用云服务器时,如果我们的redis关闭了protected-mode模式,被病毒攻击的可能会大大增加,因此我们使用redis时候,最好更改默认端口, ...

  8. Flume中的flume-env.sh和log4j.properties配置调整建议(图文详解)

    GC是内存的回收的意思. Flume中的flume-env.sh配置调整建议 [hadoop@master conf_HostInterceptor]$ pwd /home/hadoop/app/fl ...

  9. IIS8 使用FastCGI配置PHP环境支持 过程详解

    平时帮朋友们配置过一些PHP环境的服务器,但是一直使用的都是Apache HTTP+PHP,今天呢,我吧IIS+PHP配置方式给大家发一下下~呵呵. 在这里,我使用的是FastCGI模块映射的方式配置 ...

随机推荐

  1. Win8 Metro(C#)数字图像处理--2.54迭代法图像二值化

    原文:Win8 Metro(C#)数字图像处理--2.54迭代法图像二值化  [函数名称]   迭代法图像二值化      int IterativeThSegment(WriteableBitm ...

  2. WPF 使用Trigger遇到的问题

    1. 在style中使用trigger无效的场景 原因是直接在对象上设置值将导致style中的值无效,去掉TextBlock对象的Foreground后,Trigger将正常工作 <TextBl ...

  3. 基于事件驱动的DDD领域驱动设计框架分享(附源代码)

    原文:基于事件驱动的DDD领域驱动设计框架分享(附源代码) 补充:现在再回过头来看这篇文章,感觉当初自己偏激了,呵呵.不过没有以前的我,怎么会有现在的我和现在的enode框架呢?发现自己进步了真好! ...

  4. qlineedit设置背景颜色(使用QPalette的方法不行,必须使用QSS)

    使用QPalette的方法不行, ui->le_text->setAutoFillBackground(true);qDebug() << ui->le_text-> ...

  5. WPF全局异常捕获

    跟着<WPF专业编程开发指南>这书打的代码的,自己在正式项目中测试通过,可以抓取到全局的异常,用的log4net来记录日志 核心代码: 写在App.xaml.cs中 /// <sum ...

  6. 写一个可拖动的 TShape(简单有效:依靠VCL体系,TShape自己就能被探测到被点击了,然后只要改变Left坐标就行了)

    问题来源: http://www.cnblogs.com/del/archive/2009/03/09/1234066.html#1471535 本例效果图: 自定义类(TMyShape)单元 : u ...

  7. C++ 王者归来:对编程语言的需求总结为四个:效率,灵活,抽象,生产率(C++玩的是前三个,Java和C#玩的是后两个)

    Why C++ ? 王者归来(转载) 因为又有人邀请我去Quora的C2C网站去回答问题去了,这回是 关于 @laiyonghao 的这篇有点争议的博文<2012 不宜进入的三个技术点>A ...

  8. 跨平台网络通信与服务器框架 acl 3.2.0 发布,acl_cpp 是基于 acl 库的 C++ 库

    acl 3.2.0 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/F ...

  9. Codility--- Distinct

    Task description Write a function class Solution { public int solution(int[] A); } that, given a zer ...

  10. SYN591-C型 时间间隔表

       SYN591-C型 时间间隔表 脉冲计数器数显计数器电机转速表使用说明视频链接: http://www.syn029.com/h-pd-250-0_310_44_-1.html 请将此链接复制到 ...