使用STM32定时器输入捕获实现HC-SR04超声波测距
一、简单介绍
笔者所使用的SR04模块如下图所示
二、工作原理
三、电路连接
笔者的单片机为STM32F103CBT6,使用TIM2的通道1作为输入捕获通道,PA1作为触发的GPIO
因此接线如下
VCC–>3V3
ECHO–>PA0
TRIG–>PA1
GND–>GND
四、cubemx配置
配置定时器2
需要开启定时器2的中断
开启串口1作为显示输出
时钟配置
五、代码编写
添加串口重定向代码至usart.c文件中
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
根据工作原理,思路非常简单:我们想要测距的时候,在TRIG引脚产生一个高电平持续至少10us的脉冲,超声波模块就会启动,然后也返回一个脉冲,我们只需要测量这个脉冲的高电平持续时间就能知道距离。
在输入捕获回调函数中进行配置,因为当通道捕获到高电平时,就要立刻设置捕获策略为捕获低电平,否则无法测量高电平持续时间,得到的只不过是两个上升沿的时间间隔罢了。
考虑定义一个结构体用来存放信息。
代码如下
SR04.c
#include "sr04.h"
SR04_PulseType pulse;
void SR04_Init()
{
HAL_TIM_Base_Start_IT(&SR04_TIM);
HAL_TIM_IC_Start_IT(&SR04_TIM,SR04_CHANNEL);
}
void SR04_Start()
{
HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_RESET);
pulse.rising_flag =1;
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(pulse.rising_flag)
{
pulse.start = HAL_TIM_ReadCapturedValue(&SR04_TIM,SR04_CHANNEL);
__HAL_TIM_SET_CAPTUREPOLARITY(&SR04_TIM,SR04_CHANNEL,TIM_INPUTCHANNELPOLARITY_FALLING);
pulse.rising_flag = 0;
}
else
{
__HAL_TIM_SET_CAPTUREPOLARITY(&SR04_TIM,SR04_CHANNEL,TIM_INPUTCHANNELPOLARITY_RISING);
pulse.end = HAL_TIM_ReadCapturedValue(&SR04_TIM,SR04_CHANNEL);
pulse.rising_flag = 1;
}
}
void SR04_Calculate()
{
if(pulse.end > pulse.start)
pulse.cnt = pulse.end - pulse.start;
else
pulse.cnt = SR04_COUNT_PERIOD + pulse.end - pulse.start;
pulse.distance = pulse.cnt * SPEED *100 / 2.0f /1000.0f /1000.0f;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
}
sr04.h
#ifndef SR04_H
#define SR04_H
#include "main.h"
#include "tim.h"
#include "stdio.h"
#define SPEED 340.0f
#define SR04_TIM htim2
#define SR04_CHANNEL TIM_CHANNEL_1
#define SR04_COUNT_PERIOD 10000
typedef struct
{
uint16_t start;
uint16_t end;
uint16_t cnt;
float distance;
uint8_t rising_flag;
}SR04_PulseType;
extern SR04_PulseType pulse;
void SR04_Init();
void SR04_Start();
void SR04_Calculate();
#endif
主函数主要代码
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_TIM2_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
SR04_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
SR04_Start();
SR04_Calculate();
printf("%d\t%.3fmm\r\n",pulse.cnt,pulse.distance);
HAL_Delay(200);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
波形如下
高电平持续时间约为472us,与串口显示数据一致。
串口显示如下
作者:田甲