文章内容仅个人的理解,如有错误还请各位多多包涵
硬件
单片机:stm32f103c8t6,HC_SR04超声波测距
一、硬件介绍
注意不是3.3V电压(不过我接了用也能返回数据)
Trlg:接入单片机GPIO输出端
Echo:接入单片机GPIO输入端
二、超声波测距工作原理
有两个口,一个发送超声波,然后超声波碰到障碍物,反弹,另一个口就接收到回波。
怎么得到距离呢?
在一个口发出超声波时,同时间打开定时器计
超声波碰到障碍物,产生回波
等到另一个口接收到回波
就关闭定时器
此时定时器里的计数时间,是不是就是超声波传出的时间和传回的时间之和?
对,有了时间。距离就好算了,速度是声速
s=v *(t / 2),这样就明了
超声波模块是一上电就开始测量,发送超声波吗?
不,需要单片机给他发送触发信号(开始信号)
关于送触发信号
看代码理解,B11引脚我们设为输出
先从低拉到高,持续15us,再拉低,这一个过程就是单片机 发送开始信号
发送开始信号后
等待超声波模块 响应(也就是超声波模块接收到回波时)给单片机发送个提醒信号
我们这里用B10引脚接收,b10为输入
三、全代码
.h
#ifndef _HC_SR04_H
#define _HC_SR04_H
#include "stm32f10x.h" // Device header
#include "delay.h" // Device header
#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_SR04_Init(void);
float Get_Length(void);
void Timer_On(void);
void Timer_Off(void);
int Get_Echo_TIM(void);
#endif
.c
#include "hc_sr04.h" // Device header
#include "stm32f10x.h"
unsigned int Y_Out_Counter;//溢出时间增量(也就是计数器溢出的次数
void HC_SR04_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIO时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//使能TIMx时钟
//GPIO初始化 Trig(STM32发送触发信号给HC-SR04)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出(高低电平均有驱动能力)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//GPIO初始化 Echo(STM32接收回波信号,计算距离)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//定时中断配置
//选择时钟源
TIM_InternalClockConfig(TIM2);
//配置时基单元
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100-1;//ARR 定时时间0.1ms
TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;//PSC 1MHz(150HZ以上最好)
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//高级定时器采用,给0
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//TIM_ClearFlag(TIM2,TIM_FLAG_Update);//解除初始化就进入中断(避免数据出错)
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能定时中断
//配置NVIC 分配和管理中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//响应优先级
NVIC_Init(&NVIC_InitStructure);
//失能定时
TIM_Cmd(TIM2,DISABLE);
}
//定时器开
void Timer_On(void)
{
TIM_SetCounter(TIM2,0);//计数值清零(解除干扰)
Y_Out_Counter = 0;//定时器还没使能,溢出值始终为0
TIM_Cmd(TIM2,ENABLE);
}
//定时器关
void Timer_Off(void)
{
TIM_Cmd(TIM2,DISABLE);//关闭定时器
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)//中断标志判断
{
Y_Out_Counter++;//自增
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志
}
}
int Timer_Get_Counter(void)
{
unsigned int T;
T=Y_Out_Counter*100;//重装值100,每溢出一次,进入定时中断一次,因此,溢出计数值=溢出次数*重装值
T=T+TIM_GetCounter(TIM2);//总的计数值=溢出次数*重装值+最后一次没有到溢出值的计数
TIM_SetCounter(TIM2,0);//计数值清零
delay_ms(50);
return T;
}
float Get_Length(void)
{
//求解距离,采用平均值最好
int i=0;//次数变量
unsigned int t=0;
float Length=0;
float Sum=0;
for(i=0;i<3;i++)//计算3次
{
//触发信号(触发超声波模块工作)
GPIO_ResetBits(GPIOB,GPIO_Pin_11);
GPIO_SetBits(GPIOB,GPIO_Pin_11);//设B11引脚为高电平
delay_us(15);//10US以上
GPIO_ResetBits(GPIOB,GPIO_Pin_11);//设B11引脚为低电平
//---------------------------------------
//获取Echo引脚的电平状态
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==0);//低电平就执行空操作
//读取到高电平
Timer_On();//打开定时器
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==1);//高电平就执行空操作(直到读取完成)
//低电平(接收结束)
Timer_Off();//关闭定时器
t=Timer_Get_Counter();//获取时间
Length=((float)t/58.0);//计算距离
Sum=Sum+Length;//3次计算的总距离
}
//计算距离的均值
Length=Sum/3.0;
return Length;
}