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

文章目录

    • 一、打开Cube,建立工程
    • 二、系统配置
    • 三、配置串口
    • 四、配置TIM2
    • 五、在 Clock Configuration中:
    • 六、工程输出配置
    • 七、代码部分处理
    • 八、原理与代码分析

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

一、打开Cube,建立工程

图片:STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第1张图片
点击ACCESS project from MCU
然后选择芯片类型
图片:STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第2张图片

二、系统配置

在 Pinout&Configuration—System Core中:
设置时钟RCCHSE(外部高速时钟)为晶振模式:
Crystal/ceramic ResonatorSTM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第3张图片
设置系统SYSDebugSerial Wire(SWD调试)STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第4张图片

三、配置串口

在 Pinout&Configuration—Connectivity中:
打开UART1,配置工作模式,在NVIC选项中勾选使能STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第5张图片

四、配置TIM2

打开TIM2,配置工作模式,在NVIC选项中勾选使能
STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第6张图片
注意箭头,点击选择no check

五、在 Clock Configuration中:

配置时钟为72 Mhz。
STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第7张图片

六、工程输出配置

STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第8张图片
Tips:最好把Linker Settings中的Minimum Heap Size设置为0x600。
STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第9张图片
最后点击GENERATE CODE代码就生成了:
STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第10张图片
至此,一个工程就创建完了。

七、代码部分处理

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 */
}

结果展示:STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第11张图片

配套代码

相关函数

设置输入捕获极性以及清除输入捕获极性设置
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);//捕获中断

八、原理与代码分析

以测量脉宽为例
STM32CubeMX学习笔记3——TIM2输入捕获(SR-04测距)_第12张图片
通道一设置为上升沿捕获,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设置相对应

你可能感兴趣的:(CUBEMX)