STM32
直播中

哔哔哔-

8年用户 1268经验值
擅长:电源/新能源
私信 关注
[问答]

如何用STM32F103ZET6和HC-SR04超声波测距模块给直升机航模测高度呢

什么是HC-SR04超声波测距模块呢?
如何用STM32F103ZET6和HC-SR04超声波测距模块给直升机航模测高度呢?

回帖(1)

张曼曼

2021-12-1 09:12:55
一.前言:这是我写的第一篇博客,希望用这种方式记录生活。

二.正文:用STM32F103ZET6结合HC-SR04超声波测距模块给直升机航模测高度。
首先,我们先了解一下HC-SR04超声波测距模块。
HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发射
器、接收器与控制电路。应用场景可以是智能小车测距壁障,航模飞行器定高等等。
1.模块实物图:


如上图接线,VCC供5V电源,GND为地线,TRIG触发控制信号输入,ECHO回响信号。
这里注意:arm板上的3.3V口也可以使用

2.电气参数






3.工作原理及超声波时序图
  1.超声波模块接入电源和地。
  2.给脉冲触发引脚(trig)输入一个长为10us的高电平方波
  3.输入方波后,模块内部会自动发射8个40KHz的声波并检测回波,一旦检测到回波则输出回响信号(回波引脚(echo)端的电平会由0变为1,此时我们应该启动定时器计时)
  4.当超声波返回被模块接收到时,回波引脚端的电平会由1变为0;(此时应该停止定时器计数),定时器记下的这个时间即为超声波由发射到返回的总时长(tim)。
  5.根据声音在空气中的速度为344米/秒,即可计算出所测的距离(公式:tim/58=厘米或则是距离=高电平时间*声速/2)。建议测量周期为60ms以上,以防止发射信号影响回波信号(关于这一点,我的无人机可等不了这么久,怎么办?)。
  要学习和应用传感器,学会看懂传感器的时序图是很关键的,所以我们来看一下HC-SR04的时序触发图。






从以上时序图中,可以知道:
我们首先需要给模块一个至少10us的高电平,来触发模块。模块内部会自动发出8个40khz的脉冲。我们需要关注的是回响电平的时间长度,这段时间就是超声波来回的总时间,除以2就可以得到距离。关于捕捉高电平时间,用定时器就可以轻松做到。
4.测试代码:

//超声波驱动和测量
#include "cs.h"
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
//用定时器中断捕捉回响信号

u8 exchange_Alti_num[8];//压力数据

float length=0;

/*记录定时器溢出次数*/
u8 overcount=0;

/*设置中断优先级*/
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructer;

//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitStructer.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructer.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructer.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructer.NVIC_IRQChannelCmd=ENABLE;

NVIC_Init(&NVIC_InitStructer);
}

/*初始化模块的GPIO以及初始化定时器TIM2*/
void CH_SR04_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructer;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructer;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

/*TRIG触发信号*/
GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructer.GPIO_Pin=GPIO_Pin_5;
GPIO_Init(GPIOB, &GPIO_InitStructer);

/*ECOH回响信号*/
GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStructer.GPIO_Pin=GPIO_Pin_6;
GPIO_Init(GPIOB, & GPIO_InitStructer);

/*定时器TIM2初始化*/
TIM_DeInit(TIM2);
TIM_TimeBaseInitStructer.TIM_Period=999;//定时周期为1000
TIM_TimeBaseInitStructer.TIM_Prescaler=71; //分频系数72
TIM_TimeBaseInitStructer.TIM_ClockDivision=TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructer.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructer);

TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启更新中断
NVIC_Config();
TIM_Cmd(TIM2,DISABLE);//关闭定时器使能

}



float Senor_Using(void)
{
u16 tim=0;
       
PBout(5)=1;  //拉高信号,作为触发信号
delay_us(15);  //高电平信号超过10us
PBout(5)=0;
/*等待回响信号*/
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==RESET);
TIM_Cmd(TIM2,ENABLE);//回响信号到来,开启定时器计数


while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==SET);//回响信号消失
TIM_Cmd(TIM2,DISABLE);//关闭定时器

tim=TIM_GetCounter(TIM2);//获取计TIM2数寄存器中的计数值,一边计算回响信号时间

length=(float)(tim+overcount*1000)/58.0;//通过回响信号计算距离


TIM2->CNT=0;  //将TIM2计数寄存器的计数值清零
overcount=0;  //中断溢出次数清零
//delay_ms(100);

return length;//距离作为函数返回值
}



void TIM2_IRQHandler(void) //中断,当回响信号很长是,计数值溢出后重复计数,用中断来保存溢出次数
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
  {
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志
overcount++;

  }
}

//***************数据转换*******************
void Exchange_Number(void)
{
        u32 ex_Pressure;        //串口读数转换值


  Senor_Using();
       
        ex_Pressure=(long)(length);
       
        exchange_Alti_num[0]=ex_Pressure/100+'0';
        exchange_Alti_num[1]=ex_Pressure/10%10+'0';
        exchange_Alti_num[2]=ex_Pressure%10+'0';
        exchange_Alti_num[3]='.';
        exchange_Alti_num[4]=ex_Pressure*10%10+'0';
        exchange_Alti_num[5]=ex_Pressure*100%10+'0';
        exchange_Alti_num[6]='0';
        exchange_Alti_num[7]='0';
        printf("Alti: ");
        Usart_Send(exchange_Alti_num,8);
        printf("cmn");
       
       
}


主函数:

#include "stm32f10x.h"
#include "cs.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"

int main(void)
{       
         delay_init();                     //延时函数初始化       
         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
         uart_init(9600);         //串口初始化为115200
   CH_SR04_Init();
         Senor_Using();

         
        while(1)
        {
  Exchange_Number();
        }
       
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分