第四章 基于Freertos智能小车的超声波测距

        本章继续要前三章的基础上加入超声波模块,引入测距的功能,方便在后期开发超声波跟随与超声波避障。同时利用蓝牙模块,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 */
  }
}


        
        

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值