前段时间抄袭其他的stm多通道捕获代码,调试没有通过,由于半路出家也不是读得太懂,后来发现官方有个例子,原来固件库里面自带PWM输入功能,经调试稳定可用,代码如下:
//计时器和gpio口的初始化 GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /* TIM2 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* GPIOB clock enable */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); /* TIM2 chennel2 configuration : PA.01 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Connect TIM pin to AF1 */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_1); /* Enable the TIM2 global Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0; TIM_PWMIConfig(TIM2, &TIM_ICInitStructure); /* Select the TIM2 Input Trigger: TI2FP2 */ TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); /* Select the slave Mode: Reset Mode */ TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset); TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable); /* TIM enable counter */ TIM_Cmd(TIM2, ENABLE); /* Enable the CC2 Interrupt Request */ TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
相关中断函数如下:
void TIM2_IRQHandler(void) { RCC_GetClocksFreq(&RCC_Clocks); /* Clear TIM2 Capture compare interrupt pending bit */ TIM_ClearITPendingBit(TIM2, TIM_IT_CC2); /* Get the Input Capture value */ IC2Value = TIM_GetCapture2(TIM2); if (IC2Value != 0) { /* Duty cycle computation */ DutyCycle = (TIM_GetCapture1(TIM2) * 100) / IC2Value; /* Frequency computation TIM2 counter clock = (RCC_Clocks.HCLK_Frequency)/2 */ Frequency = RCC_Clocks.HCLK_Frequency / IC2Value; } else { DutyCycle = 0; Frequency = 0; } }
这个方法经测试,是简单好用的,但根据资料表明这个是通道1和通道2配合实现,其他资料也没有说明如何捕获多个通道,是否能用3和4通道配合捕获,是否1个定时器能捕获2个通道。于是网上查到另一种方法可以1个定时器捕获4个通道(),但是待测试,记录如下:
// STM32 TIM2 4 Channel Input Capture STM32F0-Discovery - [email protected] #include "stm32f0xx.h" #include "stm32f0_discovery.h" //************************************************************************************** void TIM2_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; /* TIM2 Periph clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* TIM2 Configuration */ TIM_DeInit(TIM2); /* Time base configuration */ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz, from 48 MHz TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; // Maximal, TIM2 is 32-bit counter TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // Rising/Falling/BothEdge TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0; TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_3; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_4; TIM_ICInit(TIM2, &TIM_ICInitStructure); /* TIM1 enable counter */ TIM_Cmd(TIM2, ENABLE); /* Enable the CCx Interrupt Request */ TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE); } //************************************************************************************** volatile uint32_t Freq[4]; void TIM2_IRQHandler(void) { uint32_t Current, Delta; static uint32_t Last[4]; if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) { /* Clear TIM2_CH1 Capture compare interrupt pending bit */ TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); Current = TIM_GetCapture1(TIM2); Delta = Current - Last[0]; Last[0] = Current; if (Delta) Freq[0] = 1000000 / Delta; // 1MHz clock // .. } if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET) { /* Clear TIM2_CH2 Capture compare interrupt pending bit */ TIM_ClearITPendingBit(TIM2, TIM_IT_CC2); Current = TIM_GetCapture2(TIM2); Delta = Current - Last[1]; Last[1] = Current; if (Delta) Freq[1] = 1000000 / Delta; // 1MHz clock // .. } if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET) { /* Clear TIM2_CH3 Capture compare interrupt pending bit */ TIM_ClearITPendingBit(TIM2, TIM_IT_CC3); Current = TIM_GetCapture3(TIM2); Delta = Current - Last[2]; Last[2] = Current; if (Delta) Freq[2] = 1000000 / Delta; // 1MHz clock // .. } if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) { /* Clear TIM2_CH4 Capture compare interrupt pending bit */ TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); Current = TIM_GetCapture4(TIM2); Delta = Current - Last[3]; Last[3] = Current; if (Delta) Freq[3] = 1000000 / Delta; // 1MHz clock // .. } } //************************************************************************************** void NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Enable and set TIM2 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } //************************************************************************************** void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* GPIOA Periph clock enable */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); /* Configure TIM2 input */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Connect TIM pins to AF2 */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_2); // TIM2_CH1 PA5 GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_2); // TIM2_CH2 PA1 GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_2); // TIM2_CH3 PA2 GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_2); // TIM2_CH4 PA3 } //************************************************************************************** int main(void) { NVIC_Config(); GPIO_Config(); TIM2_Config(); while(1); /* Infinite loop */ }
还有另外一种方法待测试:
// Hold onto the Channel 1 init structure -- we will use it to reverse // polarity on every edge interrupt. static TIM_ICInitTypeDef TIM_CH1_ICInitStructure; #define GPIO_AF_TIM2 GPIO_AF_2 void ConfigPwmIn() { GPIO_InitTypeDef GPIO_InitStructure; TIM_ICInitTypeDef TIM_ICInitStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_DeInit(TIM2 ); /* TIM2 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* GPIOC clock enable */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE); /* TIM2 GPIO pin configuration : CH1=PD3, C2=PD4, CH3=PD7, CH4=PD6 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOD, &GPIO_InitStructure); /* Connect pins to TIM3 AF2 */ GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_TIM2 ); GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_TIM2 ); GPIO_PinAFConfig(GPIOD, GPIO_PinSource7, GPIO_AF_TIM2 ); GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_TIM2 ); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* Enable capture*/ TIM_CH1_ICInitStructure.TIM_Channel = TIM_Channel_1; TIM_CH1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_CH1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_CH1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_CH1_ICInitStructure.TIM_ICFilter = 0; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_3; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_4; TIM_ICInit(TIM2, &TIM_ICInitStructure); /* Enable TIM2 */ TIM_Cmd(TIM2, ENABLE); /* Enable CC1-4 interrupt */ TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE); /* Clear CC1 Flag*/ TIM_ClearFlag(TIM2, TIM_FLAG_CC1 | TIM_FLAG_CC2 | TIM_FLAG_CC3 | TIM_FLAG_CC4 ); } static volatile uint32_t ccr[4]; static volatile char pulseState = 0; void TIM2_IRQHandler() { if (TIM2 ->SR & TIM_IT_CC1 ) { TIM2 ->SR &= (~TIM_IT_CC1 ); if (pulseState == 0) { TIM_CH1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; // Any time we get a rising edge on CH1, we reset the counter. All channels are // phase aligned, so they all use this as a reference. TIM_SetCounter(TIM2, 0); } else { TIM_CH1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // Pull the value on the falling edge. ccr[0] = TIM_GetCapture1(TIM2 ); } pulseState = !pulseState; // Reverse polarity. TIM_ICInit(TIM2, &TIM_CH1_ICInitStructure); } if (TIM2 ->SR & TIM_IT_CC2 ) { TIM2 ->SR &= (~TIM_IT_CC2 ); ccr[1] = TIM_GetCapture2(TIM2 ); } if (TIM2 ->SR & TIM_IT_CC3 ) { TIM2 ->SR &= (~TIM_IT_CC3 ); ccr[2] = TIM_GetCapture3(TIM2 ); } if (TIM2 ->SR & TIM_IT_CC4 ) { TIM2 ->SR &= (~TIM_IT_CC4 ); ccr[3] = TIM_GetCapture4(TIM2 ); } }