STM32 TIM通道捕获配置函数及实验

一、TIM通道捕获配置函数

1. 编码器相关函数

HAL_TIM_Encoder_Start(TIM_HandleTypeDef *htim, uint32_t Channel)

功能: 启动定时器的编码器接口模式
参数:

复制代码
htim:定时器句柄指针
Channel:通道选择

**应用:**用于旋转编码器的位置计数

__HAL_TIM_GET_COUNTER(HANDLE)

功能: 获取定时器的当前计数值
参数: 定时器句柄
**返回值:**当前计数器值(16位或32位)

__HAL_TIM_IS_TIM_COUNTING_DOWN(HANDLE)

功能: 检查定时器是否正在向下计数
参数: 定时器句柄
**返回值:**TRUE(向下计数)或FALSE(向上计数)

__HAL_TIM_SET_COUNTER(HANDLE, COUNTER)

功能: 设置定时器的计数值
参数:

复制代码
__HANDLE__:定时器句柄
__COUNTER__:要设置的计数值

2. 输入捕获相关函数

HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel)

功能: 启动输入捕获模式
参数:

复制代码
htim:定时器句柄
Channel:输入捕获通道

HAL_TIM_IC_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)

功能: 停止输入捕获模式
参数:

复制代码
htim:定时器句柄
Channel:输入捕获通道

HAL_TIM_ReadCapturedValue(const TIM_HandleTypeDef *htim, uint32_t Channel)

功能: 读取输入捕获的值
参数:

复制代码
htim:定时器句柄
Channel:通道选择

**返回值:**捕获到的计数值

3. 标志位操作宏

__HAL_TIM_GET_FLAG(HANDLE, FLAG)

功能: 获取定时器状态标志
参数:

复制代码
__HANDLE__:定时器句柄
__FLAG__:标志位

__HAL_TIM_CLEAR_FLAG(HANDLE, FLAG)

功能: 清除定时器状态标志
参数:

复制代码
__HANDLE__:定时器句柄
__FLAG__:要清除的标志位

二、编码器模式实验

1. 实验现象

当旋转编码器时,串口会实时显示转动方向和计数值变化(如"顺时针移动"或"逆时针移动");当编码器停止转动超过2秒后,串口会持续显示"编码器静止超过2s"的提示信息。

2. 示例代码

TIM初始化

复制代码
/**
  * @brief TIM3初始化函数,配置为编码器模式
  */
void MX_TIM3_Init(void)
{
  TIM_Encoder_InitTypeDef sConfig = {0};  // 编码器配置结构体
  TIM_MasterConfigTypeDef sMasterConfig = {0};  // 主模式配置结构体

  // 定时器基础参数配置
  htim3.Instance = TIM3;                    // 使用TIM3定时器
  htim3.Init.Prescaler = 4-1;               // 预分频器,4分频
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;  // 计数器模式:向上计数
  htim3.Init.Period = 65535;                // 自动重装载值,16位最大值
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;  // 时钟分频:不分频
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;  // 自动重装载预装载禁止

  // 编码器接口配置
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;    // 编码器模式:在TI1和TI2边沿计数
  sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;   // 通道1极性:上升沿
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;  // 通道1输入:直接输入
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;         // 通道1预分频:不分频
  sConfig.IC1Filter = 0;                         // 通道1滤波器:无滤波
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;   // 通道2极性:上升沿
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;  // 通道2输入:直接输入
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;         // 通道2预分频:不分频
  sConfig.IC2Filter = 0;                         // 通道2滤波器:无滤波
  
  // 初始化编码器接口
  if (HAL_TIM_Encoder_Init(&htim3, &sConfig) != HAL_OK)
  {
    Error_Handler();  // 初始化失败,进入错误处理
  }

  // 主模式配置
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;  // 主模式触发输出:复位
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;  // 主从模式:禁止
  
  // 配置主模式同步
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();  // 配置失败,进入错误处理
  }
}

主函数

复制代码
// 全局变量定义
int16_t cnt = 0;      // 当前编码器计数值
int16_t last = 0;     // 上一次编码器计数值
uint32_t time = 0;    // 时间戳,用于超时检测
uint8_t sta = 0;      // 状态标志位

/**
  * @brief 主函数
  */
int main(void)
{
  // 系统初始化
  HAL_Init();                           // 初始化HAL库
  SystemClock_Config();                 // 配置系统时钟
  
  // 外设初始化
  MX_GPIO_Init();                       // 初始化GPIO
  MX_TIM3_Init();                       // 初始化TIM3编码器
  MX_USART1_UART_Init();                // 初始化USART1串口
  
  // 启动编码器接口
  HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);

  // 主循环
  while (1)
  {
    // 读取当前编码器计数值
    cnt = __HAL_TIM_GET_COUNTER(&htim3);
    
    // 检测编码器是否发生移动
    if(cnt != last)
    {
      sta = 0;                          // 重置静止状态标志
      time = HAL_GetTick();             // 记录当前时间戳
      int16_t diff = cnt - last;        // 计算计数值变化量
      
      // 根据计数方向判断旋转方向并输出
      if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3))
        printf("逆时针移动%d\r\n", diff);    // 向下计数:逆时针
      else
        printf("顺时针移动%d\r\n", diff);    // 向上计数:顺时针
      
      last = cnt;                       // 更新上一次计数值
    }
    else
    {
      // 编码器静止状态处理
      if(HAL_GetTick() - time > 2000 && sta == 0)
        sta = 1;                        // 设置静止状态标志
      
      printf("编码器静止超过2s");        // 输出静止提示
    }
  }
}

三、超声波测距实验

1. 实验现象

系统会周期性地通过串口输出当前测量的距离值(单位:米),当超声波传感器前方物体距离发生变化时,输出的距离数值会相应变化,准确反映出物体与传感器之间的实时距离,测量周期为500毫秒。

2. 示例代码

GPIO初始化

复制代码
/**
  * @brief GPIO初始化函数
  * 配置超声波模块相关引脚:
  * - PA15: 超声波TRIG触发信号输出引脚
  */
void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* 使能GPIO端口时钟 */
  __HAL_RCC_GPIOD_CLK_ENABLE();    // 使能GPIOD时钟
  __HAL_RCC_GPIOA_CLK_ENABLE();    // 使能GPIOA时钟
  __HAL_RCC_GPIOB_CLK_ENABLE();    // 使能GPIOB时钟

  /* 配置GPIO引脚初始输出电平 */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);  // PA15初始化为低电平

  /* 配置PA15引脚为超声波TRIG信号输出 */
  GPIO_InitStruct.Pin = GPIO_PIN_15;           // 引脚15
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  // 推挽输出模式
  GPIO_InitStruct.Pull = GPIO_NOPULL;          // 无上下拉电阻
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速输出
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);      // 初始化GPIO配置
}

TIM初始化

复制代码
/**
  * @brief TIM2定时器初始化函数
  * 配置为输入捕获模式,用于超声波测距的时间测量
  */
void MX_TIM2_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};    // 时钟源配置结构体
  TIM_MasterConfigTypeDef sMasterConfig = {0};        // 主模式配置结构体
  TIM_IC_InitTypeDef sConfigIC = {0};                 // 输入捕获配置结构体

  // 定时器基础参数配置
  htim2.Instance = TIM2;                              // 使用TIM2定时器
  htim2.Init.Prescaler = 72-1;                        // 预分频器72分频,1MHz计数频率(72MHz/72)
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;        // 向上计数模式
  htim2.Init.Period = 65535;                          // 自动重装载值,16位最大值
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;  // 时钟分频:不分频
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;  // 禁止自动重装载预装载
  
  // 初始化定时器基础配置
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

  // 配置时钟源为内部时钟
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }

  // 初始化输入捕获模式
  if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

  // 配置主模式
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;          // 主模式触发输出:复位
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 禁止主从模式
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  // 配置通道1输入捕获参数(用于测量回波下降沿)
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;     // 下降沿捕获
  sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;          // 间接TI输入
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;                      // 输入捕获不分频
  sConfigIC.ICFilter = 0;                                      // 无输入滤波
  if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }

  // 配置通道2输入捕获参数(用于测量回波上升沿)
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;      // 上升沿捕获
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;            // 直接TI输入
  if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
}

主函数

复制代码
// 超声波测距相关变量定义
uint32_t start_time = 0;     // 回波开始时间(上升沿捕获值)
uint32_t end_time = 0;       // 回波结束时间(下降沿捕获值)
float pluse_width = 0.0f;    // 回波脉冲宽度(单位:秒)
float distance = 0.0f;       // 计算得到的距离值(单位:米)

/**
  * @brief 超声波TRIG触发信号生成函数
  * 产生一个10us的高电平脉冲触发超声波模块
  */
void CS_TRIG_Start(void)
{
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);  // TRIG引脚置高
  for(uint16_t i = 0; i < 90; i++);                     // 短暂延时约10us
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET); // TRIG引脚置低,结束触发
}

/**
  * @brief 主函数 - 超声波测距应用
  */
int main(void)
{
  // 系统初始化
  HAL_Init();                           // 初始化HAL库
  SystemClock_Config();                 // 配置系统时钟
  
  // 外设初始化
  MX_GPIO_Init();                       // 初始化GPIO(TRIG引脚)
  MX_TIM2_Init();                       // 初始化TIM2输入捕获
  MX_USART1_UART_Init();                // 初始化USART1串口

  // 主循环 - 持续进行距离测量
  while (1)
  {
    // 初始化定时器计数器
    __HAL_TIM_SET_COUNTER(&htim2, 0);   // 清零TIM2计数器
    
    // 启动输入捕获通道
    HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_1);  // 启动通道1(下降沿捕获)
    HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_2);  // 启动通道2(上升沿捕获)
    
    // 发送超声波触发脉冲
    CS_TRIG_Start();                    // 产生10us触发信号
    
    // 等待回波上升沿(通道2捕获标志)
    while(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC2) == RESET);  // 阻塞等待上升沿
    __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_CC2);               // 清除捕获标志
    start_time = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);  // 读取上升沿时间
    
    // 等待回波下降沿(通道1捕获标志)
    while(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC1) == RESET);  // 阻塞等待下降沿
    __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_CC1);               // 清除捕获标志
    end_time = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);    // 读取下降沿时间
    
    // 停止输入捕获
    HAL_TIM_IC_Stop(&htim2, TIM_CHANNEL_1);                   // 停止通道1捕获
    HAL_TIM_IC_Stop(&htim2, TIM_CHANNEL_2);                   // 停止通道2捕获
    
    // 计算距离
    uint32_t delta = end_time - start_time;                   // 计算时间差(微秒数)
    pluse_width = (float)delta * 1e-6f;                      // 转换为秒
    distance = pluse_width * 340.0f / 2.0f;                  // 计算距离(声速340m/s,往返除以2)
    
    // 输出测量结果
    printf("当前距离:%.2f m\r\n", distance);                 // 串口输出距离值
    
    // 延时500ms后进行下一次测量
    HAL_Delay(500);
  }
}
相关推荐
偶像你挑的噻10 小时前
15-Linux驱动开发-PWM子系统
linux·驱动开发·stm32·嵌入式硬件
硅农深芯10 小时前
是时候跟GitBucket说再见了
git·单片机
未来之窗软件服务11 小时前
幽冥大陆(三十八)P50酒店门锁SDK C#仙盟插件——东方仙盟筑基期
开发语言·单片机·c#·东方仙盟·东方仙盟sdk·东方仙盟vos智能浏览器
Java小白,一起学习14 小时前
STM32新建工程(标准库官网下载)
stm32·单片机·嵌入式硬件
Bona Sun15 小时前
单片机手搓掌上游戏机(十五)—pico运行fc模拟器之编译环境
c语言·c++·单片机·游戏机
小尧嵌入式16 小时前
C++基础语法总结
开发语言·c++·stm32·单片机·嵌入式硬件·算法
2401_8534482316 小时前
STM32F103C8T6---OLED显示屏
stm32·单片机·oled
沐欣工作室_lvyiyi16 小时前
基于单片机的居家智能音箱系统(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·智能音箱
沐欣工作室_lvyiyi16 小时前
基于单片机的飞机客舱窗帘控制系统(论文+源码)
单片机·嵌入式硬件·毕业设计·窗户