在stm32中文手册中有如下图(也就是通用定时器的结构图):
在通用定时器中,输入捕获主要用到以上部分,STM32的每个通用定时器都有4个输入捕获的通道,分别是TIMx_CH1、TIMx_CH2、TIMx_CH3、TIMx_CH4。我们可以在输入滤波器和边沿检测器中设置我们需要捕获的是上升沿还是下降沿,假设我们需要捕获上升沿,则当滤波器和边沿检测器捕获到上升沿后,CNT计数器中的值会加1,同时捕获/比较寄存器中会锁存计数器的值。
其中需要将PA0端口进行复用,复用为TIM5的通道1,所以我们需要开启复用时钟,GPIOA时钟。
(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等
voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct);
(3)设置通用定时器的输入捕获参数,开启输入捕获功能
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
其中TIM_ICInitTypeDef结构体中的成员大致意思为:
typedef struct{uint16_t TIM_Channel; //通道uint16_t TIM_ICPolarity; //捕获极性uint16_t TIM_ICSelection;//映射uint16_t TIM_ICPrescaler;//分频系数uint16_t TIM_ICFilter; //滤波器长度} TIM_ICInitTypeDef;
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //通道1TIM_ICInitStructure.TIM_ICFilter=0x00; //滤波TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1TIM_ICInit(TIM5,&TIM_ICInitStructure);
(4)开启捕获和定时器溢出(更新)中断
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE)
(5)设置定时器中断优先级,使能定时器中断通道
NVIC初始化库函数是NVIC_Init()
(6)编写定时器中断服务函数
TIM5_IRQHandlerITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);TIM_SetCounter(TIM5,0); //定时器初值为0
(7)使能定时器
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
下面有一个输入捕获大致代码(以判断但双击按键为例):
- void Tim_Input_Capture(u16 per,u16 psc)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
- TIM_ICInitTypeDef TIM_ICInitStruct;
- NVIC_InitTypeDef NVIC_InitStruct;
- /*1、打开外设时钟*/
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO , ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
-
- /*2、配置GPIO*/
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
- GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- /*3、配置定时器*/
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
- TIM_TimeBaseInitStruct.TIM_Period = per;
- TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
- TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStruct);
-
- /*4、配置输入捕获*/
- TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
- TIM_ICInitStruct.TIM_ICFilter = 0x0;
- TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
- TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
- TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
- TIM_ICInit(TIM5, &TIM_ICInitStruct);
-
- /*5、配置定时器中断*/
- TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1, ENABLE);
-
- /*6、配置NVIC*/
- NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn;
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
- NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
- NVIC_Init(&NVIC_InitStruct);
-
- /*7、使能定时器*/
- TIM_Cmd(TIM5, ENABLE);
- }
服务中断函数:
- void TIM5_IRQHandler(void)
- {
- if((input_state & NEXT_RISING ) != SET)
- {
- if(TIM_GetITStatus(TIM5, TIM_IT_Update) == SET)
- {
- if(input_state & NEXT_FALLING)//捕获到上升沿
- {
- if((input_state & 0x3F) == 0x3F)//如果溢出次数超出阈值
- {
- input_value = 0xFFFF;
- input_state |= NEXT_RISING;
- }
- else
- input_state++;
- }
- }
- if(TIM_GetITStatus(TIM5, TIM_IT_CC1) == SET)
- {
- if(input_state & NEXT_FALLING)//捕获到下降沿
- {
- //获取捕获到的值
- //改为上升沿捕获
- input_value = TIM_GetCapture1(TIM5);
- TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);
- input_state |= NEXT_RISING;
- }
- else//捕获到上升沿
- {
- //清零input_state和input_value
- //关闭定时器
- //清空当前计数值
- //将下一次捕获改为下降沿捕获
- //标志下一次捕获下降沿
- //打开定时器
- input_state = 0;
- input_value = 0;
- TIM_Cmd(TIM5, DISABLE);
- TIM_SetCounter(TIM5, 0);
- TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);
- input_state |= NEXT_FALLING;
- TIM_Cmd(TIM5, ENABLE);
- }
- }
- }
- TIM_ClearITPendingBit(TIM5, TIM_IT_Update | TIM_IT_CC1);
- }