一、超声波HC_SR04简介

        超声波传感器模块上面通常有两个超声波元器件,一个用于发射,一个用于接收。

        电路板上有四个引脚:VCC、GND、Trig(触发)、Echo(回应)。

        工作电压与电流:5V,15mA

        感应距离:2~400cm

        感测角度:不小于15度

        被测物体的面积不要小于50平方厘米并且尽量平整

        具备温度补偿电路

二、超声波原理

        距离公式:

        高电平持续时间*声速(340m/s)/2

三、超声波测距步骤

  1. 配置GPIO引脚结构体(Trig,Echo)
  2. 配置定时器4结构体
  3. 配置定时器4中断结构体
  4. 开启时钟(定时器、GPIO)
  5. Trig引脚输出高电平(10us以上),然后关闭
  6. 等待Echo引脚输出高电平开始,定时器打开->开启计数器计数
  7. 等待Echo引脚输出高电平结束,定时器关闭->停止计数器计数

四、硬件接线

  1. GND——GND
  2. VCC——5V
  3. Trig——PB11
  4. Echo——PB10

五、模块化程序

#ifndef __SYS_H
#define __SYS_H	
#include "stm32f10x.h"


#define SYSTEM_SUPPORT_UCOS		0		

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 


#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //Êä³ö 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //ÊäÈë 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //Êä³ö 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //ÊäÈë 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //Êä³ö 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //ÊäÈë 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //Êä³ö 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //ÊäÈë 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //Êä³ö 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //ÊäÈë

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //Êä³ö 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //ÊäÈë

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //Êä³ö 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //ÊäÈë



void NVIC_Configuration(void);



#endif
#include "sys.h"
#include "stm32f10x.h" 

void NVIC_Configuration(void)
{

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	

}
#include "hc.h"
#include "Delay.h"

#define HCSR04_PORT     GPIOB
#define HCSR04_CLK      RCC_APB2Periph_GPIOB
#define HCSR04_TRIG     GPIO_Pin_11
#define HCSR04_ECHO     GPIO_Pin_10

u16 msHcCount = 0; 

void HC_Init(void)
{  
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE);

    GPIO_InitStructure.GPIO_Pin =HCSR04_TRIG;      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);
    GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);

    GPIO_InitStructure.GPIO_Pin = HCSR04_ECHO;     
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);  
    GPIO_ResetBits(HCSR04_PORT,HCSR04_ECHO);    


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);   

    TIM_DeInit(TIM2);
    TIM_TimeBaseStructure.TIM_Period = (1000-1); 
    TIM_TimeBaseStructure.TIM_Prescaler =(72-1); 
    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);          

    TIM_ClearFlag(TIM4, TIM_FLAG_Update);  
    TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);    

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;             
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;         
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;       
    NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM4,DISABLE);     
}



static void OpenTimerForHc()  
{
    TIM_SetCounter(TIM4,0);
    msHcCount = 0;
    TIM_Cmd(TIM4, ENABLE); 
}


static void CloseTimerForHc()    
{
    TIM_Cmd(TIM4, DISABLE); 
}


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



  u32 GetEchoTimer(void)
{
    u32 t = 0;
    t = msHcCount*1000;
    t += TIM_GetCounter(TIM4);
    TIM4->CNT = 0;  
    Delay_ms(50);
    return t;
}

  float HC_Get(void )
{
    int t = 0;
    int i = 0;
    float lengthTemp = 0;
    float sum = 0;
    while(i!=5)
   {
       TRIG_Send = 1;      
       Delay_us(20);
       TRIG_Send = 0;
       while(ECHO_Reci == 0);      
       OpenTimerForHc();        
       i = i + 1;
       while(ECHO_Reci == 1);
       CloseTimerForHc();        
       t = GetEchoTimer();        
       lengthTemp = ((float)t/58.0);//cm
       sum = lengthTemp + sum ;

   }
    lengthTemp = sum/5.0;
    return lengthTemp;
}
#ifndef __HC_H
#define __HC_H	
#include "sys.h"

void HC_Init(void);
static void OpenTimerForHc(void);
static void CloseTimerForHc(void);
void TIM4_IRQHandler(void);
u32 GetEchoTimer(void);
float HC_Get(void );

#define TRIG_Send  PBout(11)
#define ECHO_Reci  PBin(10)
#endif
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "HC.h"

uint32_t Length;
float length;


int main(void)
{
	
  OLED_Init();
  OLED_ShowString(1,1,"Length:");
  OLED_ShowString(2,10,"cm");
  HC_Init();

while(1)
	{
		length =HC_Get(); 
		Length = length*100; //eg:54.25->5425
		OLED_ShowNum(2,4,Length/1000,1);  // 千
		OLED_ShowNum(2,5,Length%1000/100,1); //百
		OLED_ShowString(2,6,".");
		OLED_ShowNum(2,7,Length%100/10,1); //十
		OLED_ShowNum(2,8,Length%10/1,1);  //个
		
  }
}

📎测距模块.zip

六、实验现象

附录 串口调试版本

1、连线图

2、调试截图

3、模块化函数(相较于 五、模块化程序 新增部分)

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

uint8_t Serial_RxData;
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1, ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}

uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)
	{
		Serial_RxFlag = 0;
		return 1;
	}
	return 0;
}

uint8_t Serial_GetRxData(void)
{
	return Serial_RxData;
}

void USART1_IRQHandler(void)
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		Serial_RxData = USART_ReceiveData(USART1);
		Serial_RxFlag = 1;
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}
#ifndef __SERIAL_H
#define __SERIAL_H

#include <stdio.h>

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);

uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);

#endif
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "HC.h"
#include "Serial.h"

uint32_t Length;
float length;


int main(void)
{
	
	OLED_Init();
	HC_Init();
	Serial_Init();
  OLED_ShowString(1,1,"Length:");
  OLED_ShowString(2,10,"cm");
//	Serial_SendByte(0x41);
//	
//	uint8_t MyArray[] = {0x42, 0x43, 0x44, 0x45};
//	Serial_SendArray(MyArray, 4);
//	
//	Serial_SendString("\r\nNum1=");
//	
//	Serial_SendNumber(111, 3);
//	
//	printf("\r\nNum2=%d", 222);
//	
//	char String[100];
//	sprintf(String, "\r\nNum3=%d", 333);
//	Serial_SendString(String);
//	
//	Serial_Printf("\r\nNum4=%d", 444);
//	Serial_Printf("\r\n");

 
while(1)
	{ 
		length =HC_Get(); 
		Length = length*100; //eg:54.25->5425
		OLED_ShowNum(2,4,Length/1000,1);  // ǧ
		OLED_ShowNum(2,5,Length%1000/100,1); //°Ù
		OLED_ShowString(2,6,".");
		OLED_ShowNum(2,7,Length%100/10,1); //Ê®
		OLED_ShowNum(2,8,Length%10/1,1);  //¸ö
		
		Serial_SendString("The length is:");
		Serial_SendNumber(Length/1000, 1);
		Serial_SendNumber(Length%1000/100, 1);
		Serial_SendString(".");
		Serial_SendNumber(Length%100/10, 1);
		Serial_SendNumber(Length%10/1, 1);
		Serial_Printf("\r\n");
		Delay_ms(500);
		
  }
}

📎测距模块 - 串口调试版本.zip

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐