-
输入捕获原理
在输入捕获模式下,当检测到ICx信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存
器(TIMx_CCRx)中。当发生捕获事件时,相应的CCxIF标志(TIMx_SR寄存器)被置1,如果开放
了中断或者DMA操作,则将产生中断或者DMA请求。如果发生捕获事件时CCxIF标志已经为
高,那么重复捕获标志CCxOF(TIMx_SR寄存器)被置1。写CCxIF=0可清除CCxIF,或读取存储
在TIMx_CCRx寄存器中的捕获数据也可清除CCxIF。写CCxOF=0可清除CCxOF。
摘自《STM32参考手册中文》 -
简单解释:定时器一直在计数,如果检测到设置的极性边沿,会把当前的计数值存下来,并触发中断;
-
比如,定时器设置为TIM2,预分频719,计数周期0xFFFF,则TIM2 10us计数一次,计数到0xFFFF,重装载到0;现在设置的输入捕获极性为上升沿捕获,则当某通道捕获到一次上升沿后,触发中断,并将当前的计数值存在对应通道的CCR值;
-
所以无论是设置为上升沿捕获还是下降沿捕获,都只能得到整个脉冲的周期时间;如果是想获得高电平占整个周期的百分比呢?
-
那么我就需要在最开始设置为上升沿捕获,当捕获到一个上升沿后,把极性设置为下降沿捕获,依次类推,这样我们就可以得到高电平时间和周期时间了;注意要设置好标志位
-
这里的话会出现一个问题,比如我的上升沿时间点在上一个周期,下降沿时间点在下一个周期,那么在下降沿-上升沿之前还要再加上一个定时器周期
-
以下是我的STM32CubeMx配置
8. 以下是比较重要的代码
/* Private variables ---------------------------------------------------------*/
uint16_t Channel1HighTime, Channel2HighTime, Channel3HighTime, Channel4HighTime;
uint16_t Channel1Period, Channel2Period, Channel3Period, Channel4Period;
uint8_t Channel1Edge = 0, Channel2Edge = 0, Channel3Edge = 0, Channel4Edge = 0;
uint16_t Channel1Percent, Channel2Percent, Channel3Percent, Channel4Percent;
uint16_t Channel1PercentTemp[3] = {0, 0, 0};
uint8_t Channel1TempCount = 0;
uint16_t Channel1RisingTimeLast=0, Channel1RisingTimeNow, Channel1FallingTime;
uint16_t Channel2RisingTimeLast=0, Channel2RisingTimeNow, Channel2FallingTime;
uint16_t Channel3RisingTimeLast=0, Channel3RisingTimeNow, Channel3FallingTime;
uint16_t Channel4RisingTimeLast=0, Channel4RisingTimeNow, Channel4FallingTime;
/* USER CODE END PV */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_IC_CaptureCallback could be implemented in the user file
*/
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if(Channel1Edge == 0)
{
Channel1RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);//获取上升沿时间点
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);//切换捕获极性
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
Channel1Edge = 1;
if(Channel1RisingTimeLast == 0)
{
Channel1Period = 0;
}
else
{
if(Channel1RisingTimeNow > Channel1RisingTimeLast)
{
Channel1Period = Channel1RisingTimeNow - Channel1RisingTimeLast;
}
else
{
Channel1Period = Channel1RisingTimeNow + 0xffff - Channel1RisingTimeLast + 1;
}
}
Channel1RisingTimeLast = Channel1RisingTimeNow;
}
else if(Channel1Edge == 1)
{
Channel1FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
if(Channel1FallingTime < Channel1RisingTimeNow)
{
Channel1HighTime = Channel1FallingTime + 0xffff - Channel1RisingTimeNow + 1;
}
else
{
Channel1HighTime = Channel1FallingTime - Channel1RisingTimeNow;
}
if(Channel1Period != 0)
{
Channel1Percent = (uint8_t)(((float)Channel1HighTime / Channel1Period) * 1000);
printf("Channel1 = %d ", Channel1Percent);
}
Channel1Edge = 0;
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(Channel2Edge == 0)
{
Channel2RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
Channel2Edge = 1;
if(Channel2RisingTimeLast == 0)
{
Channel2Period = 0;
}
else
{
if(Channel2RisingTimeNow > Channel2RisingTimeLast)
{
Channel2Period = Channel2RisingTimeNow - Channel2RisingTimeLast;
}
else
{
Channel2Period = Channel2RisingTimeNow + 0xffff - Channel2RisingTimeLast + 1;
}
}
Channel2RisingTimeLast = Channel2RisingTimeNow;
}
else if(Channel2Edge == 1)
{
Channel2FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
if(Channel2FallingTime < Channel2RisingTimeNow)
{
Channel2HighTime = Channel2FallingTime + 0xffff - Channel2RisingTimeNow + 1;
}
else
{
Channel2HighTime = Channel2FallingTime - Channel2RisingTimeNow;
}
if(Channel2Period != 0)
{
Channel2Percent = (uint8_t)(((float)Channel2HighTime / Channel2Period) * 1000);
printf("Channel2 = %d ", Channel2Percent);
}
Channel2Edge = 0;
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
if(Channel3Edge == 0)
{
Channel3RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_3);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
Channel3Edge = 1;
if(Channel3RisingTimeLast == 0)
{
Channel3Period = 0;
}
else
{
if(Channel3RisingTimeNow > Channel3RisingTimeLast)
{
Channel3Period = Channel3RisingTimeNow - Channel3RisingTimeLast;
}
else
{
Channel3Period = Channel3RisingTimeNow + 0xffff - Channel3RisingTimeLast + 1;
}
}
Channel3RisingTimeLast = Channel3RisingTimeNow;
}
else if(Channel3Edge == 1)
{
Channel3FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_3);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
if(Channel3FallingTime < Channel3RisingTimeNow)
{
Channel3HighTime = Channel3FallingTime + 0xffff - Channel3RisingTimeNow + 1;
}
else
{
Channel3HighTime = Channel3FallingTime - Channel3RisingTimeNow;
}
if(Channel3Period != 0)
{
Channel3Percent = (uint8_t)(((float)Channel3HighTime / Channel3Period) * 1000);
printf("Channel3 = %d ", Channel3Percent);
}
Channel3Edge = 0;
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
if(Channel4Edge == 0)
{
Channel4RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
Channel4Edge = 1;
if(Channel4RisingTimeLast == 0)
{
Channel4Period = 0;
}
else
{
if(Channel4RisingTimeNow > Channel4RisingTimeLast)
{
Channel4Period = Channel4RisingTimeNow - Channel4RisingTimeLast;
}
else
{
Channel4Period = Channel4RisingTimeNow + 0xffff - Channel4RisingTimeLast + 1;
}
}
Channel4RisingTimeLast = Channel4RisingTimeNow;
}
else if(Channel4Edge == 1)
{
Channel4FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
if(Channel4FallingTime < Channel4RisingTimeNow)
{
Channel4HighTime = Channel4FallingTime + 0xffff - Channel4RisingTimeNow + 1;
}
else
{
Channel4HighTime = Channel4FallingTime - Channel4RisingTimeNow;
}
if(Channel4Period != 0)
{
Channel4Percent = (uint8_t)(((float)Channel4HighTime / Channel4Period) * 1000);
printf("Channel4 = %d\n", Channel4Percent);
}
Channel4Edge = 0;
}
}
}