Ultrasonic ranging based on STM32F407 (SR04)


foreword

The function to be realized today is ultrasonic distance measurement, which can be used in many places, for example: ultrasonic obstacle avoidance function can be added to the smart car. Today I need to use the SR04 ultrasonic module. When using this module, I will come into contact with the timing diagram.


1. SR04 ultrasonic module

The module is as shown in the figure:
insert image description here
the module has four pins
VCC for 5V power supply,
GND for the ground wire,
TRIG trigger control signal input, the pin connected to this study is PB6
ECHO echo signal output, the pin used for this study access The pin is PE6

2. Use steps

1. View SR04 product manual

In the product manual, we can see not only the pin diagram above but also a timing diagram, as shown in the figure below:
insert image description here
We need to use the ultrasonic module to obtain the measured distance according to the timing diagram. First, we need to understand the timing diagram.
We need to understand that the timing diagram needs to be interpreted from top to bottom and from left to right, so we divide the timing diagram into four parts, as shown in the figure:
insert image description here
From the figure, we can know that the initial level of the trigger signal (PB6) is low Level, after setting the high level for about 10us, our program needs more than 10us to ensure stability and then set it to low level. At this time, pin PB6 has experienced low level, high level for 10us, and low level. Eight 40KHz pulses will be sent out, and after 8 more pulses, the PE6 pin will detect a high level. We need to calculate the high level time. According to the manual:
distance = high level time * sound speed (340M/S )/2 in the formula of 340M/S can be converted into approximately 3 mm per 9 microseconds, so that we can get the actual distance.

2. Pin initialization

code show as below:

void sr04_init(void)
{
    
    
   //使能PB6时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	//使能PE6时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//配置PB6为输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
	//配置PE6为输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化
	
	PBout(6)=0;
}

3. Obtain the measurement distance

int32_t sr04_get_distance(void)
{
    
    
	int32_t t=0;
	int32_t d=0;
	//PB6高电平10us以上
	PBout(6)=1;
	delay_us(20);
	PBout(6)=0;
	//等待回响信号高电平
	while(PEin(6)==0)
	{
    
    
		t++;
		delay_us(1);
		if(t>=100000)
		{
    
    
			return -1;
		}
	} 
	t=0;
	while(PEin(6))
	{
    
    
		t++;
		delay_us(9);//3毫米距离
		if(t>=10000)
		{
    
    
			return -2;
		}
	}
	t=t/2;
	d=3*t;
	return d;
	
}

4. Complete code

#include "stm32f4xx.h"                  // Device header
#include "sys.h"
#include "stdio.h"


static GPIO_InitTypeDef  GPIO_InitStructure;
static USART_InitTypeDef USART_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
static uint16_t d;



struct __FILE {
    
     int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f) 
{
    
    
	
	USART_SendData(USART1,ch);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	
	return ch;
}


void delay_ms(uint32_t n)
{
    
    
	while(n--)
	{
    
    
		SysTick->CTRL = 0; // Disable SysTick
		SysTick->LOAD = (168000)-1; // Count from 255 to 0 (256 cycles)
		SysTick->VAL = 0; // Clear current value as well as count flag
		SysTick->CTRL = 5; // Enable SysTick timer with processor clock
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
	}
	
	SysTick->CTRL = 0; // Disable SysTick
}
void delay_us(uint32_t n)
{
    
    
	while(n--)
	{
    
    
		SysTick->CTRL = 0; // Disable SysTick
		SysTick->LOAD = (168)-1; // Count from 255 to 0 (256 cycles)
		SysTick->VAL = 0; // Clear current value as well as count flag
		SysTick->CTRL = 5; // Enable SysTick timer with processor clock
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
	}
	
	SysTick->CTRL = 0; // Disable SysTick
}

void usart1_init(uint32_t band)
{
    
    
	
	//打开硬件时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//打开串口1硬件时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//配置PA9和PA10为服用功能
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
	
	
	//将PA9和PA10引脚连接到串口1的硬件
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
	
	//配置串口1相关参数:波特率、无校验位、8位数位、1位停止位
	USART_InitStructure.USART_BaudRate = band;					//波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;		//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);
	//配置串口1的中断优先级

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

	//使能串口1工作
	USART_Cmd(USART1,ENABLE);
}

void sr04_init(void)
{
    
    
   //使能PB6时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	//使能PE6时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	//配置PB6为输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
	//配置PE6为输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化
	
	PBout(6)=0;
}

int32_t sr04_get_distance(void)
{
    
    
	int32_t t=0;
	int32_t d=0;
	//PB6高电平10us以上
	PBout(6)=1;
	delay_us(20);
	PBout(6)=0;
	//等待回响信号高电平
	while(PEin(6)==0)
	{
    
    
		t++;
		delay_us(1);
		if(t>=100000)
		{
    
    
			return -1;
		}
	} 
	t=0;
	while(PEin(6))
	{
    
    
		t++;
		delay_us(9);//3毫米距离
		if(t>=10000)
		{
    
    
			return -2;
		}
	}
	t=t/2;
	d=3*t;
	return d;
	
}


int main(void)
{
    
    
	int32_t d;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟

	//GPIOF9,F10初始化设置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化
	
	
	
	GPIO_SetBits(GPIOF,GPIO_Pin_9);
	
	
	usart1_init(115200);
	sr04_init();
	
	
	
	while(1)
	{
    
    
		d=sr04_get_distance();
		if(d>0)
		{
    
    
			if(d>=20 && d<=4000)
			{
    
    
				printf("distance=%dmm\r\n",d);
			}
		}
		delay_ms(1000);
	}
}


void USART1_IRQHandler(void)
{
    
    
	
	//检查标志位
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{
    
    
		d=USART_ReceiveData(USART1);
		
		printf(d+"");
		//清空标志位
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
	}
	
	
}



5. Running effect

We print out the measured distance through the serial port, and the effect is shown in the figure below:
insert image description here
the measured distance can be successfully printed out through the serial port!

Guess you like

Origin blog.csdn.net/weixin_46155589/article/details/127697885