STM32F207(3) SetSysClock

环境:STM32F207

内容:SetSysClock  STM32F207使用固件库,怎样设置系统时钟

在实际讲函数之前让我们来看看这个函数的功能备注:

<span style="font-size:14px;"><span style="font-size:14px;">/**
  * @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)</span></span>
备注的大概意思就是:

配置系统时间源,PLL倍频器和分频器因子,AHB/APBX预分频器和FLASH相关设置

注意:这个函数只能够被调用一次,那就是在systemInit函数里面


注意:如果能够看懂下面这个函数做了什么,那么您对STM32的时钟树已经掌握了。不敢说是完全掌握,至少知道STM32时钟树是怎么一回事。

在说之前我们先说说频率最大值:


这里说了三个时钟AHB,APB2,APB1

AHB最大频率120MHZ

APB2最大频率60MHZ

APB1最大频率30MHZ

源代码如下:

static void SetSysClock(void)
{
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* 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 == 0) && (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)
  {
    /* 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;//⑤

    /* Configure the main PLL */
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);//⑥

    /* Enable the main PLL */
    RCC->CR |= RCC_CR_PLLON;</span><span style="font-size:18px;">//⑦

    /* Wait till the main PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)//⑧
    {
    }
   
    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS; //⑨

    /* Select the main PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));  //⑩
    RCC->CFGR |= RCC_CFGR_SW_PLL;    // (11)

    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);  //(12)
    {
    }
  }
  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 */
  }

}


说明:我对上面代码写了讲解点,比如①,②,③等等

/* Enable HSE */
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);// ①</span></span>
这个地方的作用是打开外部晶振,让其起振。


就如同上面所述,大概意思就是可以通过程序打开或者关闭,但是当CPU进入待机模式之后,硬件会自动停止外部晶振震动,可能是考虑到了功耗原因吧,然后就是

当我们直接或者间接使用了HSE作为系统时间,我们就不能够将这个设置成0.


/* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;//②
    StartUpCounter++;
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));</span></span>

单从字面上理解的话,我们就知道,这里的意思是等待外部晶振起振,并且稳定下来。如下:


这个地方大概意思就是等待HSE稳定,其实这里我有个疑问,希望读者在评论中说明下,就是这里:After the HSION bit is cleared,HSERDY goes low after 6 ....

问题就是HSI什么时候清零。

/* HCLK = SYSCLK / 1*/
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;/</span><span style="font-size:18px;">/③</span>
在stm32f2xx.h里面定义有

#define  RCC_CFGR_HPRE_DIV1                  ((uint32_t)0x00000000)        /*!< SYSCLK not divided */

我们再看手册是否正确


也就是说STM32时钟树里面的AHB时钟不会被分频,那代表什么意思呢?如下图:


例如SYSCLK最后是120MHZ,那么AHB出来之后,还是120MHZ,这就是不分频的意思。



/* PCLK2 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;</span><span style="font-size:18px;">//④</span>
这里对CFGR做了操作,同样在stm32f2xx.h里面

#define  RCC_CFGR_PPRE2_DIV2                 ((uint32_t)0x00008000)        /*!< HCLK divided by 2 */

这里将第十六位bit15写成了1,bit15含义如下:




上面两张图的大概意思就是PPRE2就是设置外设高速时钟APB2的,其中bit15=1,100,就是说APB2被AHB 2分频,时钟树如下:


加入SYSCLK=120,那么经过AHB之后,到达APB2前端,时钟=120,经过PPRE2之后,APB2=60M,当然,这是外设最高时钟。


/* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;</span><span style="font-size:18px;">//⑤</span>
同上,这里是设置APB1的,APB2是高速外设,时钟最大=60M,APB1是高速时钟,时钟最大=30M。

在stm32f2xx.h里面有

#define  RCC_CFGR_PPRE1_DIV4                 ((uint32_t)0x00001400)        /*!< HCLK divided by 4 */

这里将第11位和第13位写成1,也就是bit10和bit12是1,如下


PPRE1值也就应该是101,如下图


同上面时钟树里面也就是说,APB1=SYSCLK/4=120 / 4 = 30M

/* Configure the main PLL */
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);</span><span style="font-size:18px;">//⑥</span>
这里看起来有很多东西,先捋一捋:

我们先看看PLL_N,PLL_P,PLL_Q,PLL_M分别代表什么意思:

/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M      25
#define PLL_N      240


/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2


/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
#define PLL_Q      5


如同上面所说:

系统时钟SYSCLK=PLL_VCO,

PLL_VCO=HSE / PLL_M * PLL_N


如果我们要让SYSCLK=120M,那么这几个值该怎么设置呢?如果我们每个都去假设,那可能是得不偿失的,这里有个方法,先看下面公式:

PLL_VCO=(HSE/PLL_M)*PLL_N。这里我们可以先让括号里面的值=1M,那么后面的计算就很简单了,这是一种很实用的方法,大家都是设置寄存器,为什么我们不找最简单的方式呢。

如果我们HSE=25M   ,那么1M=25/PLL_M  ,所以PLL_M=25,现在我们要得到120M的系统时钟,先下面:

SYSCLK=PLL_VCO/PLL_P;


这个PLLP的值只有这么几种,也就是说,我们最好把PLL_VCO设置成一个很特别的值,比如240M,那么我们PLLP=2就解决问题了。

好了,接下来怎么做,我就不说了,其他就很简单了,如果有需要的帮助的同学后面还是不懂,可以留言。但是FLASH那里我还没有看是怎么回事,所以暂时也不是很清楚。

OK,这是讲解STM32F207时钟相关的最后一篇文章,后面的文章主要是针对部分外设来展开。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值