野火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 */

程序现象

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

相关推荐
米饭不加菜几秒前
常用基本求导公式与法则(超详细推导版——上)
经验分享·笔记
嘉子的秃头日记5 分钟前
机械革命“自动修复”无法修复你的电脑
stm32·单片机·电脑
森旺电子15 分钟前
电子负载使用介绍
单片机·嵌入式硬件
青山是哪个青山9 小时前
LangChain 学习笔记(四):Message 与提示词模板
笔记·学习·langchain
hsjiasb10 小时前
FreeRTOS学习(二十六)——动态内存管理heap_1到heap_5
stm32·单片机·学习·学习笔记·freertos
LCG元11 小时前
STM32+ESP8266+MQTT 物联网气象站:从零搭建温湿度远程监测系统(附完整源码)
stm32·物联网·struts
Shell运维手记12 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
FakeOccupational13 小时前
【电路笔记 STM32】Cortex-M7 内核上的数据缓存(D-Cache)结构+MPU+DMA&Cache+STM32CubeMX配置
笔记·stm32·缓存
动词ing13 小时前
【学习笔记】C语言(数组指针与指针数组+字符数组+函数+参数传递+字符串作为形参+递归函数+指针函数+回调函数+结构体嵌套+内存动态分配函数)
c语言·笔记·学习
殷忆枫14 小时前
基于K210与STM32的智能垃圾分类与物联网监管系统
stm32·物联网·分类