STM32CubeMX系列|输入捕获

输入捕获

1. 输入捕获简介

输入捕获模式可以用来测量脉冲宽度或者测量频率,下图以测量脉宽为例来说明输入捕获的原理

在这里插入图片描述
假定定时器工作在向上计数模式,图中t1-t2的时间就是我们需要测量的低电平时间。测量方法为:首先设置定时器通道x为下降沿捕获,在t1时刻就会捕获到当前的CNT值,然后立即清零CNT,并设置通道x为上升沿捕获,到t2时刻又会发送捕获事件,得到此时的CNT值(记为CCRx2)。在t1-t2之间可能产生N次定时器溢出,因此需要对定时器溢出做处理,防止低电平太长导致数据不准确。
t1-t2之间计数的次数为:N * ARR + CCRx2,再乘以CNT计数周期即可得到低电平持续时间

在这里插入图片描述

2. 硬件设计

本实验通过TIM5的通道1输入捕获功能捕获KEY_UP按键的高电平持续时间,并通过printf函数打印捕获到的高电平时间,用D1指示灯提示系统正常运行

  • D1指示灯
  • K_UP按键
  • USART1串口
  • TIM5

在这里插入图片描述

3. 软件设计

3.1 STM32CubeMX设置
  • RCC设置外接HSE,时钟设置为72M
  • PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
  • 选择TIM5,设置定时器时钟源为内部时钟源、设置通道1为输入捕获模式(PA0自动被选中),NVIC设置中激活定时器中断,在GPIO设置里将PA0下拉保证没有信号输入的时候电平稳定

在这里插入图片描述
在这里插入图片描述

  • 预分频系数设置为72-1,向上计数,自动重装载值设为0xFFFF,则计时器时钟频率为1MHz,计时器周期为1us,定时器溢出周期为 65535 * 1 = 65535us

在这里插入图片描述

  • 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
3.2 MDK-ARM编程
  • 在tim.c文件中编写定时器更新中断处理回调函数
/* TIM5CH1_CAP_STA 各数据位说明
** bit7   捕获完成标志
** bit6	  捕获到高电平标志
** bit5~0 捕获高电平后定时器溢出的次数*/
uint8_t TIM5CH1_CAP_STA = 0;
uint16_t TIM5CH1_CAP_VAL;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    
    
	if((TIM5CH1_CAP_STA & 0X80) == 0){
    
    	//还未成功捕获
		if(TIM5CH1_CAP_STA & 0X40){
    
    		//已经捕获到高电平
			if((TIM5CH1_CAP_STA & 0X3F) == 0X3F){
    
    	//高电平时间太长了
				TIM5CH1_CAP_STA |= 0X80;			//标记为完成一次捕获
				TIM5CH1_CAP_VAL = 0XFFFF;			//计数器值
			}
			else
				TIM5CH1_CAP_STA++;		//溢出次数加1			
		}	
	}
}
  • 在tim.c文件中编写输入捕获中断处理回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
    
    
	if((TIM5CH1_CAP_STA & 0X80) == 0){
    
    	//还未成功捕获
		if(TIM5CH1_CAP_STA & 0X40){
    
    		//捕获到上升沿后条件为真
			TIM5CH1_CAP_STA |= 0X80;	//标记为完成一次高电平捕获
			TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);	//获取当前的计数器值
			TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);	//清除原来的设置		
			TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);	//设置上升沿捕获
		}
		else{
    
    
			TIM5CH1_CAP_STA = 0;
			TIM5CH1_CAP_VAL = 0;
			TIM5CH1_CAP_STA |= 0X40;	//标记捕获到上升沿
			__HAL_TIM_DISABLE(&htim5);	//关闭定时器
			__HAL_TIM_SET_COUNTER(&htim5,0);	//计数器值清零
			TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);	//清除原来的设置				
			TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);	//设置下降沿捕获
			__HAL_TIM_ENABLE(&htim5);	//使能定时器		
		}	
	}
}	

此处的TIM_RESET_CAPTUREPOLARITY() 函数有一处HAL库函数错误,会导致编译该函数报错,解决办法是找到该函数在 stm32f1xx_hal_tim.h 文件中的定义,删除多余的一个反括号 ‘)’

stm32f1xx_hal_tim.h
//修改前
#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__) \
  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP))) :\
   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :\
   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :\
   ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))
//修改后
#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__) \
  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP)) :\
   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :\
   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :\
   ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))
  • 在main.c文件中编写高电平持续时间处理代码
int main(void){
    
    
  long long temp = 0;
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM5_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1);	//一定要开启TIM5通道1的捕获中断
  __HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE);	//一定要开启TIM5的更新中断
  printf("This is TIM_CAP test...\n");
  /* USER CODE END 2 */
  while (1){
    
    
    HAL_Delay(500);
	if(TIM5CH1_CAP_STA & 0X80){
    
    		//完成一次高电平捕获
		temp = TIM5CH1_CAP_STA & 0X3F;
		temp *= 65536;				//溢出总时间
		temp += TIM5CH1_CAP_VAL;	//总的高电平时间
		printf("High level duration:%lld us\r\n",temp);
		TIM5CH1_CAP_STA = 0;		//准备下一次捕获
	}
	HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
  }
}

4. 下载验证

编译无误后下载到开发板,可以看到D1指示灯每500ms闪烁一次,按下KEY_UP后,串口会打印出相应的高电平持续时间

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Chuangke_Andy/article/details/108590177