9. STM32——HC_SR04超声波测距

本文详细介绍了如何使用STM32配合HC-SR04超声波传感器进行测距操作。内容包括模块的基本参数、工作原理、时序图以及详细的步骤实现,如GPIO和TIM配置、中断服务函数等。通过提供的C代码,展示了从启动到关闭定时器、获取Echo时间及计算距离的完整过程。
摘要由CSDN通过智能技术生成

HC_SR04

实物图

在这里插入图片描述

基本参数

在这里插入图片描述

工作原理

在这里插入图片描述

时序图

在这里插入图片描述

在这里插入图片描述

超声波测距步骤

在这里插入图片描述

1. 使能GPIO时钟、定时器时钟

//1.使能GPIO时钟、定时器时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

2. 配置GPIO引脚

GPIO_InitTypeDef GPIOinitStructure;
TIM_TimeBaseInitTypeDef TIMInitStructure;

//2.配置GPIO
		
//Trig B11
GPIOinitStructure.GPIO_Mode  = GPIO_Mode_Out_PP; //推挽输出
GPIOinitStructure.GPIO_Pin   = GPIO_Pin_11; //GPIOB11
GPIOinitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50Hz
GPIO_Init(GPIOB, &GPIOinitStructure); //初始化结构体
	
//Echo B10
GPIOinitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING; //浮空输入
GPIOinitStructure.GPIO_Pin   = GPIO_Pin_10; //GPIOB10
GPIO_Init(GPIOB, &GPIOinitStructure); //初始化结构体

3.配置TIM定时器时钟

定时时间 =(Prescaler+1)×(Counter +1)/ 定时器时钟频率

定时时间为 1ms,可设置 Prescaler = 72-1;Period = 1000 - 1;(TIM4时钟频率设置为72MHz)

TIM_TimeBaseInitTypeDef TIMInitStructure;

TIMInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //不分频 72MHz
TIMInitStructure.TIM_CounterMode   = TIM_CounterMode_Up; //向上计数模式
TIMInitStructure.TIM_Period        = 1000-1; 
TIMInitStructure.TIM_Prescaler     = 72-1;
		
TIM_TimeBaseInit(TIM4, &TIMInitStructure); //初始化
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); //定时器中断配置

TIM_Cmd(TIM4, DISABLE);//失能定时器

4. 配置NVIC优先级

NVIC_InitTypeDef NVICinitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //优先级1组

//配置中断优先级
NVICinitStructure.NVIC_IRQChannel                   = TIM4_IRQn; //TIM4中断的入口地址
NVICinitStructure.NVIC_IRQChannelPreemptionPriority = 0; //0级抢占优先级
NVICinitStructure.NVIC_IRQChannelSubPriority        = 0; //0级子优先级
NVICinitStructure.NVIC_IRQChannelCmd                = ENABLE; //使能
		
NVIC_Init(&NVICinitStructure); //初始化

5. 开启TIM4定时器

void TIM4_Open(void)
{
		TIM_SetCounter(TIM4, 0); //从0开始计数
		mscount=0; //设置为测量次数0
		TIM_Cmd(TIM4, ENABLE); //使能定时器
}

6. 关闭TIM4定时器

void TIM4_Close(void)
{
		TIM_Cmd(TIM4, DISABLE);
}

7. TIM4定时器中断服务函数

void TIM4_IRQHandler(void)
{
		if( TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET ) //发生中断
		{
				TIM_ClearITPendingBit(TIM4, TIM_IT_Update); //清除中断标志
			
				mscount++; //测量次数+1
		}
}

8. 获取Echo时间

在这里插入图片描述

int Get_Echo_TIM(void)
{
		uint32_t t=0;
		
		t=mscount*1000; //计时次数*定时us
		t+=TIM_GetCounter(TIM4); //总时间=获取定时器时间+计时次数*定时us
		
		TIM4->CNT = 0; //从0开始计时
		
		delay_us(50);
		
		return t;
}

9. 获取距离

float Get_Length(void)
{
		int i=0;
		uint32_t t=0;
		float sum=0;
		float length=0;
		
		while( i!=5 )
		{
				Trig_Send_Open;
				delay_us(60);
				Trig_Send_Close;
				
				while( Echo_Receive == 0 ); //一直等待低电平结束,否则卡死
					TIM4_Open();
					i++;
				
				while( Echo_Receive == 1 );
					TIM4_Close();
					t=Get_Echo_TIM();
					length=((float) t/58); //公式
					sum+=length;
		}
		length=sum/5;
		
		return length;
}

整合代码

HC_SR04.c

#include "HC_SR04.h"
#include "stm32f10x.h"
#include "SysTick.h"

extern uint16_t mscount=0;

void HC_SR04Init(void)
{
		GPIO_InitTypeDef GPIOinitStructure;
		TIM_TimeBaseInitTypeDef TIMInitStructure;
		NVIC_InitTypeDef NVICinitStructure;
		
		//1.使能GPIO时钟、计时器时钟
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

		//2.配置GPIO
		
		//Trig B11
		GPIOinitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
		GPIOinitStructure.GPIO_Pin   = GPIO_Pin_11;
		GPIOinitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOB, &GPIOinitStructure);
	
		//Echo B10
		GPIOinitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
		GPIOinitStructure.GPIO_Pin   = GPIO_Pin_10;
		GPIO_Init(GPIOB, &GPIOinitStructure);
		
		//3.配置TIM
		TIMInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
		TIMInitStructure.TIM_CounterMode   = TIM_CounterMode_Up;
		TIMInitStructure.TIM_Period        = 1000-1;
		TIMInitStructure.TIM_Prescaler     = 72-1;
		
		TIM_TimeBaseInit(TIM4, &TIMInitStructure);
		TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);

		TIM_Cmd(TIM4, DISABLE);
		
		//配置中断优先级
		NVICinitStructure.NVIC_IRQChannel                   = TIM4_IRQn;
		NVICinitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVICinitStructure.NVIC_IRQChannelSubPriority        = 0;
		NVICinitStructure.NVIC_IRQChannelCmd                = ENABLE;
		
		NVIC_Init(&NVICinitStructure);
	
}

void TIM4_Open(void)
{
		TIM_SetCounter(TIM4, 0);
		mscount=0;
		TIM_Cmd(TIM4, ENABLE);
}

void TIM4_Close(void)
{
		TIM_Cmd(TIM4, DISABLE);
}

void TIM4_IRQHandler(void)
{
		if( TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET )
		{
				TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
			
				mscount++;
		}
}

int Get_Echo_TIM(void)
{
		uint32_t t=0;
		
		t=mscount*1000;
		t+=TIM_GetCounter(TIM4);
		
		TIM4->CNT = 0;
		
		delay_us(50);
		
		return t;
}

float Get_Length(void)
{
		int i=0;
		uint32_t t=0;
		float sum=0;
		float length=0;
		
		while( i!=5 )
		{
				Trig_Send_Open;
				delay_us(60);
				Trig_Send_Close;
				
				while( Echo_Receive == 0 );
					TIM4_Open();
					i++;
				
				while( Echo_Receive == 1 );
					TIM4_Close();
					t=Get_Echo_TIM();
					length=((float) t/58);
					sum+=length;
		}
		length=sum/5;
		
		return length;
}

HC_SR04.h

#include "stm32f10x.h"

#define	Trig_Send_Open GPIO_SetBits(GPIOB, GPIO_Pin_11)
#define	Trig_Send_Close GPIO_ResetBits(GPIOB, GPIO_Pin_11) 
#define Echo_Receive GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)

void HC_SR04Init(void);
float Get_Length(void);
void TIM4_Open(void);
void TIM4_Close(void);
int Get_Echo_TIM(void);

usart.c

#include "usart.h"
#include "stm32f10x.h"

void usart_init()
{
		GPIO_InitTypeDef 	gpioInitStructure;
		USART_InitTypeDef	usartInitStructure;
		NVIC_InitTypeDef 	nvicInitStructure;
		
		//1.配置时钟
		
		//1.1配置GPIOA、串口时钟、复用时钟
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
		
		//2.配置GPIOA结构体
		
		//2.1 A9 TX
		gpioInitStructure.GPIO_Mode		= GPIO_Mode_AF_PP;
		gpioInitStructure.GPIO_Pin		= GPIO_Pin_9;
		gpioInitStructure.GPIO_Speed	= GPIO_Speed_50MHz;
		
		GPIO_Init(GPIOA, &gpioInitStructure);
		
		//2.2 A10 RX
		gpioInitStructure.GPIO_Mode		= GPIO_Mode_IN_FLOATING;
		gpioInitStructure.GPIO_Pin		= GPIO_Pin_10;
		
		GPIO_Init(GPIOA, &gpioInitStructure);

		//3.配置串口结构体
		usartInitStructure.USART_BaudRate				= 115200;
		usartInitStructure.USART_HardwareFlowControl	= USART_HardwareFlowControl_None;
		usartInitStructure.USART_Mode					= USART_Mode_Tx | USART_Mode_Rx;
		usartInitStructure.USART_Parity					= USART_Parity_No;
		usartInitStructure.USART_StopBits				= USART_StopBits_1;
		usartInitStructure.USART_WordLength				= USART_WordLength_8b;
		
		//3.1 初始化串口
		USART_Init(USART1, &usartInitStructure);
		
		//3.2 配置串口中断
		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
		
		//3.3 使能串口
		USART_Cmd(USART1, ENABLE);
		
		//4.配置NVIC中断优先级
		
		//4.1 配置优先级组
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
		
		//4.2 配置NVIC优先级结构体
		nvicInitStructure.NVIC_IRQChannel					= USART1_IRQn;
		nvicInitStructure.NVIC_IRQChannelPreemptionPriority	= 1;
		nvicInitStructure.NVIC_IRQChannelSubPriority		= 1;
		nvicInitStructure.NVIC_IRQChannelCmd				= ENABLE;
		
		//4.3 初始化NVIC优先级
		NVIC_Init(&nvicInitStructure);
		
}

void USARTSendByte(USART_TypeDef* USARTx, uint16_t Data)
{
		USART_SendData( USARTx, Data);
		while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
}

void USARTSendStr(USART_TypeDef* USARTx, char* str)
{
		uint16_t i=0;
		
		while( *(str+i) != '\0' )
		{
				/*
				USART_SendData( USARTx, *(str+i));
				while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
				*/
				
				USARTSendByte( USART1, *(str+i) );
				i++;
		}
		
		while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}

int fputc( int ch, FILE* f )
{
		USART_SendData( USART1, (uint8_t) ch );
		while( USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET );
	
		return ch;
}

int fgetc(FILE* f)
{
//		USART_ReceiveData(USART1);
		while( USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET );
		
		return (int) USART_ReceiveData(USART1);
}

usart.h

#include "stm32f10x.h"
#include <stdio.h>

void usart_init(void);
void USARTSendByte(USART_TypeDef* USARTx, uint16_t Data);
void USARTSendStr(USART_TypeDef* USARTx, char* str);

main.c

#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "shake.h"
#include "relay.h"
#include "exti.h"
#include "usart.h"
#include "tim.h"
#include "motor.h"
#include "SysTick.h"
#include "HC_SR04.h"

void delay(uint16_t time)
{
	uint16_t i=0;
	
	while(time--)
	{
		i=10000;
		while(i--);
	}
}

int main()
{
		float Length=0;
		
		HC_SR04Init();
		usart_init();
		
//		printf("abc");
		
		while(1)
		{
				Length=Get_Length();
				printf("%.3f\r\n",Length);
				delay_ms(100);

		}

}

测距完成

在这里插入图片描述

评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值