工作原理

提供一个10uS以上脉冲触发信号-->模块将发出8个40kHz周期电平并检测回波-->输出回响信号
通过发射信号到收到的回响信号时间间隔可以计算得到距离
距离=高电平时间*声速
建议测量周期为60ms以上,以防止发射信号对回响信号的影响
引脚 Trig --> PB10 Echo --> PB0
注意电源接5v,3.3v不可以!!!


uart1配置默认就行

//sr04.h
#ifndef __SR04_H
#define __SR04_H
#include "stm32f1xx_hal.h"
#define TRIG_H HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET)
#define TRIG_L HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET)
#define TRIG_DELAY() HAL_Delay(15)
//状态机状态枚举
typedef enum {
state0=0,
state1,
state2,
state3
}STATE;
void SR04_Init(void);
void SR04_FSM(void);
void SR04_GetData(void);
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);
#endif
//sr04.c
#include "sr04.h"
#include "uart.h"
extern TIM_HandleTypeDef htim3;
volatile STATE state = state0;
volatile static uint8_t ic_cplt; //输入捕获标志位
static uint32_t capture_buf[2];
void SR04_Init(void)
{
HAL_TIM_Base_Start(&htim3);
capture_buf[0] = 0;
capture_buf[1] = 0;
ic_cplt = 0;
}
//状态机,切换状态
void SR04_FSM(void)
{
switch(state)
{
case state0 :
TIM3->CNT = 0;
//__HAL_TIM_SET_COUNTER(&htim3,0); 和上面那句等价
__HAL_TIM_CLEAR_IT(&htim3, TIM_IT_CC3);
//给trig知识10us高电平脉冲信号,trig返回8个40khz脉冲
TRIG_H;
TRIG_DELAY();
TRIG_L ;
//启动上升沿触发,开始输入捕获
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_3);
state = state1 ;
break;
case state1:
if(ic_cplt)
{
ic_cplt = 0;
capture_buf[0]=HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_3);
//捕获上升沿计数值后切换下降沿触发
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_FALLING);
state = state2;
}
break;
case state2:
if(ic_cplt)
{
ic_cplt = 0;
//捕获下降沿计数值
capture_buf[1]=HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_3);
HAL_TIM_IC_Stop_IT(&htim3,TIM_CHANNEL_3);
//测量周期60ms,避免发射信号对回响信号影响
HAL_Delay(60);
state = state3;
}
break;
case state3 :
SR04_GetData();
state = state0;
break;
default:
//错误情况,重置
HAL_TIM_IC_Stop_IT(&htim3,TIM_CHANNEL_3);
state = state0 ;
break;
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3 )
{
ic_cplt = 1;
//发现标志位自己不手动清除也是可以的
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);
}
}
void SR04_GetData(void)
{
uint32_t high_time = 0;
float distance;
//计算计数值,考虑溢出情况
if(capture_buf[1]>capture_buf[0])
{
high_time = capture_buf[1]-capture_buf[0];
}
else if(capture_buf[1]<capture_buf[0])
{
high_time = (TIM3->ARR + 1) - capture_buf[0] + capture_buf[1] ;
}
//距离=高电平时间*声速/2
distance = high_time * 0.034 /2.0f;
//过滤异常值
if(distance<2 || distance>400)
return;
printf("distance:%.2f cm\r\n",distance);
}
//uart.c
#include "uart.h"
extern UART_HandleTypeDef huart1;
//重定向printf用于串口打印数值
int fputc(int ch ,FILE *F)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
return ch;
}
//uart.h
#ifndef __UART_H
#define __UART_H
#include "stm32f1xx_hal.h"
#include "stdio.h"
int fputc(int ch ,FILE *F);
#endif
使用这个记得勾选 Use MicroLIB 小锤子-->Target

//main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "uart.h"
#include "sr04.h"
/* 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 */
/* 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 */
/* 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_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
SR04_Init();
printf("SR04 START\r\n");
while (1)
{
SR04_FSM();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
这里可能有点小问题是,发现串口某个时刻没有数据,因为限制了范围
if(distance<2 || distance>400) return;
可能会卡住
展示


1239

被折叠的 条评论
为什么被折叠?



