基于stm32的超声波模块(中断实现)

开发板:秉火-霸道V1
芯片:STM32F103ZET6
定时器:TIM2
通道: 3

模块工作原理

  • 采用 IO 触发测距,给 Trig 引脚至少 10us 的高电平信号;
  • 模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
  • 有信号返回,通过引脚 Echo 输出一高电平,高电平持续的时间就是 超声波从发射到返回的时间.
  • 测试距离 = (高电平时间 * 声速(340M/S)) / 2;

时序图

在这里插入图片描述

我们可以借助通用定时器的 输入捕获 来测量 Echo 引脚高电平持续的时间

HC_SR04.h

#ifndef _BSP_HCSR04_H
#define _BSP_HCSR04_H

#include"stm32f10x.h"
#include"stm32f10x_tim.h"

//TIM2
#define GENERAL_TIMx            TIM2
#define GENERAL_TIMx_CLK_FUN    RCC_APB1PeriphClockCmd
#define GENERAL_TIMx_CLK        RCC_APB1Periph_TIM2

//Trig引脚定义---PA10
#define HCSR04_GPIO_CLK_FUN  RCC_APB2PeriphClockCmd
#define HCSR04_GPIO_CLK      RCC_APB2Periph_GPIOA
#define HCSR04_GPIO_TRIG_PORT GPIOA
#define HCSR04_GPIO_TRIG_PIN  GPIO_Pin_10

#define HCSR04_TRIG_Hight   HCSR04_GPIO_TRIG_PORT->BSRR = HCSR04_GPIO_TRIG_PIN
#define HCSR04_TRIG_Low     HCSR04_GPIO_TRIG_PORT->BRR = HCSR04_GPIO_TRIG_PIN

//TIM引脚定义
#define GENERAL_TIMx_CH3_CLK_FUN    RCC_APB2PeriphClockCmd
#define GENERAL_TIMx_CH3_CLK        RCC_APB2Periph_GPIOA
#define GENERAL_TIMx_CH3_PORT       GPIOA
#define GENERAL_TIMx_CH3_PIN        GPIO_Pin_2
#define GENERAL_TIMx_CHANNEL_x      TIM_Channel_3

//TIM2中断
#define GENERAL_TIMx_IRQn       TIM2_IRQn
#define GENERAL_TIMx_IRQHandler TIM2_IRQHandler 


typedef struct {
    uint8_t Capture_FinishFlag; // 捕获结束标志位
    uint8_t Capture_StartFlag;  // 捕获开始标志位
    uint16_t Capture_CcrValue;  // 捕获寄存器的值
    uint16_t Capture_Period;    // 自动重装载寄存器更新标志
} TIM_ICUserValueTypeDef;

extern TIM_ICUserValueTypeDef TIM_ICUserValueStruct;

void TIM_Config(void);

void HCSR04_GPIO_Config(void);
void HCSR04_TRIG_Send(void);


#endif /*_BSP_HCSR04_H*/

HC_SR04.c

/*
    Trig: PA2
    Echo: PA10
*/

#include"bsp_HCSR04.h"
#include "bsp_delay.h"

TIM_ICUserValueTypeDef TIM_ICUserValueStruct = {0,0,0,0};

//HCSR04初始化引脚
void HCSR04_GPIO_Config(void)
{
    //定义GPIO结构体变量
    GPIO_InitTypeDef GPIO_InitStruct;
    //打开时钟
    HCSR04_GPIO_CLK_FUN(HCSR04_GPIO_CLK,ENABLE);

    //Trig引脚
    GPIO_InitStruct.GPIO_Pin = HCSR04_GPIO_TRIG_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(HCSR04_GPIO_TRIG_PORT,&GPIO_InitStruct);
}

void HCSR04_TRIG_Send(void)
{
    HCSR04_TRIG_Hight;
    Delay_Us(15);
    HCSR04_TRIG_Low;
}


static void GENERAL_TIMx_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    GENERAL_TIMx_CH3_CLK_FUN(GENERAL_TIMx_CH3_CLK,ENABLE);

    GPIO_InitStruct.GPIO_Pin = GENERAL_TIMx_CH3_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GENERAL_TIMx_CH3_PORT,&GPIO_InitStruct);
}

//中断初始化
static void GENERAL_TIMx_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStruct;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

    //设置中断通道
    NVIC_InitStruct.NVIC_IRQChannel = GENERAL_TIMx_IRQn;
    //设置子优先级
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    //设置抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    //中断通道使能
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStruct);
}

static void GENERAL_TIMx_Mode_Config(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_ICInitTypeDef TIM_ICInitStruct;

    GENERAL_TIMx_CLK_FUN(GENERAL_TIMx_CLK,ENABLE);

    //初始化时基
    TIM_TimeBaseInitStruct.TIM_Prescaler = (72-1);
    TIM_TimeBaseInitStruct.TIM_Period = 0xFFFF;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
    
    TIM_TimeBaseInit(GENERAL_TIMx,&TIM_TimeBaseInitStruct);

    //初始化 IC
    TIM_ICInitStruct.TIM_Channel = GENERAL_TIMx_CHANNEL_x;
    TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStruct.TIM_ICFilter = 0;

    TIM_ICInit(GENERAL_TIMx,&TIM_ICInitStruct);

    //清楚更新中断标志
    TIM_ClearFlag(GENERAL_TIMx,TIM_FLAG_Update | TIM_FLAG_CC3);
    //中断初始化
    TIM_ITConfig(GENERAL_TIMx,TIM_FLAG_Update | TIM_FLAG_CC3,ENABLE);
    //使能TIM
    TIM_Cmd(GENERAL_TIMx,ENABLE);
}

void TIM_Config(void)
{
    GENERAL_TIMx_GPIO_Config();
    GENERAL_TIMx_NVIC_Config();
    GENERAL_TIMx_Mode_Config();
}

TIM2中断函数

详细过程参考野火例徎 32-TIM—高级定时器

//TIM2中断函数
void GENERAL_TIMx_IRQHandler(void)
{
  //判断是否超出Period   检测位为更新中断
  //若是更新,改变Capture_Period值
  if(TIM_GetITStatus(GENERAL_TIMx,TIM_IT_Update) != RESET)
  {
    TIM_ICUserValueStruct.Capture_Period++;
    //清除中断等待
    TIM_ClearITPendingBit(GENERAL_TIMx,TIM_IT_Update);
  }
  //捕获边沿
  if(TIM_GetITStatus(GENERAL_TIMx,TIM_IT_CC3) != RESET)
  {
    //表示第一次捕获  清除CCR
    if(TIM_ICUserValueStruct.Capture_StartFlag == 0)
    {
      
      TIM_SetCounter(GENERAL_TIMx,0);              //从0开始计数
     TIM_ICUserValueStruct.Capture_CcrValue = 0;  //捕获值为0 
     // 自动重装载寄存器更新标志清0
			TIM_ICUserValueStruct.Capture_Period = 0;
      //改变捕获极性
      TIM_OC3PolarityConfig(GENERAL_TIMx,TIM_ICPolarity_Falling);
      TIM_ICUserValueStruct.Capture_StartFlag = 1;
    }
    //第二次捕获
    else
    {
      //得到CCR的值
      TIM_ICUserValueStruct.Capture_CcrValue = TIM_GetCapture3(GENERAL_TIMx);
      //改变捕获极性
      TIM_OC3PolarityConfig(GENERAL_TIMx,TIM_ICPolarity_Rising);
      //改变标志
      TIM_ICUserValueStruct.Capture_StartFlag = 0;
      TIM_ICUserValueStruct.Capture_FinishFlag = 1;
    }
    TIM_ClearITPendingBit (GENERAL_TIMx,TIM_IT_CC3);	
  }
}

在这里插入图片描述

在这里插入图片描述

delay函数

#include "bsp_delay.h"

void Delay_Us( __IO uint32_t us)
{
    uint32_t i;
    SysTick_Config(SystemCoreClock/1000000);
    for (i=0; i<us; i++) 
    {

    // 当计数器的值减小到 0 的时候,CRTL 寄存器的位 16 会置 1

    while ( !((SysTick->CTRL)&(1<<16)) );

    }

    // 关闭 SysTick 定时器

    SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;

}

main.c

/*
	按下 K1 启动测量
*/
#include"bsp_HCSR04.h"
#include"bsp_usart.h"
#include"bsp_key.h"

int main()
{
	uint32_t time;
	
	// TIM 计数器的驱动时钟
	uint32_t TIM_PscCLK = 72000000 / (71+1);
	float d = 0;

	USART_Config();
	HCSR04_GPIO_Config();
	TIM_Config();
	KEY_GPIO_Config();
	
	printf("\rHC_SR04实验\n");
	
	while (1)
	{
		if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN)== KEY_ON)
			HCSR04_TRIG_Send();
		if(TIM_ICUserValueStruct.Capture_FinishFlag == 1)
		{
			// 计算高电平时间的计数器的值
			time = TIM_ICUserValueStruct.Capture_Period * (0xFFFF+1) + (TIM_ICUserValueStruct.Capture_CcrValue+1);

			printf ( "\r\n测得高电平脉宽时间:%ld.%ld s\r\n",time/TIM_PscCLK,time%TIM_PscCLK );
			d = (float)time * 170 / 10000;
			printf("距离为:");
			Print_Float(d);

			TIM_ICUserValueStruct.Capture_FinishFlag = 0;			
		}		
	}
}

上述部分代码移植了野火的例程代码

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点灯大师~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值