HC-SR04超声波传感器测距(学习笔记)
1、任务
利用HC-SR04超声波传感器进行测距实验,通过stm32单片机板载的按键实现手动触发测距,将测得的距离显示在OLED屏上。
2、工作原理
a.单片机IO向HC-SR04的Trig接口发送一个持续时间大于10us的高电平信号;
b.HC-SR04接收到来自单片机的信号后,自动发送8个频率为4KHz的方波,方波遇到障碍物后会反射,HC-SR04会自动检测反射回来的信号;
c.HC-SR04的Trig接口接收到单片机高电平信号自动发送方波的同时,Echo接口向单片机IO口发送高电平信号,当HC-SR04接收到返回信号时,Echo接口向单片机IO发送低电平信号,高电平持续的时间就是超声波从发射到返回的总时间T,此时空气中的声速为v,则测得的距离S=(T*v)/2。
3、硬件
a.硬件:HC-SR04传感器、OLED显示屏、stm32F103C8T6单片机
b.接线:VCC——单片机5V GND——单片机GND
Trig——PA6(TIM3_CH1) Echo——PA7(TIM3_CH2)
4、代码实现
代码思路:利用定时器中断获取高电平持续时间,将TIM3重装载周期设为1000次,每次1us,当Echo上升沿时开启TIM3,TIM3将每1ms进入中断,在中断函数中记录中断次数,多少次中断就是多少ms,再获取TIM3的计数寄存器值,寄存器值为0~1000,即0us~1000us。
定时时间:Tout=((arr+1)*(psc+1))/Tclk
Tclk:TIMx的输入时钟频率(单位MHz,一般是72MHz)
Tout:TIMx的溢出时间,即定时时间(单位us)
arr:自动重装载寄存器周期的值,自定
psc:时钟频率除数的预分频值
hcsr.c
#include "hcsr.h"
#include "sys.h"
#include "delay.h"
//定时时间=((arr+1)*(psc+1))/72MHz=1000us=1ms
u32 arr=1000-1;
u32 psc=72-1;
u32 HcCount=0; //ms计数
//初始化
void HcsrInit(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//使能RCC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//PA6 Trig 发送电平引脚
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
//PA7 Echp 接收电平引脚
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
//PA0 KEY
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period=arr;
TIM_TimeBaseStructure.TIM_Prescaler=psc;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //不分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许更新中断
TIM_Cmd(TIM3,DISABLE); //失能时钟外设(先关掉,后面开)
//中断管理
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //开启TIM3时钟中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure);
}
//定时器TIM3中断服务程序
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET) //检查TIM3是否发生中断,TIM3开启后1ms进一次中断
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除更新中断标志
HcCount++; //溢出的时间,一次1ms
}
}
//打开定时器
void OpenTimerForHc()
{
TIM_SetCounter(TIM3,0); //清除计数
HcCount = 0;
TIM_Cmd(TIM3, ENABLE); //使能TIM2外设
}
//关闭定时器
void CloseTimerForHc()
{
TIM_Cmd(TIM3, DISABLE); //使能TIM2外设
}
//获取定时器时间
u32 GetTimer(void)
{
u32 t = 0;
t = HcCount*1000; //转化为us
t += TIM_GetCounter(TIM3); //未溢出的时间,单位us
TIM2->CNT = 0; //定时器计数寄存器值清0
delay_ms(50);
return t;
}
hcsr.h
#ifndef __HCSR__H
#define __HCSR__H
#include "sys.h"
#define TRIG_Send PAout(6)
#define ECHO_Reci PAin(7)
#define KEY PAin(0)
void HcsrInit(void);
void TIM3_IRQHandler(void);
u32 GetTimer(void);
void OpenTimerForHc(void);
void CloseTimerForHc(void);
#endif
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "hcsr.h"
#include "OLED.h"
int main(void)
{
float distance = 0;
u32 time=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
OLED_Init();
delay_init();
HcsrInit();
OLED_ShowString(1,3,"Distance-cm:");
while(1)
{
//当按键按下触发传感器测距
if(KEY==0)
{
delay_ms(20);
if(KEY==0)
{
//防止按键长按连触
while(KEY==0);
//向传感器发出信号,开始测距
TRIG_Send=1;
delay_us(20);
TRIG_Send=0;
//捕获高电平持续时间
while(ECHO_Reci==0);
OpenTimerForHc(); //捕获上升沿开启时钟
while(ECHO_Reci==1);
CloseTimerForHc(); //捕获下降沿关闭时钟
}
}
time = GetTimer(); //获取高电平持续时间
distance =time/58.3; //计算距离
OLED_ShowNum(3,7,distance,4); //OLED显示
}
}
5、效果