STM32——HC_SR04超声波测距
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);
}
}
测距完成

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

7964

被折叠的 条评论
为什么被折叠?



