本文主要是介绍STM32:TIM定时中断配置的最全库函数讲解笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
声明:本博客为哔哩哔哩up主@江协科技 “STM32入门教程”的听课笔记,仅供学习、参考使用,不得用作其他用途,违者必究。如有版权问题,请联系作者修改。
目录
一、综述
二、TIM库
初始化
2.1、TIM_DeInit 恢复缺省值
2.2、TIM_TimeBaseInit 时基单元初始化
2.3、 TIM_TimeBaseStructInit 时基单元结构体默认赋值
2.4、TIM_Cmd 使能计数器
2.5、TIM_ITConfig 使能中断输出信号
2.6、TIM_InternalClockConfig 选择内部时钟
2.7、TIM_ITRxExternalClockConfig
2.8、TIM_TIxExternalClockConfig
2.9、TIM_ETRClockMode1Config
2.10、TIM_ETRClockMode2Config
2.11、TIM_ETRConfig
2.12、6~11讲解
2.13、TIM结构体讲解
2.13.1、TIM_ClockDivision
2.13.2、TIM_CounterMode
2.13.3、TIM_Period
2.13.4、TIM_Prescaler
2.13.5、TIM_RepetitionCounter
参数变更
2.14、TIM_PrescalerConfig 单独写入预分频值
2.15、TIM_CounterModeConfig 改变计数器的计数模式
2.16、TIM_ARRPreloadConfig自动重装器预装功能配置
2.17、TIM_SetCounter 给计数器写入一个值
2.18、TIM_SetAutoreload 写入自动重装值
2.19、TIM_GetCounter 获取当前计数器的值
2.20、TIM_GetPrescaler 获取当前分频器的值
2.21、TIM_GetFlagStatus 主程序标志位获取
2.22、TIM_ClearFlag 主程序中清除标志位
2.23、TIM_GetITStatus 中断程序中获取标志位
2.24、TIM_ClearITPendingBit 中断程序中清除标志位
三、定时中断完整代码
3.1、Timer.h
3.2、Timer.c
3.2.1、具体步骤
3.2.2、完整代码
3.3、main.c
四、一个问题
五、定时中断完整代码(调整后)
5.1、Timer.h
5.2、Timer.c
5.2.1、具体步骤
5.2.2、完整代码
5.3、main.c
一、综述
上图是定时中断的整个框架结构。我们只需要把这里面的每个模块都打通,就可以让定时器工作了。
具体步骤
第一步:RCC开启时钟。在这里打开时钟之后,定时器的基准时钟和整个外设的工作时钟就都会同时打开了。
第二步:选择时基单元的时钟源。对于定时中断,我们选择内部时钟源。
第三步:配置时基单元。包括这里的与分频器,计数器计数模式,自动重装器等等。这些参数用一个结构体就可以配置好了。
第四步:配置输出中断控制,允许更行中断输出到NVIC。
第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级。
整个模块配置完成之后我们还需要使能一下计数器,不然计数器是不会运行的。当定时器使能后,计时器就会开始报数了。当计时器更新时,触发中断。最后再写一个定时器的中断函数,这样这个中断函数每隔一段时间就能自动执行一次了。
二、TIM库
初始化
2.1、TIM_DeInit 恢复缺省值
函数原型:void TIM_DeInit(TIM_TypeDef* TIMx);
函数讲解:恢复缺省配置;
函数定义:
/*** @brief Deinitializes the TIMx peripheral registers to their default reset values.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @retval None*/
void TIM_DeInit(TIM_TypeDef* TIMx)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx)); if (TIMx == TIM1){RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, DISABLE); } else if (TIMx == TIM2){RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, DISABLE);}else if (TIMx == TIM3){RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, DISABLE);}else if (TIMx == TIM4){RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, DISABLE);} else if (TIMx == TIM5){RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, DISABLE);} else if (TIMx == TIM6){RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, DISABLE);} else if (TIMx == TIM7){RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, DISABLE);} else if (TIMx == TIM8){RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, DISABLE);}else if (TIMx == TIM9){ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM9, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM9, DISABLE); } else if (TIMx == TIM10){ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM10, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM10, DISABLE); } else if (TIMx == TIM11) { RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM11, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM11, DISABLE); } else if (TIMx == TIM12){ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM12, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM12, DISABLE); } else if (TIMx == TIM13) { RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM13, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM13, DISABLE); }else if (TIMx == TIM14) { RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM14, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM14, DISABLE); } else if (TIMx == TIM15){RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM15, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM15, DISABLE);} else if (TIMx == TIM16){RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM16, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM16, DISABLE);} else{if (TIMx == TIM17){RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM17, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM17, DISABLE);} }
}
2.2、TIM_TimeBaseInit 时基单元初始化
函数原型:
void TIM_TimeBaseInit(TIM_TypeDef* TIMx,
TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
函数讲解:时基单元初始化;两个参数:第一个TIMx选择某个定时器,第二个是结构体,里面包含了配置时基单元的一些参数。
函数定义:
/*** @brief Initializes the TIMx Time Base Unit peripheral according to * the specified parameters in the TIM_TimeBaseInitStruct.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param TIM_TimeBaseInitStruct: pointer to a TIM_TimeBaseInitTypeDef* structure that contains the configuration information for the * specified TIM peripheral.* @retval None*/
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{uint16_t tmpcr1 = 0;/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx)); assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));tmpcr1 = TIMx->CR1; if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||(TIMx == TIM4) || (TIMx == TIM5)) {/* Select the Counter Mode */tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;}if((TIMx != TIM6) && (TIMx != TIM7)){/* Set the clock division */tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;}TIMx->CR1 = tmpcr1;/* Set the Autoreload value */TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;/* Set the Prescaler value */TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17)) {/* Set the Repetition Counter value */TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;}/* Generate an update event to reload the Prescaler and the Repetition countervalues immediately */TIMx->EGR = TIM_PSCReloadMode_Immediate;
}
2.3、 TIM_TimeBaseStructInit 时基单元结构体默认赋值
函数原型:
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
函数讲解:这个函数可以把结构体变量赋一个默认值。
函数定义:
/*** @brief Fills each TIM_TimeBaseInitStruct member with its default value.* @param TIM_TimeBaseInitStruct : pointer to a TIM_TimeBaseInitTypeDef* structure which will be initialized.* @retval None*/
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{/* Set the default configuration */TIM_TimeBaseInitStruct->TIM_Period = 0xFFFF;TIM_TimeBaseInitStruct->TIM_Prescaler = 0x0000;TIM_TimeBaseInitStruct->TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStruct->TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStruct->TIM_RepetitionCounter = 0x0000;
}
2.4、TIM_Cmd 使能计数器
函数原型:void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
函数讲解:这个函数是用来使能计数器的,对应图中的“运行控制”板块。它有两个参数,第一个TIMx选择定时器,第二个NewState新的状态,也就是使能还是失能。使能的话,计数器就可以运行,失能的话,计数器就不能运行。
函数定义:
/*** @brief Enables or disables the specified TIM peripheral.* @param TIMx: where x can be 1 to 17 to select the TIMx peripheral.* @param NewState: new state of the TIMx peripheral.* This parameter can be: ENABLE or DISABLE.* @retval None*/
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_FUNCTIONAL_STATE(NewState));if (NewState != DISABLE){/* Enable the TIM Counter */TIMx->CR1 |= TIM_CR1_CEN;}else{/* Disable the TIM Counter */TIMx->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));}
}
2.5、TIM_ITConfig 使能中断输出信号
函数原型:
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
函数讲解:这个是用来使能中断输出信号的,对应图中的“中断输出控制”。第一个参数TIMx,选择定时器;第二个参数TIM_IT,选择要配置哪个中断输出;第三个参数新的状态,使能还是失能。这种IT_Config之后会经常遇到,就是使能外设的中断输出。
第二个参数可以是下面这些值的任意组合:
* @arg TIM_IT_Update: TIM update Interrupt source* @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source* @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source* @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source* @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source* @arg TIM_IT_COM: TIM Commutation Interrupt source* @arg TIM_IT_Trigger: TIM Trigger Interrupt source* @arg TIM_IT_Break: TIM Break Interrupt source
函数定义:
/*** @brief Enables or disables the specified TIM interrupts.* @param TIMx: where x can be 1 to 17 to select the TIMx peripheral.* @param TIM_IT: specifies the TIM interrupts sources to be enabled or disabled.* This parameter can be any combination of the following values:* @arg TIM_IT_Update: TIM update Interrupt source* @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source* @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source* @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source* @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source* @arg TIM_IT_COM: TIM Commutation Interrupt source* @arg TIM_IT_Trigger: TIM Trigger Interrupt source* @arg TIM_IT_Break: TIM Break Interrupt source* @note * - TIM6 and TIM7 can only generate an update interrupt.* - TIM9, TIM12 and TIM15 can have only TIM_IT_Update, TIM_IT_CC1,* TIM_IT_CC2 or TIM_IT_Trigger. * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_IT_Update or TIM_IT_CC1. * - TIM_IT_Break is used only with TIM1, TIM8 and TIM15. * - TIM_IT_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17. * @param NewState: new state of the TIM interrupts.* This parameter can be: ENABLE or DISABLE.* @retval None*/
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
{ /* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_IT(TIM_IT));assert_param(IS_FUNCTIONAL_STATE(NewState));if (NewState != DISABLE){/* Enable the Interrupt sources */TIMx->DIER |= TIM_IT;}else{/* Disable the Interrupt sources */TIMx->DIER &= (uint16_t)~TIM_IT;}
}
2.6、TIM_InternalClockConfig 选择内部时钟
函数原型:void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
函数讲解:选择内部时钟。参数只有一个TIMx。
函数定义:
/*** @brief Configures the TIMx internal Clock* @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15* to select the TIM peripheral.* @retval None*/
void TIM_InternalClockConfig(TIM_TypeDef* TIMx)
{/* Check the parameters */assert_param(IS_TIM_LIST6_PERIPH(TIMx));/* Disable slave mode to clock the prescaler directly with the internal clock */TIMx->SMCR &= (uint16_t)(~((uint16_t)TIM_SMCR_SMS));
}
2.7、TIM_ITRxExternalClockConfig
函数原型:
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx,
uint16_t TIM_InputTriggerSource);
函数讲解:选择ITR其他定时器的时钟。第一个参数是TIMx,选择要配置的定时器,二个参s数是TIM_InputTriggerSource,选择要接入哪个其他的定时器。
函数定义:
/*** @brief Configures the TIMx Internal Trigger as External Clock* @param TIMx: where x can be 1, 2, 3, 4, 5, 9, 12 or 15 to select the TIM peripheral.* @param TIM_ITRSource: Trigger source.* This parameter can be one of the following values:* @param TIM_TS_ITR0: Internal Trigger 0* @param TIM_TS_ITR1: Internal Trigger 1* @param TIM_TS_ITR2: Internal Trigger 2* @param TIM_TS_ITR3: Internal Trigger 3* @retval None*/
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
{/* Check the parameters */assert_param(IS_TIM_LIST6_PERIPH(TIMx));assert_param(IS_TIM_INTERNAL_TRIGGER_SELECTION(TIM_InputTriggerSource));/* Select the Internal Trigger */TIM_SelectInputTrigger(TIMx, TIM_InputTriggerSource);/* Select the External clock mode1 */TIMx->SMCR |= TIM_SlaveMode_External1;
}
2.8、TIM_TIxExternalClockConfig
函数原型:
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx,
uint16_t TIM_TIxExternalCLKSource,
uint16_t TIM_ICPolarity, uint16_t ICFilter);
函数讲解:选择TIx捕获通道的时钟,第一个参数TIMx选择需要配置的定时器;第二个参数TIM_TIxExternalCLKSource,选择TIx具体的某个引脚;第三个参数TIM_ICPolarity输入的极性;第四个参数ICFilter,输入的滤波器。对于外部引脚的波形,一般都会有极性选择和滤波器,这样更灵活一些。
函数定义:
/*** @brief Configures the TIMx Trigger as External Clock* @param TIMx: where x can be 1, 2, 3, 4, 5, 9, 12 or 15 to select the TIM peripheral.* @param TIM_TIxExternalCLKSource: Trigger source.* This parameter can be one of the following values:* @arg TIM_TIxExternalCLK1Source_TI1ED: TI1 Edge Detector* @arg TIM_TIxExternalCLK1Source_TI1: Filtered Timer Input 1* @arg TIM_TIxExternalCLK1Source_TI2: Filtered Timer Input 2* @param TIM_ICPolarity: specifies the TIx Polarity.* This parameter can be one of the following values:* @arg TIM_ICPolarity_Rising* @arg TIM_ICPolarity_Falling* @param ICFilter : specifies the filter value.* This parameter must be a value between 0x0 and 0xF.* @retval None*/
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter)
{/* Check the parameters */assert_param(IS_TIM_LIST6_PERIPH(TIMx));assert_param(IS_TIM_TIXCLK_SOURCE(TIM_TIxExternalCLKSource));assert_param(IS_TIM_IC_POLARITY(TIM_ICPolarity));assert_param(IS_TIM_IC_FILTER(ICFilter));/* Configure the Timer Input Clock Source */if (TIM_TIxExternalCLKSource == TIM_TIxExternalCLK1Source_TI2){TI2_Config(TIMx, TIM_ICPolarity, TIM_ICSelection_DirectTI, ICFilter);}else{TI1_Config(TIMx, TIM_ICPolarity, TIM_ICSelection_DirectTI, ICFilter);}/* Select the Trigger source */TIM_SelectInputTrigger(TIMx, TIM_TIxExternalCLKSource);/* Select the External clock mode1 */TIMx->SMCR |= TIM_SlaveMode_External1;
}
2.9、TIM_ETRClockMode1Config
函数原型:
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx,
uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
uint16_t ExtTRGFilter);
函数原型:选择ETR通过外部时钟模式1输入的时钟。第二个参数TIM_ExtTRGPrescaler,外部触发预分频器,可以对ETR的外部时钟再提前做一个分频,第三个参数TIM_ExtTRGPolarity输入的极性,第四个参数ExtTRGFilter输入的滤波器。
函数定义:
/*** @brief Configures the External clock Mode1* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.* @param TIM_ExtTRGPrescaler: The external Trigger Prescaler.* This parameter can be one of the following values:* @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF.* @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2.* @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4.* @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8.* @param TIM_ExtTRGPolarity: The external Trigger Polarity.* This parameter can be one of the following values:* @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active.* @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active.* @param ExtTRGFilter: External Trigger Filter.* This parameter must be a value between 0x00 and 0x0F* @retval None*/
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter)
{uint16_t tmpsmcr = 0;/* Check the parameters */assert_param(IS_TIM_LIST3_PERIPH(TIMx));assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler));assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity));assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter));/* Configure the ETR Clock source */TIM_ETRConfig(TIMx, TIM_ExtTRGPrescaler, TIM_ExtTRGPolarity, ExtTRGFilter);/* Get the TIMx SMCR register value */tmpsmcr = TIMx->SMCR;/* Reset the SMS Bits */tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_SMS));/* Select the External clock mode1 */tmpsmcr |= TIM_SlaveMode_External1;/* Select the Trigger selection : ETRF */tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_TS));tmpsmcr |= TIM_TS_ETRF;/* Write to TIMx SMCR */TIMx->SMCR = tmpsmcr;
}
2.10、TIM_ETRClockMode2Config
函数原型:
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx,
uint16_t TIM_ExtTRGPrescaler,
uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
函数讲解:
选择ETR通过外部时钟模式2输入的时钟。参数同上。对于ETR输入的时钟而言,9和10两个函数是等效的,它们的参数也是一样的。如果不需要触发输入的功能,那两个函数可以互换。
函数定义:
/*** @brief Configures the External clock Mode2* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.* @param TIM_ExtTRGPrescaler: The external Trigger Prescaler.* This parameter can be one of the following values:* @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF.* @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2.* @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4.* @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8.* @param TIM_ExtTRGPolarity: The external Trigger Polarity.* This parameter can be one of the following values:* @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active.* @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active.* @param ExtTRGFilter: External Trigger Filter.* This parameter must be a value between 0x00 and 0x0F* @retval None*/
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter)
{/* Check the parameters */assert_param(IS_TIM_LIST3_PERIPH(TIMx));assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler));assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity));assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter));/* Configure the ETR Clock source */TIM_ETRConfig(TIMx, TIM_ExtTRGPrescaler, TIM_ExtTRGPolarity, ExtTRGFilter);/* Enable the External clock mode2 */TIMx->SMCR |= TIM_SMCR_ECE;
}
2.11、TIM_ETRConfig
函数原型:
void TIM_ETRConfig(TIM_TypeDef* TIMx,
uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
uint16_t ExtTRGFilter);
函数讲解:单独用来配置ETR引脚的预分频器、极性、滤波器这些参数的。
函数定义:
/*** @brief Configures the TIMx External Trigger (ETR).* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.* @param TIM_ExtTRGPrescaler: The external Trigger Prescaler.* This parameter can be one of the following values:* @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF.* @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2.* @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4.* @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8.* @param TIM_ExtTRGPolarity: The external Trigger Polarity.* This parameter can be one of the following values:* @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active.* @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active.* @param ExtTRGFilter: External Trigger Filter.* This parameter must be a value between 0x00 and 0x0F* @retval None*/
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter)
{uint16_t tmpsmcr = 0;/* Check the parameters */assert_param(IS_TIM_LIST3_PERIPH(TIMx));assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler));assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity));assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter));tmpsmcr = TIMx->SMCR;/* Reset the ETR Bits */tmpsmcr &= SMCR_ETR_Mask;/* Set the Prescaler, the Filter value and the Polarity */tmpsmcr |= (uint16_t)(TIM_ExtTRGPrescaler | (uint16_t)(TIM_ExtTRGPolarity | (uint16_t)(ExtTRGFilter << (uint16_t)8)));/* Write to TIMx SMCR */TIMx->SMCR = tmpsmcr;
}
2.12、6~11讲解
上面这六个函数对应的就是时基单元的时钟选择部分,可以选择RCC内部时钟、ETR外部时钟、ITRx其他定时器、TIx捕获通道等。
2.13、TIM结构体讲解
typedef struct
{uint16_t TIM_Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock.This parameter can be a number between 0x0000 and 0xFFFF */uint16_t TIM_CounterMode; /*!< Specifies the counter mode.This parameter can be a value of @ref TIM_Counter_Mode */uint16_t TIM_Period; /*!< Specifies the period value to be loaded into the activeAuto-Reload Register at the next update event.This parameter must be a number between 0x0000 and 0xFFFF. */ uint16_t TIM_ClockDivision; /*!< Specifies the clock division.This parameter can be a value of @ref TIM_Clock_Division_CKD */uint8_t TIM_RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounterreaches zero, an update event is generated and counting restartsfrom the RCR value (N).This means in PWM mode that (N+1) corresponds to:- the number of PWM periods in edge-aligned mode- the number of half PWM period in center-aligned modeThis parameter must be a number between 0x00 and 0xFF. @note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef;
2.13.1、TIM_ClockDivision
指定时钟分频,参数可以是TIM_Clock_Division_CKD中的一个值。
时钟分频的作用:
在定时器的外部信号输入引脚, 一般都会有滤波器用来过滤掉信号抖动的干扰。
工作原理是:在一个固定的时钟频率f下进行采样,如果连续N个采样点都为相同的电平,那就代表输入信号稳定了,就把这个采样值输出出去;如果这N个采样值不全都相同,那就说明信号有抖动,这时就保持上一次的输出或者直接输出低电平。这样就能保证输出信号在一定程度上的滤波。
这里的采样频率f和采样点数N都是滤波器的参数。频率越低,采样点数越多,滤波效果越好,不过相应的信号延迟就越大。
滤波器的采样频率f的来源:STM32手册中声明它可以由内部时钟直接而来,也可以是由内部时钟加一个时钟分频而来。分频多少就是由这个参数TIM_ClockDivision决定的。
(这个参数和时基单元关系并不大)
TIM_Clock_Division_CKD:
/** @defgroup TIM_Clock_Division_CKD * @{*/#define TIM_CKD_DIV1 ((uint16_t)0x0000)
#define TIM_CKD_DIV2 ((uint16_t)0x0100)
#define TIM_CKD_DIV4 ((uint16_t)0x0200)
TIM_CKD_DIV1是1分频,即不分频;
TIM_CKD_DIV2是2分频;
TIM_CKD_DIV4是4分频;
2.13.2、TIM_CounterMode
计数器模式。TIM_CounterMode可以是TIM_Counter_Mode中的一个值。
/** @defgroup TIM_Counter_Mode * @{*/#define TIM_CounterMode_Up ((uint16_t)0x0000)
#define TIM_CounterMode_Down ((uint16_t)0x0010)
#define TIM_CounterMode_CenterAligned1 ((uint16_t)0x0020)
#define TIM_CounterMode_CenterAligned2 ((uint16_t)0x0040)
#define TIM_CounterMode_CenterAligned3 ((uint16_t)0x0060)
#define IS_TIM_COUNTER_MODE(MODE) (((MODE) == TIM_CounterMode_Up) || \((MODE) == TIM_CounterMode_Down) || \((MODE) == TIM_CounterMode_CenterAligned1) || \((MODE) == TIM_CounterMode_CenterAligned2) || \((MODE) == TIM_CounterMode_CenterAligned3))
从上到下分别是向上计数、向下计数、三种中央对齐模式。
2.13.3、TIM_Period
周期,就是ARR自动重装器的值。时基单元中关键寄存器的参数之一。
计算方法:
注意:
1.预分频器和计数器都有一个数的偏差,所以使用的时候要-1。、
2.PSC和ARR的取值都要在0~65535之间,不要超出范围。
3.PSC和ARR的取值不是唯一的。可以预分频值给少一点、自动重装给多一点,这样就是以一个比较高的频率计比较多的数;也可以预分频值给多一点、自动重装给少一点,这样就是以一个比较低的频率计比较少的数。两种方法都可以达到目标的定时时间。
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
在这里我们是对72MHz进行7200分频,得到的是10k的计数频率。 在10k的频率下计1w个数,正好是1s的时间。
2.13.4、TIM_Prescaler
PSC预分频器的值。时基单元中关键寄存器的参数之一。
2.13.5、TIM_RepetitionCounter
重复计数器的值。时基单元中关键寄存器的参数之一。是高级定时器才有的。
参数变更
2.14、TIM_PrescalerConfig 单独写入预分频值
函数原型:
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler,
uint16_t TIM_PSCReloadMode);
函数讲解:
这个函数是用来单独写预分频值的。第一个参数Prescaler就是要写入的预分频值,第二个参数TIM_PSCReloadMode是指写入的模式。
预分频器有一个缓冲器,写入的值是在更新时间发生后才有效的。所以这里有个写入的模式,可以选择听从安排,在更新事件生效,或者是在写入后手动产生一个更新事件,让这个值立刻生效。
函数定义:
/*** @brief Configures the TIMx Prescaler.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param Prescaler: specifies the Prescaler Register value* @param TIM_PSCReloadMode: specifies the TIM Prescaler Reload mode* This parameter can be one of the following values:* @arg TIM_PSCReloadMode_Update: The Prescaler is loaded at the update event.* @arg TIM_PSCReloadMode_Immediate: The Prescaler is loaded immediately.* @retval None*/
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_PRESCALER_RELOAD(TIM_PSCReloadMode));/* Set the Prescaler value */TIMx->PSC = Prescaler;/* Set or reset the UG Bit */TIMx->EGR = TIM_PSCReloadMode;
}
2.15、TIM_CounterModeConfig 改变计数器的计数模式
函数原型:void TIM_CounterModeConfig(TIM_TypeDef* TIMx,
uint16_t TIM_CounterMode);
函数讲解:这个函数用于改变计数器的计数模式。参数TIM_CounterMode选择新的计数器模式。
函数定义:
/*** @brief Specifies the TIMx Counter Mode to be used.* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.* @param TIM_CounterMode: specifies the Counter Mode to be used* This parameter can be one of the following values:* @arg TIM_CounterMode_Up: TIM Up Counting Mode* @arg TIM_CounterMode_Down: TIM Down Counting Mode* @arg TIM_CounterMode_CenterAligned1: TIM Center Aligned Mode1* @arg TIM_CounterMode_CenterAligned2: TIM Center Aligned Mode2* @arg TIM_CounterMode_CenterAligned3: TIM Center Aligned Mode3* @retval None*/
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode)
{uint16_t tmpcr1 = 0;/* Check the parameters */assert_param(IS_TIM_LIST3_PERIPH(TIMx));assert_param(IS_TIM_COUNTER_MODE(TIM_CounterMode));tmpcr1 = TIMx->CR1;/* Reset the CMS and DIR Bits */tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));/* Set the Counter Mode */tmpcr1 |= TIM_CounterMode;/* Write to TIMx CR1 register */TIMx->CR1 = tmpcr1;
}
2.16、TIM_ARRPreloadConfig自动重装器预装功能配置
函数原型:void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx,
FunctionalState NewState);
函数讲解:
自动重装器预装功能配置。有无预装是可以自己选择的。
选择方法:第二个参数NewState赋值为使能or失能。
函数定义:
/*** @brief Enables or disables TIMx peripheral Preload register on ARR.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param NewState: new state of the TIMx peripheral Preload register* This parameter can be: ENABLE or DISABLE.* @retval None*/
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_FUNCTIONAL_STATE(NewState));if (NewState != DISABLE){/* Set the ARR Preload Bit */TIMx->CR1 |= TIM_CR1_ARPE;}else{/* Reset the ARR Preload Bit */TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_ARPE);}
}
2.17、TIM_SetCounter 给计数器写入一个值
函数原型:void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
函数讲解:给计数器写入一个值。如果想手动给一个计数值,就可以用这个函数。
函数定义:
/*** @brief Sets the TIMx Counter Register value* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param Counter: specifies the Counter register new value.* @retval None*/
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));/* Set the Counter Register value */TIMx->CNT = Counter;
}
2.18、TIM_SetAutoreload 写入自动重装值
函数原型:void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);
函数讲解:给自动重装器写入一个值。如果想手动给一个自动重装值,就可以用这个函数。
函数定义:
/*** @brief Sets the TIMx Autoreload Register value* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param Autoreload: specifies the Autoreload register new value.* @retval None*/
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));/* Set the Autoreload Register value */TIMx->ARR = Autoreload;
}
2.19、TIM_GetCounter 获取当前计数器的值
函数原型:uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
函数讲解:获取当前计数器的值。如果想要查看当前计数器计到哪里了,就可以调用一下这个函数,返回当前计数器的值。
函数定义:
/*** @brief Gets the TIMx Counter value.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @retval Counter Register value.*/
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));/* Get the Counter Register value */return TIMx->CNT;
}
2.20、TIM_GetPrescaler 获取当前分频器的值
函数原型:uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);
函数讲解:获取当前的预分频器的值。如果想看预分频值,就调用一下这个函数。
函数定义:
/*** @brief Gets the TIMx Prescaler value.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @retval Prescaler Register value.*/
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));/* Get the Prescaler Register value */return TIMx->PSC;
}
2.21、TIM_GetFlagStatus 主程序标志位获取
函数原型:FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
函数讲解:主程序中获取标志位。
函数定义:
/*** @brief Checks whether the specified TIM flag is set or not.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param TIM_FLAG: specifies the flag to check.* This parameter can be one of the following values:* @arg TIM_FLAG_Update: TIM update Flag* @arg TIM_FLAG_CC1: TIM Capture Compare 1 Flag* @arg TIM_FLAG_CC2: TIM Capture Compare 2 Flag* @arg TIM_FLAG_CC3: TIM Capture Compare 3 Flag* @arg TIM_FLAG_CC4: TIM Capture Compare 4 Flag* @arg TIM_FLAG_COM: TIM Commutation Flag* @arg TIM_FLAG_Trigger: TIM Trigger Flag* @arg TIM_FLAG_Break: TIM Break Flag* @arg TIM_FLAG_CC1OF: TIM Capture Compare 1 overcapture Flag* @arg TIM_FLAG_CC2OF: TIM Capture Compare 2 overcapture Flag* @arg TIM_FLAG_CC3OF: TIM Capture Compare 3 overcapture Flag* @arg TIM_FLAG_CC4OF: TIM Capture Compare 4 overcapture Flag* @note* - TIM6 and TIM7 can have only one update flag. * - TIM9, TIM12 and TIM15 can have only TIM_FLAG_Update, TIM_FLAG_CC1,* TIM_FLAG_CC2 or TIM_FLAG_Trigger. * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_FLAG_Update or TIM_FLAG_CC1. * - TIM_FLAG_Break is used only with TIM1, TIM8 and TIM15. * - TIM_FLAG_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17. * @retval The new state of TIM_FLAG (SET or RESET).*/
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)
{ ITStatus bitstatus = RESET; /* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_GET_FLAG(TIM_FLAG));if ((TIMx->SR & TIM_FLAG) != (uint16_t)RESET){bitstatus = SET;}else{bitstatus = RESET;}return bitstatus;
}
2.22、TIM_ClearFlag 主程序中清除标志位
函数原型:void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
函数讲解:主程序中清除标志位。
函数定义:
/*** @brief Clears the TIMx's pending flags.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param TIM_FLAG: specifies the flag bit to clear.* This parameter can be any combination of the following values:* @arg TIM_FLAG_Update: TIM update Flag* @arg TIM_FLAG_CC1: TIM Capture Compare 1 Flag* @arg TIM_FLAG_CC2: TIM Capture Compare 2 Flag* @arg TIM_FLAG_CC3: TIM Capture Compare 3 Flag* @arg TIM_FLAG_CC4: TIM Capture Compare 4 Flag* @arg TIM_FLAG_COM: TIM Commutation Flag* @arg TIM_FLAG_Trigger: TIM Trigger Flag* @arg TIM_FLAG_Break: TIM Break Flag* @arg TIM_FLAG_CC1OF: TIM Capture Compare 1 overcapture Flag* @arg TIM_FLAG_CC2OF: TIM Capture Compare 2 overcapture Flag* @arg TIM_FLAG_CC3OF: TIM Capture Compare 3 overcapture Flag* @arg TIM_FLAG_CC4OF: TIM Capture Compare 4 overcapture Flag* @note* - TIM6 and TIM7 can have only one update flag. * - TIM9, TIM12 and TIM15 can have only TIM_FLAG_Update, TIM_FLAG_CC1,* TIM_FLAG_CC2 or TIM_FLAG_Trigger. * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_FLAG_Update or TIM_FLAG_CC1. * - TIM_FLAG_Break is used only with TIM1, TIM8 and TIM15. * - TIM_FLAG_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17. * @retval None*/
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)
{ /* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_CLEAR_FLAG(TIM_FLAG));/* Clear the flags */TIMx->SR = (uint16_t)~TIM_FLAG;
}
2.23、TIM_GetITStatus 中断程序中获取标志位
函数原型:ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
函数讲解:中断程序中获取标志位。
函数定义:
/*** @brief Checks whether the TIM interrupt has occurred or not.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param TIM_IT: specifies the TIM interrupt source to check.* This parameter can be one of the following values:* @arg TIM_IT_Update: TIM update Interrupt source* @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source* @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source* @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source* @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source* @arg TIM_IT_COM: TIM Commutation Interrupt source* @arg TIM_IT_Trigger: TIM Trigger Interrupt source* @arg TIM_IT_Break: TIM Break Interrupt source* @note* - TIM6 and TIM7 can generate only an update interrupt.* - TIM9, TIM12 and TIM15 can have only TIM_IT_Update, TIM_IT_CC1,* TIM_IT_CC2 or TIM_IT_Trigger. * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_IT_Update or TIM_IT_CC1. * - TIM_IT_Break is used only with TIM1, TIM8 and TIM15. * - TIM_IT_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17. * @retval The new state of the TIM_IT(SET or RESET).*/
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT)
{ITStatus bitstatus = RESET; uint16_t itstatus = 0x0, itenable = 0x0;/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_GET_IT(TIM_IT));itstatus = TIMx->SR & TIM_IT;itenable = TIMx->DIER & TIM_IT;if ((itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET)){bitstatus = SET;}else{bitstatus = RESET;}return bitstatus;
}
2.24、TIM_ClearITPendingBit 中断程序中清除标志位
函数原型:void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
函数讲解:中断程序中清除标志位。
函数定义:
/*** @brief Clears the TIMx's interrupt pending bits.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param TIM_IT: specifies the pending bit to clear.* This parameter can be any combination of the following values:* @arg TIM_IT_Update: TIM1 update Interrupt source* @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source* @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source* @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source* @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source* @arg TIM_IT_COM: TIM Commutation Interrupt source* @arg TIM_IT_Trigger: TIM Trigger Interrupt source* @arg TIM_IT_Break: TIM Break Interrupt source* @note* - TIM6 and TIM7 can generate only an update interrupt.* - TIM9, TIM12 and TIM15 can have only TIM_IT_Update, TIM_IT_CC1,* TIM_IT_CC2 or TIM_IT_Trigger. * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_IT_Update or TIM_IT_CC1. * - TIM_IT_Break is used only with TIM1, TIM8 and TIM15. * - TIM_IT_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17. * @retval None*/
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_IT(TIM_IT));/* Clear the IT pending Bit */TIMx->SR = (uint16_t)~TIM_IT;
}
三、定时中断完整代码
3.1、Timer.h
#ifndef _TIMER_H
#define _TIMER_Hvoid timer_init(void);#endif
3.2、Timer.c
3.2.1、具体步骤
第一步:RCC开启时钟。在这里打开时钟之后,定时器的基准时钟和整个外设的工作时钟就都会同时打开了。
/*第一步:配置rcc时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
第二步:选择时基单元的时钟源。对于定时中断,我们选择内部时钟源。
TIM_InternalClockConfig(TIM2);
第三步:配置时基单元。包括这里的与分频器,计数器计数模式,自动重装器等等。这些参数用一个结构体就可以配置好了。
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
第四步:配置输出中断控制,允许更行中断输出到NVIC。
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;/*中断通道*/NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);
整个模块配置完成之后我们还需要使能一下计数器,不然计数器是不会运行的。当定时器使能后,计时器就会开始报数了。当计时器更新时,触发中断。最后再写一个定时器的中断函数,这样这个中断函数每隔一段时间就能自动执行一次了。
TIM_Cmd(TIM2,ENABLE);
3.2.2、完整代码
#include "stm32f10x.h" // Device headerextern uint16_t num;void timer_init(void)
{/*第一步:配置rcc时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/*配置时基单元*/TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);/*使能更新中断*/TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);/*此时已经开启了更新中断到NVIC的通路*//*配置NVIC通路*//*NVIC优先级分组:*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;/*中断通道*/NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);/*启动定时器*/TIM_Cmd(TIM2,ENABLE);
}void TIM2_IRQHandler(void)
{/*检查中断标志位*/if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);}
}
3.3、main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"uint16_t num;
int main(void)
{OLED_Init();timer_init();/*初始化定时器*/OLED_ShowString(1, 1, "num:");while (1){OLED_ShowNum(1,5,num,5);OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5); }
}
四、一个问题
烧录代码观察现象,发现num是从1开始计数的。但是num的初始值为0,按理说应该是从0开始计数的,但是num一经上电就立刻变为1了,说明中断函数在初始化后就立刻进入了一次。
在TIM_TimeBaseInit的函数定义中:
/*** @brief Initializes the TIMx Time Base Unit peripheral according to * the specified parameters in the TIM_TimeBaseInitStruct.* @param TIMx: where x can be 1 to 17 to select the TIM peripheral.* @param TIM_TimeBaseInitStruct: pointer to a TIM_TimeBaseInitTypeDef* structure that contains the configuration information for the * specified TIM peripheral.* @retval None*/
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{uint16_t tmpcr1 = 0;/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx)); assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));tmpcr1 = TIMx->CR1; if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||(TIMx == TIM4) || (TIMx == TIM5)) {/* Select the Counter Mode */tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;}if((TIMx != TIM6) && (TIMx != TIM7)){/* Set the clock division */tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;}TIMx->CR1 = tmpcr1;/* Set the Autoreload value */TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;/* Set the Prescaler value */TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17)) {/* Set the Repetition Counter value */TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;}/* Generate an update event to reload the Prescaler and the Repetition countervalues immediately */TIMx->EGR = TIM_PSCReloadMode_Immediate;
}
其中最后一行代码上面的注释:
/* Generate an update event to reload the Prescaler and the Repetition counter values immediately */
翻译为:立刻生成一个更新事件,来重新装载预分频器和重复计数器的值。
TIM_TimeBaseInit函数中有 “TIMx->EGR = TIM_PSCReloadMode_Immediate;”这句的原因是:
预分频器是有一个缓冲寄存器的,我们写入的值只有在更新事件时才会真正起作用。所以这里为了让值立刻起作用,就在函数的最后手动生成了一个更新事件,这样,预分频器的值就有效了。
但同时,它的副作用就是更新事件和更新中断是同时发生的,更新中断会置更新标志位。当我们之后一旦初始化结束,更新中断就会立刻进入。这就是我们刚一上电就立刻进入中断的原因。
解决方法:
在TIM_TimeBaseInit()的后面,开启中断的前面,调用一下TIM_ClearFlag()函数,手动将TIM_FLAG_Update更新标志位清除一下,就能避免刚初始化结束就立刻进入中断的问题了。
五、定时中断完整代码(调整后)
5.1、Timer.h
#ifndef _TIMER_H
#define _TIMER_Hvoid timer_init(void);#endif
5.2、Timer.c
5.2.1、具体步骤
第一步:RCC开启时钟。在这里打开时钟之后,定时器的基准时钟和整个外设的工作时钟就都会同时打开了。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
第二步:选择时基单元的时钟源。对于定时中断,我们选择内部时钟源。
TIM_InternalClockConfig(TIM2);
第三步:配置时基单元。包括这里的与分频器,计数器计数模式,自动重装器等等。这些参数用一个结构体就可以配置好了。
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
第四步:配置输出中断控制,允许更行中断输出到NVIC。
/*使能更新中断*/TIM_ClearFlag(TIM2,TIM_FLAG_Update);TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;/*中断通道*/NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);
整个模块配置完成之后我们还需要使能一下计数器,不然计数器是不会运行的。当定时器使能后,计时器就会开始报数了。当计时器更新时,触发中断。最后再写一个定时器的中断函数,这样这个中断函数每隔一段时间就能自动执行一次了。
TIM_Cmd(TIM2,ENABLE);
5.2.2、完整代码
#include "stm32f10x.h" // Device headerextern uint16_t num;void timer_init(void)
{/*第一步:配置rcc时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/*配置时基单元*/TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);/*使能更新中断*/TIM_ClearFlag(TIM2,TIM_FLAG_Update);TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);/*此时已经开启了更新中断到NVIC的通路*//*配置NVIC通路*//*NVIC优先级分组:*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;/*中断通道*/NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);/*启动定时器*/TIM_Cmd(TIM2,ENABLE);
}void TIM2_IRQHandler(void)
{/*检查中断标志位*/if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);}
}
5.3、main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"uint16_t num;
int main(void)
{OLED_Init();timer_init();/*初始化定时器*/OLED_ShowString(1, 1, "num:");while (1){OLED_ShowNum(1,5,num,5);OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5); }
}
这篇关于STM32:TIM定时中断配置的最全库函数讲解笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!