默认APB1时钟频率(PCLK1)=AHB时钟频率(HCLK)/2
默认APB2时钟频率(PCLK1)=AHB时钟频率(HCLK)
话不多说,先上代码
所有定时器都需要使能,使能后开始计时
TIM_Cmd(TIMx, ENABLE);
计算公式为:普通定时器定时时长=
(1/((APB1时钟频率×2)/(TIM_Prescaler+1)))×(TIM_Period+1)
为什么APB1时钟频率×2,因为当默认APB1时钟频率(PCLK1)=AHB时钟频率(HCLK)/2时,根据时钟树,普通定时器的时钟频率=APB1时钟频率×2
所以当RCC_HCLK_Div1和RCC_HCLK_Div2对于普通定时器的时钟频率来说都是AHB时钟频率(HCLK),而选择RCC_HCLK_Div4时
普通定时器的时钟频率=(AHB时钟频率(HCLK)/4)×2
/**
* @brief Configures the Low Speed APB clock (PCLK1).
* @param RCC_HCLK: defines the APB1 clock divider. This clock is derived from
* the AHB clock (HCLK).
* This parameter can be one of the following values:
* @arg RCC_HCLK_Div1: APB1 clock = HCLK
* @arg RCC_HCLK_Div2: APB1 clock = HCLK/2
* @arg RCC_HCLK_Div4: APB1 clock = HCLK/4
* @arg RCC_HCLK_Div8: APB1 clock = HCLK/8
* @arg RCC_HCLK_Div16: APB1 clock = HCLK/16
* @retval None
*/
void RCC_PCLK1Config(uint32_t RCC_HCLK)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RCC_PCLK(RCC_HCLK));
tmpreg = RCC->CFGR;
/* Clear PPRE1[2:0] bits */
tmpreg &= CFGR_PPRE1_Reset_Mask;
/* Set PPRE1[2:0] bits according to RCC_HCLK value */
tmpreg |= RCC_HCLK;
/* Store the new value */
RCC->CFGR = tmpreg;
}
/**
* @brief Configures the High Speed APB clock (PCLK2).
* @param RCC_HCLK: defines the APB2 clock divider. This clock is derived from
* the AHB clock (HCLK).
* This parameter can be one of the following values:
* @arg RCC_HCLK_Div1: APB2 clock = HCLK
* @arg RCC_HCLK_Div2: APB2 clock = HCLK/2
* @arg RCC_HCLK_Div4: APB2 clock = HCLK/4
* @arg RCC_HCLK_Div8: APB2 clock = HCLK/8
* @arg RCC_HCLK_Div16: APB2 clock = HCLK/16
* @retval None
*/
void RCC_PCLK2Config(uint32_t RCC_HCLK)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RCC_PCLK(RCC_HCLK));
tmpreg = RCC->CFGR;
/* Clear PPRE2[2:0] bits */
tmpreg &= CFGR_PPRE2_Reset_Mask;
/* Set PPRE2[2:0] bits according to RCC_HCLK value */
tmpreg |= RCC_HCLK << 3;
/* Store the new value */
RCC->CFGR = tmpreg;
}
此代码用TIM2做定时器,计时1s
void TIM2_run(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef TIM_NVICinitStucture;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 时钟使能
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
TIM_NVICinitStucture.NVIC_IRQChannel = TIM2_IRQn;//中断通道,选择串口中断
TIM_NVICinitStucture.NVIC_IRQChannelPreemptionPriority = 0;//配置中断优先级
TIM_NVICinitStucture.NVIC_IRQChannelCmd = ENABLE;//使能打开
TIM_NVICinitStucture.NVIC_IRQChannelSubPriority = 2;//配置中断子优先级
NVIC_Init(&TIM_NVICinitStucture);//串口结构体初始化
TIM_TimeBaseStructure.TIM_Period = 10000-1;
//设置自动重装载计数值,可以设置的值为0x0000-0xFFFF,即0到65535
//但由于从0开始计数,所以设置值=实际所需重载值-1
TIM_TimeBaseStructure.TIM_Prescaler =7199;
//设置预分频,可以设置的值为0x0000-0xFFFF,即0到65535
//但由于没有0分频的说法,所以设置值=实际所需分频值-1
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//根据指定参数初始化TIMx
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE );
}
上述定时器是通用定时器的定时方法
使用高级定时器TIM1或TIM8做定时器时,可以根据需要定义TIM_RepetitionCounter的值
高级定时器定时时长=
(1/(APB2时钟频率/(TIM_Prescaler+1)))×(TIM_Period+1)
代码如下(此代码实现了计时3s)
void TIM1_run(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef TIM_NVICinitStucture;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // 时钟使能
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
TIM_NVICinitStucture.NVIC_IRQChannel = TIM1_UP_IRQn; //中断通道,选择串口中断
TIM_NVICinitStucture.NVIC_IRQChannelPreemptionPriority = 0;//配置中断优先级
TIM_NVICinitStucture.NVIC_IRQChannelCmd = ENABLE;//使能打开
TIM_NVICinitStucture.NVIC_IRQChannelSubPriority = 2;//配置中断子优先级
NVIC_Init(&TIM_NVICinitStucture);//串口结构体初始化
TIM_TimeBaseStructure.TIM_Period = 10000-1;
//设置自动重装载计数值,可以设置的值为0x0000-0xFFFF,即0到65535
//但由于从0开始计数,所以设置值=实际所需重载值-1
TIM_TimeBaseStructure.TIM_Prescaler =7199;
//设置预分频,可以设置的值为0x0000-0xFFFF,即0到65535
//但由于没有0分频的说法,所以设置值=实际所需分频值-1
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseStructure.TIM_RepetitionCounter=2;
//该参数设定溢出多少次才触发中断,可以设置的值为0x00-0xFF
//但由于从0开始计数,所以设置值=实际所需溢出次数-1
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);//根据指定参数初始化TIMx
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE );
}
中断函数
void TIM2_IRQHandler()
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
void TIM1_UP_IRQHandler()
{
if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) //判断TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM1, TIM_IT_Update ); //清除TIMx更新中断标志
}
}
高级定时器有四个中断入口
TIM1_BRK_IRQn = 24,
/*!< TIM1 Break Interrupt */
TIM1_UP_IRQn = 25,
/*!< TIM1 Update Interrupt ,该中断入口可用于定时器 */
TIM1_TRG_COM_IRQn = 26,
/*!< TIM1 Trigger and Commutation Interrupt */
TIM1_CC_IRQn = 27,
/*!< TIM1 Capture Compare Interrupt */
四个中断入口各自对应着中断函数
具体可以查看startup_stm32f10x_hd.s 文件