基于STM32的输入捕获实验
2026/4/14 18:26:32 网站建设 项目流程

一、实验简介

输入捕获是STM32定时器的重要功能之一,可以用来**测量脉冲宽度**或**测量信号频率**。其基本原理是:通过检测TIMx_CHx引脚上的边沿信号,当边沿信号发生跳变(上升沿或下降沿)时,将当前定时器计数器的值存放到对应的捕获/比较寄存器中,完成一次捕获。

**实验目标**:学习通用定时器的输入捕获功能,捕获输入信号的高电平脉宽,并通过串口打印测量结果。

**硬件资源**:
- 通用定时器TIM2_CH1(PA0)作为输入捕获通道
- 串口1(TX→PA9,RX→PA10)用于打印结果
- 可选:TIM3_CH1(PA6)配合PWM输出作为信号源

二、工作原理

2.1 脉宽测量原理

以测量高电平脉宽为例:

1. **设置捕获边沿**:首先设置为**上升沿捕获**
2. **第一次捕获**:上升沿到来时,捕获当前CNT值并清零计数器,然后将捕获边沿切换为**下降沿**
3. **第二次捕获**:下降沿到来时,再次捕获CNT值
4. **计算脉宽**:两次捕获之间的计数值 × 计数周期 = 高电平持续时间

2.2 溢出处理

当被测脉宽较长时,定时器可能发生溢出。需要在中断中对溢出次数进行累加,最终高电平时间为:


高电平时间 = (溢出次数 × ARR + 最后一次捕获值) × 计数周期

2.3 状态变量设计

三、硬件连接

四、软件设计

4.1 STM32CubeMX配置

**1. 时钟配置**
- 选择外部高速时钟(HSE)
- 系统时钟设为72MHz
- APB1总线时钟72MHz(定时器时钟源)

**2. TIM2输入捕获配置**
- 通道1:输入捕获模式
- 预分频器PSC:`72-1` → 计数频率 = 72MHz / 72 = 1MHz(1μs/计数)
- 自动重装载值ARR:`65535`(最大计数范围)
- 计数方式:向上计数
- 极性:上升沿捕获(代码中会动态切换)

**3. 中断配置**
- 使能TIM2的捕获中断(CC1IE)
- 使能TIM2的更新中断(UIE)
- 设置合适的优先级

**4. USART1配置**
- 模式:异步通信
- 波特率:115200
- 数据位:8
- 停止位:1
- 无校验

**5. GPIO配置**
- PA0:输入模式,下拉
- PA9:复用推挽输出
- PA10:浮空输入

4.2 代码实现

**定义全局变量**:

```c
/* TIM2捕获状态
* bit7: 捕获完成标志
* bit6: 已捕获到高电平标志
* bit5~0: 溢出次数
*/
uint8_t TIM2CH1_CAP_STA = 0;
uint16_t TIM2CH1_CAP_VAL; // 捕获值
```

**定时器溢出中断回调**:

```c
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
if((TIM2CH1_CAP_STA & 0X80) == 0) // 还未成功捕获
{
if(TIM2CH1_CAP_STA & 0X40) // 已捕获到高电平
{
if((TIM2CH1_CAP_STA & 0X3F) == 0X3F) // 溢出次数达到上限
{
TIM2CH1_CAP_STA |= 0X80; // 标记完成
TIM2CH1_CAP_VAL = 0XFFFF;
}
else
{
TIM2CH1_CAP_STA++; // 溢出次数+1
}
}
}
}
}
```

**输入捕获中断回调**:

```c
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
if((TIM2CH1_CAP_STA & 0X80) == 0) // 还未完成捕获
{
if(TIM2CH1_CAP_STA & 0X40) // 已捕获到上升沿,当前是下降沿
{
// 捕获完成
TIM2CH1_CAP_STA |= 0X80;
TIM2CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);

// 切换回上升沿捕获,准备下一次
TIM_RESET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1);
TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);
}
else // 第一次捕获到上升沿
{
TIM2CH1_CAP_STA = 0;
TIM2CH1_CAP_VAL = 0;
TIM2CH1_CAP_STA |= 0X40; // 标记已捕获到高电平

// 清零计数器
__HAL_TIM_SET_COUNTER(&htim2, 0);

// 切换为下降沿捕获
TIM_RESET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1);
TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);
}
}
}
}
```

**主函数**:

```c
int main(void)
{
uint32_t high_time_us = 0;

HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();

// 启动输入捕获(使能捕获中断和更新中断)
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE);

printf("Input Capture Test Started...\r\n");

while(1)
{
if(TIM2CH1_CAP_STA & 0X80) // 完成一次高电平捕获
{
high_time_us = (TIM2CH1_CAP_STA & 0X3F); // 溢出次数
high_time_us *= 65536; // 溢出时间
high_time_us += TIM2CH1_CAP_VAL; // 最后一次捕获值

printf("High level duration: %d us\r\n", high_time_us);

TIM2CH1_CAP_STA = 0; // 准备下一次捕获
}
}
}
```

五、实验现象

将待测信号连接到PA0引脚,串口调试助手将打印出测量到的高电平持续时间。

**测量范围说明**:
- 计数频率1MHz,每个计数周期1μs
- ARR=65535,单次最大测量时间约65.5ms
- 通过溢出计数,可测量更长时间

**串口输出示例**:
```
Input Capture Test Started...
High level duration: 1500 us
High level duration: 2500 us
...
```

六、常见问题与注意事项

6.1 测量精度问题
- 输入捕获的精度取决于计数频率,计数频率越高精度越高,但测量范围会减小
- 可通过调整PSC预分频值在精度和范围之间权衡

6.2 信号抖动
- 可在TIM_ICInitStructure中设置IC1F滤波器参数,对输入信号进行滤波
- 滤波器值越大,抗干扰能力越强,但响应会变慢

6.3 中断优先级
- 建议将捕获中断优先级设置高于其他非关键中断
- 更新中断和捕获中断需要配合工作,优先级应合理设置

6.4 寄存器错误修复
使用`TIM_RESET_CAPTUREPOLARITY`宏时,部分HAL库版本可能存在语法错误。如遇到编译报错,请检查该宏定义并删除多余的右括号。

七、扩展应用

输入捕获功能可广泛应用于:
- **超声波测距**:捕获Echo引脚的高电平时间计算距离
- **编码器测速**:捕获脉冲间隔计算电机转速
- **频率计**:通过测量周期计算信号频率
- **电容触摸按键**:检测充放电时间变化

有需要学习嵌入式的,欢迎私信入群一起学习

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询