STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)


MCU:STM32F103ZET6
IDE: MDK-ARM V5 +STM32CubeMX5.2.1

一、打开Cube,建立工程

图片:在这里插入图片描述
点击ACCESS project from MCU
然后选择芯片类型
图片:在这里插入图片描述

二、系统配置

在 Pinout&Configuration—System Core中:
设置时钟RCCHSE(外部高速时钟)为晶振模式:
Crystal/ceramic Resonator在这里插入图片描述
设置系统SYSDebugSerial Wire(SWD调试)在这里插入图片描述

三、配置串口

在 Pinout&Configuration—Connectivity中:
打开UART1,配置工作模式,在NVIC选项中勾选使能在这里插入图片描述

四、配置TIM2

打开TIM2,配置工作模式,在NVIC选项中勾选使能
在这里插入图片描述
注意箭头,点击选择no check

五、在 Clock Configuration中:

配置时钟为72 Mhz。
在这里插入图片描述

六、工程输出配置

在这里插入图片描述
Tips:最好把Linker Settings中的Minimum Heap Size设置为0x600。
在这里插入图片描述
最后点击GENERATE CODE代码就生成了:
在这里插入图片描述
至此,一个工程就创建完了。

七、代码部分处理

printf重定义
见上一贴

中断函数处理
在tim.c文件中添加如下代码

/* USER CODE BEGIN 1 */
void TIM2_IRQHandler(void)
{
  HAL_TIM_IRQHandler(&TIM2_Handler);//定时器共用处理函数
}

uint8_t   TIM2CH1_CAPTURE_STA=0;	//输入捕获状态		    				
uint32_t	TIM2CH1_CAPTURE_VAL;	//输入捕获值(TIM2/TIM5是32位)

//定时器更新中断(计数溢出)中断处理回调函数, 该函数在HAL_TIM_IRQHandler中会被调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//更新中断(溢出)发生时执行
{
	
	if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
	{
			if(TIM2CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
			{
				if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
				{
					TIM2CH1_CAPTURE_STA|=0X80;		//标记成功捕获了一次
					TIM2CH1_CAPTURE_VAL=0XFFFFFFFF;
				}
				else TIM2CH1_CAPTURE_STA++;
			}	 
	}		
}


//定时器输入捕获中断处理回调函数,该函数在HAL_TIM_IRQHandler中会被调用
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕获中断发生时执行
{
	if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
	{
		if(TIM2CH1_CAPTURE_STA&0X40)		//捕获到一个下降沿 		
			{	  			
				TIM2CH1_CAPTURE_STA|=0X80;		//标记成功捕获到一次低电平脉宽
				TIM2CH1_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.
				
				long long temp=0;
				temp=TIM2CH1_CAPTURE_STA&0X3F; 
				temp*=0XFFFFFFFF;		 	    //溢出时间总和
				temp+=TIM2CH1_CAPTURE_VAL;      //得到总的高电平时间
				temp=temp*17/1000;
				printf("distence:%lld cm\r\n",temp);//打印总的高点平时间 
				__HAL_TIM_DISABLE(&htim2);        //关闭定时器2
			}
		else  								//还未开始,第一次捕获上升沿
			{
				TIM2CH1_CAPTURE_STA=0;			//清空
				TIM2CH1_CAPTURE_VAL=0;
				TIM2CH1_CAPTURE_STA|=0X40;		//标记捕获到了上升沿
				__HAL_TIM_DISABLE(&htim2);        //关闭定时器2
				__HAL_TIM_SET_COUNTER(&htim2,0);
				TIM_RESET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1);   //一定要先清除原来的设置!!
				TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);//定时器2通道1设置为上下降沿捕获
				__HAL_TIM_ENABLE(&htim2);//使能定时器5
			}		    
	}		
	
}
/* USER CODE END 1 */

最后直接在main.c中添加

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
	extern uint8_t   TIM2CH1_CAPTURE_STA;	//输入捕获状态		
	extern uint32_t	 TIM2CH1_CAPTURE_VAL;	//输入捕获值(TIM2/TIM5是32位)
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	long long temp=0;
  /* 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_TIM3_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);

printf("\n\r ====================================================================\n\r");
  printf("\n\r FS-STM32F407IGT开发板  输入捕获实验 \n\r");
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);   //开启TIM2的捕获通道1,并且开启捕获中断
  __HAL_TIM_ENABLE_IT(&htim2,TIM_IT_UPDATE);   //使能更新中断
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
			HAL_Delay(1);
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {if(TIM2CH1_CAPTURE_STA&0X80)        //成功捕获到了一次低电平
		{
			HAL_Delay(1000);
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
			HAL_Delay(1);
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
			__HAL_TIM_SET_COUNTER(&htim2,0);
			TIM_RESET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1);   //一定要先清除原来的设置!! 

			TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//定时器2通道1设置为上升沿捕获
			__HAL_TIM_ENABLE(&htim2);//使能定时器2
			TIM2CH1_CAPTURE_STA=0; 
		}


    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

结果展示:在这里插入图片描述

配套代码

相关函数

设置输入捕获极性以及清除输入捕获极性设置
TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);//清除极性设置
TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器 5 通道 1 设置为下降沿捕获

__HAL_TIM_ENABLE(); //开启定时器
__HAL_TIM_ENABLE_IT(&TIM5_Handler,TIM_IT_UPDATE); //使能定时器更新中断

HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel);//同时用来开启定时器的输入捕获通道和使能捕获中断
HAL_StatusTypeDef HAL_TIM_IC_Start (TIM_HandleTypeDef *htim, uint32_t Channel);//,只是开启输入捕获功能

回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);//更新(溢出)中断
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);//捕获中断

八、原理与代码分析

以测量脉宽为例
在这里插入图片描述
通道一设置为上升沿捕获,t1时事件发生,我们记下此时的计数值然后立即清除计数值重新开始计数并设置通道二为下降沿捕获,t2时事件触发记下此时的计数值
CNT计数的次数等于:N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间

源码分析
打开cube生成工程定位到time.c文件

/* TIM2 init function */
void MX_TIM2_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 84;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 0xffffffff;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }

}

我们可以看到定时器定时部分初始化和输入捕获初始化与cube设置相对应

  • 3
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值