野火STM32_HAL库版课程笔记-TIM通道捕获应用之超声波测距

前置介绍

超声波测距模块规格手册

在代码中需要对 33ms 进行处理, 在配置的时候, 用定时器进行计数测量这个脉冲的时间.

其是从 0 计数到 ARR , 那么这个计数的时间就不要低于 33ms, 才能保证如果是最远距离也不会导致 ARR 溢出重新计数, 那么就没有办法去计算时间了.

所以在频率配置上要特别注意, 每一个完整的技术周期要超过这个时间.

超声波测距模块其用法即为:
  1. 将 TRIG 引脚接入 MCU 的一个输出引脚
  2. 输出引脚输出一个 10us 的高电平, 超声波测距模块收到信号开始工作, 发出超声波再收到超声波
  3. 接入定时器, 通过 输入捕获模式 捕获回响信号的高电平和低电平, 即可得到高电平的宽度.
  4. 计算高电平区间计数数量, 与频率共同计算得到高电平时间
  5. 通过距离推算公式, 得到超声波测距的距离.
TIM-输入捕获之超声波测距
实验关键点: 如何捕获上升沿和下降沿?

假设使用定时器通道 2 做输入捕获, 虽然在选择输入捕获模式的时候, 可以将上升沿和下降沿都进行计数, 但是没办法在上升沿和下降沿都进行捕获.

所以就要用到 TI2FP2 做为 直接捕获 (比如捕获上升沿部分), 再用 通道 1TI1FP2 也就是 间接捕获 (捕获信号下降沿部分)

即: 使用两个通道, 来传输一个信号.

以为我们从框图中能够看到, 通道一和通道二是 直接捕获间接捕获 相互的, 而通道三和通道四则是直接和间接相互的. 那么我们就可以检测. 将下降沿的读数减去上升沿的读数, 就能得到高电平期间的计数.

TIM-超声波测距所用函数

项目配置

GPIO

PA15 设置为 GPIO_Output

User Label 设置为 CS100A_TRIG

TIM2

先将 Channel2 设置为 Input Capture direct mode (直接输入捕获模式)

再将 Channel1 设置为 Input Capture indirect mode (间接输入捕获模式)

两个通道的 IC Selection 因为上面已经选择了直接和间接, 所以这里就只有一个选项, 默认即可

直接通道选择捕获上升沿, 间接通道选择捕获下降沿.

Prescaler 修改为 72 - 1.

Counter Period 默认即可, 注意: 不要小于测距模块 33 ms 的返回时间

使能 auto-reload preload .

指令周期 - CPU工作的基本单元, CPU从内存中取出一条指令并执行完成所需要的全部时间

此处为语雀内容卡片,点击链接查看:https://www.yuque.com/heartacheboy/opk4mi/egfnxkwmgp9yw97u

代码部分

复制代码
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include <stdio.h>  // 使用 printf 函数
#include <string.h> // 使用 strncmp

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

uint32_t start_time = 0;    // 记录超声波回响开始时间 (单位: 定时器计数值)
uint32_t end_time = 0;      // 记录超声波回响结束时间 (单位: 定时器计数值)

float pulse_width = 0.0f;   // 计算出的超声波高电平脉宽时间 (单位: 微秒 s)
float distance = 0.0f;      // 根据脉宽计算出的距离值 (单位: 厘米 cm)

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/**
  * @brief  发送超声波 TRIG 触发信号
  * @note   输出一个大约 10us 的高电平, 用于启动超声波测距
  * @retval 无
  */
void CS100A_TRIG_Start(void)
{
  // 设置 TRIG 引脚为高电平, 开始发出超声波脉冲
  HAL_GPIO_WritePin(GPIOA, CS100A_TRIG_Pin, GPIO_PIN_SET);
  
  // 因为延迟的最小单位是 ms, 所以这里使用软延迟实现. 
  // 内核时钟频率是 72MHz, 也就是每执行 72个指令周期, 才会消耗掉 1us, 
  // 而一个 for 循环是八个指令周期, 操作九次才能够达到 8 * 9 = 72, 消耗 1us, 
  // 而我们需要 10us 的高电平, 就需要用 9 * 10 次
  
  // 简单延时, 用于产生大约 10us 的脉冲宽度 (72)
  for (uint16_t i = 0; i < 90; i++);
  
  // 设置 TRIG 引脚为低电平, 完成触发
  HAL_GPIO_WritePin(GPIOA, CS100A_TRIG_Pin, GPIO_PIN_RESET);
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    // 清零定时器计数器 CNT
    __HAL_TIM_SET_COUNTER(&htim2, 0);
    
    // 启动输入捕获功能 (通道1为间接, 捕获下降沿; 通道2为直接, 捕获上升沿)
    // 注意: 必须在触发前先开启捕获, 否则肯呢个错过回拨信号
    // 捕获下降沿
    HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_1);
    // 捕获上升沿
    HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_2);
    
    
    // 发送超声波触发信号
    CS100A_TRIG_Start();
    
    // 检测通道二所捕获的上升沿标志位 (等待回波信号上升沿捕获完成, 即开始计时)
    while(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC2) == RESET);
    
    // 代表检测到了回波信号的高电平 (清除上升沿中断标志位)
    __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_CC2);
    
    // 读取通道2捕获的上升沿时间 (起始时间) (从对应的htim中读取捕获到的值)
    start_time = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
    
    
    // 等待回波信号下降沿捕获完成, 即停止计时
    // 下降沿是由通道一, 的间接捕获来完成的, 所以这里要检测通道一的CC1状态
    while(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC1) == RESET);
    
    // 代表检测到了回波信号的高电平 (清除上升沿中断标志位)
    __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_CC1);
    
    // 读取通道1捕获的下降沿时间 (结束时间)
    end_time = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
    
    
    // 停止捕获 (避免干扰下次采样)
    // 停止捕获下降沿
    HAL_TIM_IC_Stop(&htim2, TIM_CHANNEL_1);
    // 停止捕获上升沿
    HAL_TIM_IC_Stop(&htim2, TIM_CHANNEL_2);
    
    
    // 计算计数差
    uint32_t delta = end_time - start_time;
    
    // 换算成脉宽 (单位: s) 
    // 因为是 1MHz 所以是一秒记一百万个数. 
    pulse_width = (float)delta * 1e-6f;
    
    // 根据声速换算成距离 (单位: m)
    distance = pulse_width * 340.0f / 2.0f;
    
    printf("当前距离: %.2f m\r\n", distance);
    
    // 500ms 测量一次
    // 当测量完成后, 就会回到上面, 重新清零定时器计数器, 再一次开启输入捕获, 捕获上升沿和下降沿
    // 计算中间的计数值, 转换脉宽, 转换距离等. 
    HAL_Delay(500);
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

/* USER CODE BEGIN 4 */

/**
  * @brief  重定向 printf 的输出到串口
  * @param  ch: 要发送的字符
  * @param  f:  文件指针 (标准库要求的参数, 一般不使用)
  * @retval 返回发送的字符
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
  return ch;
}

/* USER CODE END 4 */

程序现象

移动超声波测距模块 或者 改变用手遮挡超声波测距模块的距离, 可以看到输出距离发生变化.

相关推荐
dqsh062 小时前
振兴中华之threadX RTOS移植到stm32用stm32cubeMX 保姆级教程
stm32·单片机·嵌入式硬件·rtos·threadx
Yu_Lijing2 小时前
基于C++的《Head First设计模式》笔记——访问者模式
c++·笔记·设计模式
浅念-2 小时前
Linux 进程与操作系统
linux·运维·服务器·网络·数据结构·笔记·网络协议
刘若里3 小时前
【论文阅读】自适应稀疏自注意力——可直接用!
论文阅读·人工智能·笔记·深度学习·计算机视觉
滴_咕噜咕噜3 小时前
WPF项目实战视频《五》(主要为项目实战-客户端)
笔记
GreenGoblin3 小时前
14.DSP学习记录之I2C
单片机·dsp开发·c2000
老虎06273 小时前
LeetCode热题100 刷题笔记(第六天)双指针 「 盛最多水的容器」
笔记·算法·leetcode
ZhiqianXia3 小时前
Gem5 学习笔记(3) : 源代码鸟瞰
笔记·学习