一.前言:这是我写的第一篇博客,希望用这种方式记录生活。
二.正文:用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();
}
}
一.前言:这是我写的第一篇博客,希望用这种方式记录生活。
二.正文:用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();
}
}
举报