基于stm32f10x的超声波模块HC-SR04的测距示例,并用串口将数据打印出来

230 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。 一.所需材料:

1任何一种型号的stm32f10x的微控制器

2.HC-SR04模块

3.安装串口驱动与串口助手(这里用的火哥的串口调试助手)

4.ST-link或者串口等下载方式都可以

二。超声波原理

网上一大堆,这里我就大体说一下:单片机先给TRIG一个大于10us的高电平,然后模块ECHO引脚会发出一个高电平,检测高电平的时间乘声速便可算出距离。这里ECHO发出也接收,所以检测的时间,假设按秒算,然后乘170便是以m为单位的距离。

三.源代码分析

1.接口定义:

//由于只是用的定时器的基本计时功能,所以IO口随便找两个便可以
#define HCSR04_PORT              GPIOB
#define HCSR04_PORTC_CLK_FUN     RCC_APB2PeriphClockCmd
#define HCSR04_CLK               RCC_APB2Periph_GPIOB
#define HCSR04_TRIG              GPIO_Pin_11
#define HCSR04_ECHO              GPIO_Pin_10

2.驱动函数分析

//超声波计数,记录有几个更新中断,由于在.c文件中定义,中断函数中测试其值,故加个extern
extern u16 msHcCount = 0; 

//IO口初始化 TRIG为普通推挽输出,ECHO为浮空输入,
//配置时基结构体
void Hcsr04Init(void)
{  
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   
GPIO_InitTypeDef GPIO_InitStructure;
HCSR04_PORTC_CLK_FUN(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);         //定时器时钟1MHZ,自动重装载寄存器的值为1000, 也就是说满一次为1MS
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);    
hcsr04_NVIC();
TIM_Cmd(TIM4,DISABLE);     
}

//中断配置,这里只用了一个中断,不用考虑中断嵌套等等,所以中断优先级以及次优先级可以随便配置,只用到了定时器update中断

void hcsr04_NVIC(void)
{
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);
}

//关闭定时器4
static void CloseTimerForHc(void)    
{
TIM_Cmd(TIM4, DISABLE); 

//打开定时器4
static void OpenTimerForHc(void)  
{
TIM_SetCounter(TIM4,0);
msHcCount = 0;
TIM_Cmd(TIM4, ENABLE); 
}
//获取定时器4计数器值,此值为更新中断的次数1000+计数器的值
u32 GetEchoTimer(void)
{
u32 t = 0;
t = msHcCount
1000;
t += TIM_GetCounter(TIM4);
TIM4->CNT = 0;  
Systick_DelayMs(50);
return t;
}

//通过定时器4计数器值推算距离,单位厘米,假设测试值为x,距离y=x/1M*17000

//这里每测出5此求个平均值输出
float Hcsr04GetLength(void )
{
u32 t = 0;
int i = 0;
float lengthTemp = 0;
float sum = 0;
while(i!=5)
{
GPIO_SetBits(HCSR04_PORT,HCSR04_TRIG);
Systick_DelayUs(20);
GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);
while(GPIO_ReadInputDataBit(HCSR04_PORT,HCSR04_ECHO)==RESET);
OpenTimerForHc();
i = i + 1;
while(GPIO_ReadInputDataBit(HCSR04_PORT,HCSR04_ECHO)==SET);
CloseTimerForHc();
t = GetEchoTimer();
lengthTemp = ((float)t*0.017);//cm

sum = lengthTemp + sum ;

}
lengthTemp = sum/5.0;
return lengthTemp;
}

\

3.主函数测试程序:

float length;
//延时函数初始化
Systick_DelayMs(10); //这里用的系统滴答定时器延时  
hcsr04_NVIC(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级

USART_Config();//串口服务程序,这里我用的火哥的串口一
Hcsr04Init();  

  while(1) 
{  
length = Hcsr04GetLength();
printf("距离为:%.3fcm\n",length);
Systick_DelayMs(1000);
}

\

四.效果图 ​​​