STM32L431(CubeMX)使用HC_SR04超声波模块测量距离并通过串口打印

12 篇文章 3 订阅
1 篇文章 0 订阅


参考文章:

【STM32】HAL库 STM32CubeMX教程八—定时器输入捕获

一、开发平台

·小熊派(STM32L431)
·HC_SR04超声波模块
·keil5
·cubemx
·使用HAL库

二、HC_SR04介绍

·实物图:
在这里插入图片描述
·基本工作原理
在这里插入图片描述
在这里插入图片描述

通过时序图可知,需要在TRIG的IO口上给出10us及以上的高电平信号,模块内部自动发出8个40KHz脉冲,自动检测是否有信号返回,若有信号返回,测量高电平在ECHO的IO口中输出的时间,测量距离 = (ECHO高电平输出时间*声速(340M/s)/2),建议测量周期在60ms(大约2.5cm)以上,否则测距功能会失效。

三、CubeMX配置

·选择芯片
在这里插入图片描述
RCC选择外部高速时钟
在这里插入图片描述
配置SYS
在这里插入图片描述
配置时钟树,stm32l431最大时钟频率为80MHz
在这里插入图片描述
配置USART,按默认配置,引脚默认在PA9,PA10。
在这里插入图片描述
配置TIM2时钟
在这里插入图片描述
·预分频填80-1,时钟计数频率 = 80MHz/PSC+1=1Mhz ,即计数频率为1us
·上升沿捕获
·自动装载值设置为32Bit最大值 65535
·并在NVIC设置中使能TIM2中断
在这里插入图片描述
配置GPIO,配置PB9作为TRIG,默认输出低电平
在这里插入图片描述

设置路径,工程名称,编译器
在这里插入图片描述
勾选代码生成
在这里插入图片描述

四、keil5代码部分

1、printf重定向

首先勾选Use MicroLIB调用MDK的微库,MicroLIB是对C标准库高度优化之后的库,比标准库代码更少,使用效率更高。
在这里插入图片描述

在usart.c文件最后加上代码,这里不使用HAL库函数HAL_UART_Transmit来发送数据,直接操作寄存器来发送,效率更高。

/* USER CODE BEGIN 1 */
#if 1
#include <stdio.h>
int fputc(int ch, FILE *stream)
{
    /* 堵塞判断串口是否发送完成 */
    while((USART1->ISR & 0X40) == 0);

    /* 串口发送完成,将该字符发送 */
    USART1->TDR = (uint8_t) ch;

    return ch;
}

#endif
/* USER CODE END 1 */

2、创建HC_SR04.c/.h文件

在这里插入图片描述
在这里插入图片描述

3、HC_SR04.h

·为了防止头文件重复定义

#ifndef	__HC_SR04_H__
#define __HC_SR04_H__

#endif

·添加所需头文件

#ifndef	__HC_SR04_H__
#define __HC_SR04_H__

#include "stm32l4xx_hal.h"
#include "tim.h"
#include "usart.h"
#include <stdio.h>

#endif

·定义TRIG高电平与低电平

#define TRIG_L	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET)
#define TRIG_H	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET)

·声明函数

void delay_us(uint16_t us);
void Get_Distance(void);

4、HC_SR04.c

·包含头文件以及定义变量

#include "HC_SR04.h"

float distance;		//测量距离
uint32_t capture_value1;	//存放定时器捕获值数组
uint32_t capture_value2;
uint8_t cnt=0;		//状态计数值

·HC_SR04模块需要用到us级延时,而HAL库中的HAL_Delay只支持ms级延时,所以自己实现us延时

void delay_us(uint16_t us)
{     
	uint16_t differ = 0xffff-us-5;				
	__HAL_TIM_SET_COUNTER(&htim2,differ);	//设定TIM2计数器起始值
	HAL_TIM_Base_Start(&htim2);		//启动定时器	
	
	while(differ < 0xffff-5){	//判断
		differ = __HAL_TIM_GET_COUNTER(&htim2);		//查询计数器的计数值
	}
	HAL_TIM_Base_Stop(&htim2);
}

·根据时序图可知

/*
HC_SR04启动函数:触发信号顺序
给TRIG一个低电平,延时10us以上,再给TRIG一个高电平
*/
void HC_SR04_Start(void)
{
	TRIG_L;	
	delay_us(20);
	TRIG_H;
}

·tim中断回调函数

/*中断回调函数*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//
{
	
		if(TIM2 == htim->Instance)// 判断触发的中断的定时器为TIM2
		{	
			switch(cnt){
			case 1:
			capture_value1 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);  //设置为下降沿捕获
			cnt++;
			break;
			
			case 2:
			capture_value2 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.
			HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_1); //停止捕获   或者: __HAL_TIM_DISABLE(&htim2);			
			cnt++;
		}
	}
}

·获得测量后的距离

/*
获取HC_SR04测出与目标之间的距离

*/
void Get_Distance(void)
{
	uint16_t measure;
	switch(cnt){
		case 0:
		HC_SR04_Start();
		__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
		HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);	//启动输入捕获       或者: __HAL_TIM_ENABLE(&htim5);   
		cnt++;
		break;
	
		case 3:
		measure = capture_value2-capture_value1;
		distance = (measure*0.034)/2;
		printf("距离为%f cm\r\n",distance);
		cnt = 0;
		TIM2->CNT = 0;
		break;

	}
}

实现以上功能的流程

1.设置TIM2 CH1为输入捕获功能;
2.设置上升沿捕获;
3.使能TIM2 CH1捕获功能;
4.捕获到上升沿后,定时器当前计数值存入capture_value1,改为捕获下降沿;
5.捕获到下降沿后,定时器当前计数值存入存入capture_value2,关闭TIM2 CH1捕获功能; cnt=3;
6. 高电平时间: capture_value2 - capture_value1 重新启动输入捕获

__HAL_TIM_SET_COUNTER(&TIM2_Handler,0); //设置计数寄存器的值变为0
HAL_TIM_PWM_Start() 函数用于使能定时器某一通道的PWM输出。
HAL_TIM_IC_Start_IT() 函数用于使能定时器某一通道的输入捕获功能,并使能相应的中断
HAL_TIM_IC_Stop_IT() 函数和开启功能相反,是关闭定时器某一通道的输入捕获功能和相应中断
__HAL_TIM_SET_CAPTUREPOLARITY不是函数,而是底层操作的一个宏定义
在stm32l4xx_hal_tim.h文件中可以找到。其作用是修改定时器某一通道的输入捕获极性在这里插入图片描述
其中有两个函数,第一个为清除清除原来的捕获极性,第二个为设置通道捕捉极性

TIM_RESET_CAPTUREPOLARITY(&TIM2_Handler,TIM_CHANNEL_1);   //一定要先清除原来的捕获极性!!
TIM_SET_CAPTUREPOLARITY(&TIM2_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器2通道1设置为下降沿捕获(重设捕获极性)

在修改定时器某一通道的输入捕获极性时,一定要先清除该通道之前捕获极性
__HAL_TIM_GET_COMPARE也是一个宏定义。 
在stm32l4xx_hal_tim.h文件中可以找到。其作用是获取定时器某一通道的捕获/比较寄存器值,等价于 : HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
在这里插入图片描述
两者都是直接读取对应CCRx寄存器的值

5、main.c

在main函数的循环中添加

/* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		Get_Distance();
		HAL_Delay(500);
  }
  /* USER CODE END 3 */

五、接线

HC_SR04开发板
VCC5V
TRIGPB9
ECHOPA0
GNDGND

六、串口打印效果

在这里插入图片描述

作者能力有限,如有出错,希望各位大佬帮忙指出,谢谢

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用标准库和 HC-SR04 模块进行远距离超声波测距的 stm32 代码: ```c #include "stm32f10x.h" #include <stdio.h> #define TRIG_PIN GPIO_Pin_0 #define TRIG_PORT GPIOA #define ECHO_PIN GPIO_Pin_1 #define ECHO_PORT GPIOA void delay_us(uint32_t nus) { uint32_t i; for (i = 0; i < nus * 8; i++); } void delay_ms(uint32_t nms) { uint32_t i; for (i = 0; i < nms * 8000; i++); } void send_trigger_pulse(void) { GPIO_WriteBit(TRIG_PORT, TRIG_PIN, Bit_SET); delay_us(10); GPIO_WriteBit(TRIG_PORT, TRIG_PIN, Bit_RESET); } float measure_distance(void) { uint32_t start_tick = 0, end_tick = 0; float distance = 0; while (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == RESET); start_tick = TIM_GetCounter(TIM2); while (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == SET); end_tick = TIM_GetCounter(TIM2); distance = (float)(end_tick - start_tick) * 1.7 / 100.0; return distance; } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = TRIG_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(TRIG_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ECHO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(ECHO_PORT, &GPIO_InitStructure); TIM_TimeBaseInitStructure.TIM_Period = 0xFFFF; TIM_TimeBaseInitStructure.TIM_Prescaler = 71; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); TIM_Cmd(TIM2, ENABLE); while (1) { send_trigger_pulse(); delay_ms(50); float distance = measure_distance(); // Do something with the measured distance printf("Distance: %.2f cm\n", distance); } } ``` 与之前的代码相比,这个代码主要是增加了使用标准库的 printf 函数来输出测量到的距离。如果你想使用 printf 函数,需要在工程中添加相应的库文件和头文件。在这个例子中,我们使用的是 Keil MDK-ARM 开发环境,所以需要添加 stdio.h 和 retarget.c 两个文件。在 retarget.c 文件中,需要实现 _write 函数,用于将 printf 函数的输出重定向到串口。 当然,如果你不想使用 printf 函数,也可以通过其他方法来处理测量到的距离

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值