stm32l151c8t6-A单片机关于定时器的时钟配置和计算(定时1ms的配置)

首先来看一下STM32L151的clock tree, 可以看到TIM2-7是在APB1上的, APB1的最大时钟配置是32MHz, 接下来我的及进行一下我的项目中的始终配置说明,后续也会附上代码。

我的项目中HSE用的是8MHz外部晶振,在项目配置中,我选择了PLLMUL=6,PLLDIV=/3, 这样算下来我的PLLCLK 大小为

PLLCLK =  8 *6 /3 = 16MHz,然后我选择PLLCLK作为SYSCLKd的时钟源,这样SYSCLK=16MHz, 然后选择AHB(也就是HCLK)的Prescaler = /1, 所以HCLK = 16MHz,  APB1(PCLK1) 和 APB2(PCLK2)都是16MHz, 这样TIM2-7的时钟也是16MHz

stm32l151c8t6-A单片机关于定时器的时钟配置和计算(定时1ms的配置)

注意:注意下图中,蓝色部分的说明。(下面这个图是截取的F系列的单片机说明,但是原理是一样的),在上图L151系列的途中,也有说明,红色曲折线后面的也说明了 当APB1 prescaler =1时,TIM2-7的时钟等于APB1的时钟,当APB1 prescaler为其他值时,则TIM2-7的时钟为APB1的2倍(✖2).

有人会问,既然需要 TIM2~7 的时钟频率=32MHz,为什么不直接取 APB1 的预分频系数=1?答
案是:APB1 不但要为 TIM2~7 提供时钟,而且还要为其它外设提供时钟;设置这个倍频器可
以在保证其它外设使用较低时钟频率时,TIM2~7 仍能得到较高的时钟频率。
再举个例子:当 AHB=32MHz 时,APB1 的预分频系数必须大于 2,因为 APB1 的最大频率只能
为 16MHz。如果 APB1 的预分频系数=2,则因为这个倍频器,TIM2~7 仍然能够得到 32MHz 的
时钟频率。能够使用更高的时钟频率,无疑提高了定时器的分辨率,这也正是设计这个倍频
器的初衷。

stm32l151c8t6-A单片机关于定时器的时钟配置和计算(定时1ms的配置)

下面将配置代码粘贴出来:

//时钟配置代码:

void platform_rcc_init(void)
{
    __IO uint32_t count = 0;   //__IO 是volatile的定义,表示每次使用都要重新重寄存器里取值

    RCC_HSEConfig(RCC_HSE_ON);
    while((RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET) && (count != HSE_STARTUP_TIMEOUT)){
        count++;
    }
    if ((RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET)&&(count != HSE_STARTUP_TIMEOUT)){
        FLASH_ReadAccess64Cmd(ENABLE);
        FLASH_PrefetchBufferCmd(ENABLE);
        FLASH_SetLatency(FLASH_Latency_1);
        RCC_HCLKConfig(RCC_SYSCLK_Div1);    //RCC_SYSCLK_Div1:   AHB clock = SYSCLK
        RCC_PCLK2Config(RCC_HCLK_Div1);       //RCC_HCLK_Div1:  APB2 clock = HCLK
        RCC_PCLK1Config(RCC_HCLK_Div1);       //16MHz  RCC_HCLK_Div1:  APB1 clock = HCLK
        //RCC_PLLMul_6: PLL clock source multiplied by 6
        //RCC_PLLDiv_3: PLL Clock output divided by 3
        RCC_PLLConfig(RCC_PLLSource_HSE,RCC_PLLMul_6, RCC_PLLDiv_3); // PLL = 8MHz * 6 /3 =16MHz
        RCC_PLLCmd(ENABLE);
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//RCC_SYSCLKSource_PLLCLK: PLL selected as system clock source
        while(RCC_GetSYSCLKSource() != 0x0C); //  - 0x0C: PLL used as system clock
    }else{
        RCC_HSEConfig(RCC_HSE_OFF);
        RCC_DeInit();
        RCC_HSICmd(ENABLE);
        FLASH_ReadAccess64Cmd(ENABLE);
        FLASH_PrefetchBufferCmd(ENABLE);
        FLASH_SetLatency(FLASH_Latency_1);
        while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
        RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
        while(RCC_GetSYSCLKSource() != 0x04);//- 0x04: HSI used as system clock
    }
}

定时器配置代码:

void Timer_Init(uint16_t Period,uint16_t Prescaler)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;

    TIM_DeInit(TIM2);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

    TIM_TimeBaseInitStruct.TIM_Period            =  Period-1;
    TIM_TimeBaseInitStruct.TIM_Prescaler       =  Prescaler-1;
    TIM_TimeBaseInitStruct.TIM_CounterMode=  TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_ClockDivision=  TIM_CKD_DIV1;
    //TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);

    TIM_ClearFlag(TIM2,TIM_FLAG_Update);
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

    NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
    NVIC_Init(&NVIC_InitStruct);

    TIM_Cmd(TIM2,ENABLE);                                      //timer enable
}
 

调用Timer_Init(10,1600)得到的就是1ms的定时器设置,可以在定时器中断函数中TIM2_IRQHandler进行相应的定时响应处理。

定时1ms的计算 = ((1+TIM_prescaler)/16MHz ) * (1+ TIM_Period)

                            = (1+(1600-1)) /16000000  *  (1+(10-1))

                             = 1600/16000000 * 10

                             =1/1000  s      也就是1ms