本章继续要前三章的基础上加入超声波模块,引入测距的功能,方便在后期开发超声波跟随与超声波避障。同时利用蓝牙模块,stm32计算出距离都会传输到手机APP上进行显示。此外大家可以回顾前几章内容学习制作小车,零基础制作Freertos智能小车
1.模块概述
此次的模块使用的是HC-SR04,核心功能是通过发射和接收超声波信号,适用于2cm~400cm的中短距离测量。工作电压5V。
2.模块工作原理
a.采用 IO 口 TRIG 触发测距信号,保持 10-20us 的高电平。
b.模块会自动发送 8 个 40khz 的方波,发送完成后,ECHO会置为1。
c.打开单片机的定时器资源进行计时,不断循环等待ECHO何实置0。
d.ECHO高电平持续的时间就是超波从发射到返回的时间,当ECHO会置为0后,关闭定时器,并读取定时器的计数值。
e.距离=(声速*时间)/2,声速为342.62m/s
3.程序设计
引脚使用
HCSR04_TRIG PA2
HCSR04_ECHO PA3
配置定时器
对于定时器不了解的大家可以参考这篇文章STM32F103的定时器
- 预分频器 (Prescaler) = 71,将 72MHz 的时钟分频为 1MHz
- 自动重载值 (Period) = 999,定时器每计数 1000 次产生一次溢出中断
- 计数频率 = 1MHz,即每个计数周期为 1 微秒 (μs)
- 定时器溢出周期 = 1000μs = 1ms,即每 1ms 产生一次中断
#ifndef __HC-SR04_H #define __HC-SR04_H #include "sys.h" #define ECHO_Reci PAin(3) #define TRIG_Send PAout(2) //超声波硬件接口定义 //超声波硬件接口定义 //超声波硬件接口定义 #define HCSR04_PORT GPIOA #define HCSR04_CLK RCC_APB2Periph_GPIOA #define HCSR04_TRIG GPIO_Pin_2 #define HCSR04_ECHO GPIO_Pin_3 void Hcsr04Init(); float Hcsr04GetLength(void ); #endif
#include "stm32f10x.h" // Device header
#include "HC-SR04.h"
#include "delay.h"
//超声波计数
u16 msHcCount = 0;
//定时器3设置
void hcsr04_NVIC()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//TIM4定时器中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//IO口初始化 及其他初始化
void Hcsr04Init()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE);
//GPIO初始化
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);
//TIM4时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
//设置定时器预分频系数和周期
TIM_TimeBaseStructure.TIM_Period = (1000-1);
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);
//清除TIM4的待处理标志位
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
//TIM4中断使能
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
//定时器中断初始化
hcsr04_NVIC();
//TIM4使能
TIM_Cmd(TIM4,DISABLE);
}
//定时器4终中断
void TIM4_IRQHandler(void)
{
//记录返回信号高电平持续的时间
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update );
msHcCount++;//定时器计数
}
}
启动测量
//打开定时器4
static void OpenTimerForHc()
{
TIM_SetCounter(TIM4,0);//定时器从0开始计数
msHcCount = 0;//计数归零
TIM_Cmd(TIM4, ENABLE); //使能
}
关闭计数
//关闭定时器4
static void CloseTimerForHc()
{
TIM_Cmd(TIM4, DISABLE);
}
测量并读取时间
//获取定时器4计数器值
u32 GetEchoTimer(void)
{
u32 t = 0;
t = msHcCount*1000;//将定时器计数转换成时间
t += TIM_GetCounter(TIM4);//定时器输入捕获
TIM4->CNT = 0; //清空定时器计数
delay_ms(50);//每次测量间隔
return t;
}
推算距离
//通过定时器4计数器值推算距离
float Hcsr04GetLength(void )
{
u32 t = 0;
int i = 0;
float lengthTemp = 0;
float sum = 0;
while(i!=5)//测量五次
{
TRIG_Send = 1; //给TRIG口输出一个高电平,延时20us
delay_us(20);
TRIG_Send = 0;
while(ECHO_Reci == 0); //等待ECHO口返回高电平信号
OpenTimerForHc(); //ECHO输出高电平之后打开定时器
i = i + 1;
while(ECHO_Reci == 1);//用中断接收8个40khz的方波
CloseTimerForHc(); //接收完成后关闭定时器
t = GetEchoTimer(); //t就是高电平持续的时间
lengthTemp = ((float)t*342.62)/2;//lengthTemp = 342.62*t/2;
sum = lengthTemp + sum ;
}
lengthTemp = sum/5.0;//测量五次取平均值
return lengthTemp;
}
4.加入主程序逻辑
在写好超声波的初始化程序后,就可以加入Freertos中。
引入头文件,创建超声波测距任务句柄,超声波测距_Task任务实现,设置全局变量,获取超声波的距离,并设置在跟随以及避障模式下生效。
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "Task.h"
#include "queue.h"
#include "usart.h"//蓝牙
/**************************** 任务句柄 ********************************/
/*
* 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
* 这个句柄可以为NULL。
*/
static TaskHandle_t HCSR04_Len_Task_Handle = NULL;/* 超声波测距任务句柄 */
static void HCSR04_Len_Task(void* pvParameters);/* 超声波测距_Task任务实现 */
/*
获取超声波的距离,只在跟随以及避障模式下生效
*/
float Len = 0.0;
/**********************************************************************
* @ 函数名 : HCSR04_Len_Task
* @ 功能说明: 获取超声波的测试距离,通过@SR04:距离#的方式发给手机APP,在终端上查看距离
* @ 参数 :
* @ 返回值 : 无
********************************************************************/
static void HCSR04_Len_Task(void* parameter)
{
while (1)
{
if(Mode == 0 || Mode == 2)//仅在跟随模式与避障模式下生效
{
Len = Hcsr04GetLength();//测距
printf("@SR04:%f#",Len);//将距离通过蓝牙传给手机APP
}
vTaskDelay(500); /* 延时100个tick */
}
}