HC-SR04超级简单教程:快速入门指南

目录

一、模块介绍(个人理解)

        1.简单理解

        2.该模块的参数

二、HC-SR04的操作

三、代码

        1.代码前的注意事项

        2.关键代码

四、代码实战效果图

 五、结束


一、模块介绍(个人理解)

        1.简单理解

        HC-SR04是一个超声波测距模块,通过发出超声波然后接收超声波,利用这个往返时间算出距离的模块。

HC-SR04模块 (实物图)

        2.该模块的参数

   参数图 

二、HC-SR04的操作

        HC-SR04的操作相对其他模块来说还是很简单的。首先该模块有四个口VCC、Gnd、Trig、Echo,并不多。在模块工作的时候,先要给Trig口拉高电平至少10us,然后Echo口会返回一个高电平信号,同时发射超声波。在HC-SR04接收到发出去反射回来的声波后,会给一个低电平。至此,一次检测就完成了。我们可以用定时器在发射声波时开始计数,等到接收声波后,停止计数。这样我们就有了时间。但是这个是往返时间,我们要除2,声音的传播速度时340m/s(这里暂时不考虑其他因素的影响)。有了时间和速度,路程就可以算出来了。我的代码会有详细的介绍,这部分内容。

三、代码

        1.代码前的注意事项

               1) 如果你的HC-SR04不能够回应你的单片机发送的信号,可能就是该模块有问题。

               2)下面代码我是看了很多博主的,才写下来的,相对来说比较简单。移植性比较好,没 有在文件外定义有什么变量。

               3)本人用stm32单片机的,型号是stm32f103c8t6 。

               4)代码的解释非常详细,可以结合上面的操作过程看。特别是在操作模块的那个函数的代码。

               5)代码在计算阶段并没有对(温度等)影响做修正,也没有取多次距离再取平均数。大家可以自己加上去,毕竟这个是最低门槛的写法了。

        

        2.关键代码

HC-SR04.h

#ifndef _HC_SR04_H
#define	_HC_SR04_H

uint32_t Get_Timer(void);
static void OpenTIM2();
static void CloseTIM2();
void HC_SR04_Init();
void HC_SR04_GPIO_Init();
void HC_SR_04_TIME_NVIC_Init();
float Get_Length();

#endif

HC-SR04.c


#include	"stm32f10x.h"
#include	"Delay.h"
#include 	"OLED.h"

#define RCC_GPIO	RCC_APB2Periph_GPIOB
#define GPIOx 		GPIOB
#define trigGPIO 	GPIO_Pin_6
#define echoGPIO 	GPIO_Pin_7


//给毫秒ms计数
uint16_t count = 0;

//GPIO口的初始化
void HC_SR04_GPIO_Init(){
    //定义结构体
    GPIO_InitTypeDef GPIO_InitStruct;
    //开启GPIOB RCC时钟
    RCC_APB2PeriphClockCmd(RCC_GPIO,ENABLE);

    //对结构体成员赋值
    //发送GPIOB6 模式为推挽输出 trig
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Pin =  trigGPIO;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_ResetBits(GPIOx,trigGPIO);   //设置默认为低电平 高电平会触发HC-SR发射超声波

	GPIO_Init(GPIOx,&GPIO_InitStruct);
	
    //返回GPIOB7 模式设置为浮空输入(因为该GPIO口需要被外设改变电平)
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Pin =  echoGPIO;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_ResetBits(GPIOx,echoGPIO);   //设置默认低电平

    //初始化GPIO外围设备    echo
    GPIO_Init(GPIOx,&GPIO_InitStruct);
}

//初始化定时器
void HC_SR_04_TIME_NVIC_Init(){

    //定义定时器的结构体
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

    //NVIC结构体
    NVIC_InitTypeDef NVIC_InitStructure;

    //开启TIM2
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

    //将TIMx外围寄存器反初始化为其默认重置值。
    TIM_DeInit(TIM2);

    //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,计数到1000为1ms
    TIM_TimeBaseInitStructure.TIM_Period = 1000-1; 	

    //设置用来作为TIMx时钟频率除数的预分频值  1M的计数频率 1US计数				
    TIM_TimeBaseInitStructure.TIM_Prescaler =72-1;

    //不分频					
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;	

    //TIM向上计数模式		
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

    //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx TimeBase Unit外设  	
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); 

    //打开定时器的更新中断
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
    //选择串口1中断
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;           	  

    //抢占式中断优先级设置为1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     

    //响应式中断优先级设置为1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;            

    //使能中断
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;               
    NVIC_Init(&NVIC_InitStructure);

    //先关掉定时器,先不让它计时
    TIM_Cmd(TIM2,DISABLE); 
}

void HC_SR04_Init(){
    HC_SR04_GPIO_Init();
    HC_SR_04_TIME_NVIC_Init();
}

//打开定时器
static void OpenTIM2()        
{
        TIM_SetCounter(TIM2,0);			//清除计数
        count = 0;
        TIM_Cmd(TIM2, ENABLE);  		//使能TIM2外设
}

//关闭定时器
static void CloseTIM2()        
{
        TIM_Cmd(TIM2, DISABLE);  //使能TIM2外设
}
 
 

//TIM2定时器的中断函数
void TIM2_IRQHandler(void)   
{
        //检查是否是更新中断位
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) 
        {
            //清除标志位	清除TIMx的中断挂起位
            TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  
            count++;
        }
}
 

//获取定时器时间
uint32_t Get_Timer(void)
{
        uint32_t t = 0;

        //此处t为us
        t = count*1000;	

        //TIM_GetCounter 获取TIM2计数器值
        t += TIM_GetCounter(TIM2);
        //将TIM2计数寄存器的计数值清零  
        TIM2->CNT = 0;  					  
        delay_ms(50);
        return t;
}
 
 float Get_Length(){
    
	 
    //存储时间
    float t = 0,length = 0;
    
    // 1. 先将trig置位(设置为高电平)
    GPIO_SetBits(GPIOx,trigGPIO);

    // 2. 持续时间至少要10us    这里我就给20了
    Delay_us(20);

    // 3. 然后需要将trig位清零(也就是设置为低电平)
    GPIO_ResetBits(GPIOx,trigGPIO);
	 
    // 4. 等待 HC-SR04 将echo置位(也就是高电平),如果置位了就开始发出声波了,我们要开始计时
    //      这里用GPIO_ReadInputDataBit 是读取GPIO的输入
    while (GPIO_ReadInputDataBit(GPIOx,echoGPIO) == RESET){
	
	};
    // 5. 打开定时器 开始计时
    OpenTIM2();
	
	
    // 6. 等待 HC-SR04 将echo清零(也就是低电平),如果清零了就是收到了声波
    while (GPIO_ReadInputDataBit(GPIOx,echoGPIO) == SET);
    
	
    // 7. 关闭定时器 停止计时
    CloseTIM2();

    // 8. 获取时间,因为是us(微秒),我们要转化为ms(毫秒)所以除1000
    t = Get_Timer() / 1000.0;

    // 9. 计算长度cm(厘米)
    //      声音在空气中传播的速度是340m/s,我们转换一下就是 34cm/ms
    length = t*34.0;

    // 10. 返回长度,因为是一个往返我们要除2
    return length/2;
 }


main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "HC_SR04.h"

// 不需要的头文件就不用就好了
int main(void)
{
	float length = 0;

	OLED_Init();

	HC_SR04_Init();
	
	while (1)
	{
		OLED_ShowString(1, 1, "kiana");
		length = Get_Length();
		Delay_ms(500);
		OLED_ShowSignedNum(2,1,length,3);
	}
}

四、代码实战效果图

        这里对齐不好固定,我就大概来一下大概的了哦。

效果图

 五、结束

        为了美好的明天继续奋斗吧!

物联沃分享整理
物联沃-IOTWORD物联网 » HC-SR04超级简单教程:快速入门指南

发表评论