STM32 HAL/STD库驱动HC-SR04测距
- ✨说明:本文不介绍HC-SR04原理。
-
📌相关篇《STM32F103VC+DS18B20温度+hc-sr04超声波测距+I2C OLED显示》
-
🌿HAL库实现方法比较简易,只需配置2个IO引脚:一个配置为输入,一个配置为输出即可。
-
🌿基于标准库例程,是使用定时器3,输出通道比较模式:TIM_OCMode_PWM1和输入通道捕获上升沿检测实现。
-
🌼HC-SR04
📓标准库驱动函数
- 👉🏻使用的是正点原子资料中的标准库工程模版
- 📝
stm32f10x_HC-SR04.c
#include "stm32f10x_HC-SR04.h"
extern void EnableHCSR04PeriphClock(void);
static void initMeasureTimer() {
RCC_ClocksTypeDef RCC_ClocksStatus;
RCC_GetClocksFreq(&RCC_ClocksStatus);
uint16_t prescaler = RCC_ClocksStatus.SYSCLK_Frequency / 1000000 - 1; //1 tick = 1us (1 tick = 0.165mm resolution)
TIM_DeInit(US_TIMER);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_Prescaler = prescaler;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 0xFFFF;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(US_TIMER, &TIM_TimeBaseInitStruct);
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 15; //us
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(US_TIMER, &TIM_OCInitStruct);
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICFilter = 0;
TIM_PWMIConfig(US_TIMER, &TIM_ICInitStruct);
TIM_SelectInputTrigger(US_TIMER, US_TIMER_TRIG_SOURCE);
TIM_SelectMasterSlaveMode(US_TIMER, TIM_MasterSlaveMode_Enable);
TIM_CtrlPWMOutputs(US_TIMER, ENABLE);
TIM_ClearFlag(US_TIMER, TIM_FLAG_Update);
}
static void initPins() {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = US_TRIG_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(US_TRIG_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = US_ECHO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(US_ECHO_PORT, &GPIO_InitStructure);
}
void InitHCSR04() {
EnableHCSR04PeriphClock();
initPins();
initMeasureTimer();
}
int32_t HCSR04GetDistance() {
(US_TIMER)->CNT = 0;
TIM_Cmd(US_TIMER, ENABLE);
while(!TIM_GetFlagStatus(US_TIMER, TIM_FLAG_Update));
TIM_Cmd(US_TIMER, DISABLE);
TIM_ClearFlag(US_TIMER, TIM_FLAG_Update);
return (TIM_GetCapture2(US_TIMER)-TIM_GetCapture1(US_TIMER))*165/1000;
}
- 📝
stm32f10x_HC-SR04.h
#ifndef __STM32F10X_HC_SR04_H_
#define __STM32F10X_HC_SR04_H_
#include "stm32f10x.h"
#define US_TIMER TIM3
#define US_TRIG_PORT GPIOB
#define US_TRIG_PIN GPIO_Pin_0 //TIM Ch3 (trig output)
#define US_ECHO_PORT GPIOA
#define US_ECHO_PIN GPIO_Pin_6 //TIM Ch1 (echo input)
#define US_TIMER_TRIG_SOURCE TIM_TS_TI1FP1
/**
* How to use this driver:
* 1. Implement EnableHCSR04PeriphClock function and turn on clock for used peripherals
* ex:
* void EnableHCSR04PeriphClock() {
* RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
* RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
* RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
* }
* 2. Call InitHCSR04();
* 3. Get distance (in mm) using HCSR04GetDistance function.
* Value lower than zero means no echo received (distance >3m)
* Measuring takes about 65ms
*
* If necessary, change defines above, but be careful, US_ECHO_PIN must be tim ch1
* and US_TRIG_PIN must be ch3 or ch4. In case of ch4 change TIM_OC3Init into TIM_OC4Init in stm32f10x_HC-SR04.c file
*/
/**
* Implement this function. See instruction at the top of this file.
*/
void EnableHCSR04PeriphClock(void);
/**
* Initialization of HCSR04's peripherals
*/
void InitHCSR04(void);
/**
* Measure distance and get value in mm. Lower than 0 means no echo signal: distance more than ~3m.
*/
int32_t HCSR04GetDistance(void);
#endif /* STM32F10X_HC_SR04_H_ */
- 📝main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "stm32f10x_HC-SR04.h"
void EnableHCSR04PeriphClock() {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
}
int main(void)
{
u8 t = 0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化
InitHCSR04();
while(1)
{
int32_t dist = HCSR04GetDistance();
printf("dist:%d \n",dist);
delay_ms(800);
}
}
HAL库工程
- GPIO引脚配置函数:
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
/*Configure GPIO pin : PA1 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : PA2 */
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
- main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 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 "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.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 */
uint32_t sensor_time;
uint16_t distance;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void delay_us(uint32_t udelay);
uint32_t Read_HCSR04(void);
/* 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_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while(1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
for(uint8_t i = 8; i > 0; i--)
{
sensor_time = Read_HCSR04(); // get the high time
distance += sensor_time * 165 / 1000;
HAL_Delay(5);
}
distance >>= 3;
HAL_Delay(1000);
printf("distance:%d \n", distance);
}
/* 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 */
void delay_us(uint32_t udelay)
{
uint32_t startval, tickn, delays, wait;
startval = SysTick->VAL;
tickn = HAL_GetTick();
//sysc = 72000; //SystemCoreClock / (1000U / uwTickFreq);
delays = udelay * 72; //sysc / 1000 * udelay;
if(delays > startval)
{
while(HAL_GetTick() == tickn)
{
}
wait = 72000 + startval - delays;
while(wait < SysTick->VAL)
{
}
}
else
{
wait = startval - delays;
while(wait < SysTick->VAL && HAL_GetTick() == tickn)
{
}
}
}
uint32_t Read_HCSR04(void)
{
uint32_t local_time = 0;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // pull the trig pin high
delay_us(10); // wait for 10 us
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // pull the trig pin low
// wait for the echo pin to go high
while(!(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2)));
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2)) // while the pin is high
{
local_time++; // increment local time
delay_us(1); // every 1 us
}
return local_time * 2;
}
/* 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 */
📓工程源码
- 🌿标准库工程
链接:https://pan.baidu.com/s/1x6Z7IQ_JHMfXKE3z5zFVFQ
提取码:25q4
- 🌿HAL工程
链接:https://pan.baidu.com/s/12Lzn7WAtL7vbaWgupCI8jQ
提取码:no8c