基于STM32的超声波HC-SR04详解


HC-SR04基本工作原理:

(1)采用IO口TRIG触发测距,给最少10us的高电平信呈。
(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;
(3)有信号返回, 通过IO口ECHO输出一个高电平, 高电平持续的时间就是超声波从发射到返回的时间。

测试距离=(高电平时间*声速(340M/S))/2

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




程序编写思路是:

1、配置好使用到的GPIO以及定时器;
2、给模块TRIG端口发送大于10us的高电平信号,当收、收到ECHO回响信号是,打开定时器开始定时;
3、当回响信号消失,关闭定时器;
4、通过定时器定时时间来确定距离。




连线

1.这里,HC-SR04模块必须使用5V供电,不能是3.3V (若接3.3V,则数据出错)
2.Trig引脚我这里接GPIOB6
3.Echo引脚我这里接GPIOB7




相关代码

main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"

float Distance_Calculate(u32 count)
{
	//单位cm
	//v = 340m/s = 34000cm/s = 34000cm/10^6us = 0.034cm/us
	//s = vt/2 = t*0.034/2 = t*0.017 ≈ t/58
    float Distance = 0;
    Distance = ((float)count / 58));
    return Distance;

}

int main(void)
{		
	u32 count = 0;
	float Distance = 0;
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
	LED_Init();			     //LED端口初始化
	Ultrasonic_Config();	//引脚初始化
	Timer2_Config();	//定时器2初始化
	GPIO_SetBits(GPIOB,GPIO_Pin_5);	//一开始我给它亮
	LED0 = 0;	//小灯指示用途
	LED1 = 0;
	printf("Test start\n");
	while(1)
	{
		//拉高Trig引脚10us
		GPIO_ResetBits(GPIOB, GPIO_Pin_6);//预先拉低Trig引脚
		GPIO_SetBits(GPIOB, GPIO_Pin_6);
		delay_us(10);
		GPIO_ResetBits(GPIOB, GPIO_Pin_6);//发出10us的脉冲
		TIM2->CNT = 0;	//计数器的值为0
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7) == 0);	//等待高电平
		TIM_Cmd(TIM2, ENABLE);	//开启定时器
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7) == 1){}	//等待低电平
		TIM_Cmd(TIM2, DISABLE);	//关闭定时器
		count = TIM2->CNT;	//获取定时器的值
		printf("count = %d\r\n",count);
		//count是计数器,单位是us,可根据上图转换一下即可。
		Distance = Distance_Calculate(count);	//计算距离
		printf("Distance = %f.", Distance);
		delay_ms(500);
		LED0 = !LED0;
		LED1 = !LED1;
	}	 
}	 

命名问题,不需要配置led

led.h

#ifndef __LED_H
#define __LED_H	 
#include "sys.h"

void Timer2_Config(void);
void Ultrasonic_Config(void);
	 

led.c

void Ultrasonic_Config(void){
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;	//Trig
	//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;	//ECHO,输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	//设为输入
	GPIO_Init(GPIOB,&GPIO_InitStructure);	
}
void Timer2_Config(void){
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
	TIM_TimeBaseInitStructure.TIM_Period = 49999;	//72*50000/72 = 50000us = 500ms.
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);	//更新产生中断
}

usart.c

void uart_init(u32 bound){
	  //GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
	
	//USART1_TX   GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
	
	//USART1_RX	  GPIOA.10初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
	
	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	//USART 初始化设置
	
	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
	
	USART_Init(USART1, &USART_InitStructure); //初始化串口1
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
	USART_Cmd(USART1, ENABLE);                    //使能串口1 
}



实验结果

在这里插入图片描述
说明:count是计数器
v = 340m/s,v = 0.034cm/us.
t = s/v = 400cm/0.034cm/us = 11764us
而我设置计数50000次,也就是50000us,因此,是能够测量最大距离的。




参考资料

[1] STM32F103 实验定时器

[2] STM32F103 实验按键输入与串口实验

[3] 基于STM32使用超声波HC-SR04模块

  • 43
    点赞
  • 227
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
以下是基于STM32hc-sr04超声波测距模块的代码示例: ```c #include "stm32f10x.h" #define Trig_Pin GPIO_Pin_0 #define Echo_Pin GPIO_Pin_1 #define Trig_Port GPIOC #define Echo_Port GPIOC void TIM2_Configuration(void); float ultrasonic_measure(void); int main(void) { float distance; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin = Trig_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Trig_Port, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = Echo_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Echo_Port, &GPIO_InitStruct); TIM2_Configuration(); while(1) { distance = ultrasonic_measure(); } } void TIM2_Configuration(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1; TIM_TimeBaseInitStruct.TIM_Period = 0xFFFF; TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); TIM_OCInitTypeDef TIM_OCInitStruct; TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStruct.TIM_Pulse = 0; TIM_OC1Init(TIM2, &TIM_OCInitStruct); TIM_Cmd(TIM2, ENABLE); } float ultrasonic_measure(void) { uint16_t TIM2_CountStart, TIM2_CountEnd; float Distance; GPIO_ResetBits(Trig_Port, Trig_Pin); TIM_SetCounter(TIM2, 0); while(TIM_GetCounter(TIM2) < 10); // delay 10us GPIO_SetBits(Trig_Port, Trig_Pin); while(GPIO_ReadInputDataBit(Echo_Port, Echo_Pin) == RESET); TIM_Cmd(TIM2, ENABLE); while(GPIO_ReadInputDataBit(Echo_Port, Echo_Pin) == SET); TIM_Cmd(TIM2, DISABLE); TIM2_CountStart = TIM2->CCR1; TIM2_CountEnd = TIM_GetCapture1(TIM2); Distance = (float)(TIM2_CountEnd - TIM2_CountStart) * 0.01715f; // Distance = (High level time * sound velocity (340M/S) / 2) return Distance; } ``` 代码中使用了STM32的定时器TIM2进行计时,测量距离的原理是通过发送一个10us的高电平脉冲触发hc-sr04模块,然后接收返回的超声波信号并测量高电平持续时间,最后通过公式计算出距离。需要注意的是,本示例中使用的是72MHz的系统时钟,如果系统时钟不同,需要相应地修改计时器的预分频值。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值