首先来看一下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
注意:注意下图中,蓝色部分的说明。(下面这个图是截取的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 的
时钟频率。能够使用更高的时钟频率,无疑提高了定时器的分辨率,这也正是设计这个倍频
器的初衷。
下面将配置代码粘贴出来:
//时钟配置代码:
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