STM32标准库通用定时器输入捕获
1.STM32标准库时钟树设置2.通过keil内置标准库创建stm32工程3.STM32硬件IIC使用4.STM32FATFS文件系统移植5.STM32SPIFLASH读写6.STM32标准库内部Flash读写7.STM32F103xC,xD,xE引脚定义8.STM32标准库通用定时器PWM生成9.STM32标准库通用定时器计数10.STM32标准库基本定时器11.STM32标准库RTC时钟12.STM32ADC单通道转换13.STM32标准库串口DMA空闲中断接收14.STM32OLED使用15.STM32标准库低功耗16.STM32标准库通用定时器输出比较
17.STM32标准库通用定时器输入捕获
18.STM32硬件IIC使用STM32标准库定时器输入捕获
1.输入捕获介绍
输入捕获为STM32定时器的一个功能,可以用来测量输入信号的频率和占空比。
具体原理:当输入信号经过比较捕获通道时,STM32会依据通道的极性设置决定是否触发捕获中断TIM_IT_CCx。此时定时器会将当前计数值TIMx->CNT的值保存在TIMx->CCRx中,通过计算两次捕获中断的时间差便可计算出捕获的电平时长,由此可计算出输入信号的频率、周期、占空比等信息。
在本文中,使用野火指南者开发板,配置TIM2定时器的通道4为输入通道,TIM3定时器的通道1为输出通道。
2. 输入捕获通道与定时器初始化
需要引用头文件
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
void TIM2_Init() // 定时器2初始化
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); // 使能定时器2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 使能GPIOA的时钟
GPIO_InitTypeDef GPIO_InitStructure; // 定义GPIO_InitTypeDef类型的结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; // 定义TIM_TimeBaseInitTypeDef类型的结构体
TIM_ICInitTypeDef TIM_IC_nitStructure; // 定义TIM_ICInitTypeDef类型的结构体
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ; // 选择通道4的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 设置通道4为浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚速度为50MHz
GPIO_Init(GPIOA,&GPIO_InitStructure); // 初始化GPIOA
TIM_TimeBaseInitStructure.TIM_Period = 1000-1; // 设置定时器2的自动重装值,计数到1000-1
TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1; // 设置定时器2的预分频值,分频720-1
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 设置时钟分割
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数器模式为向上计数
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); // 初始化定时器2
TIM_IC_nitStructure.TIM_Channel = TIM_Channel_4; // 选择通道4
TIM_IC_nitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 设置通道4的上升沿触发
TIM_IC_nitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 设置通道4的输入分频器
TIM_IC_nitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // 设置通道4映射到TI4
TIM_IC_nitStructure.TIM_ICFilter = 0x00; // 设置通道4的滤波器
TIM_ICInit(TIM2,&TIM_IC_nitStructure); // 初始化定时器2的通道4
NVIC_InitTypeDef NVIC_InitStructure; // 定义NVIC_InitTypeDef结构体变量
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 选择定时器2的中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 设置中断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 设置中断子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure); // 初始化NVIC_InitTypeDef结构体变量
TIM_ITConfig(TIM2,TIM_IT_CC4 | TIM_IT_Update ,ENABLE); // 使能定时器2的通道4的中断和更新中断
TIM_Cmd(TIM2,ENABLE); // 使能定时器2
}
需要注意输入通道引脚为GPIO_Mode_IN_FLOATING模式,TIM_Period为定时器溢出值。
-
TIM_ICInitTypeDef:输入捕获通道配置结构体。
-
TIM_Channel:输入通道,可选参数为TIM_Channel_x。
-
TIM_ICPolarity:输入通道极性设置,可选参数为TIM_ICSelection_DirectTI、TIM_ICSelection_IndirectTI、TIM_ICSelection_TRC。
-
TIM_ICSelection_DirectTI:将定时器输入通道1、2、3、4依次映射到IC1、IC2、IC3、IC4。
-
TIM_ICSelection_IndirectTI:将定时器输入通道1、2、3、4依次映射到IC2、IC1、IC4、IC3。
-
TIM_ICSelection_TRC:将定时器输入通道1、2、3、4连接至TRC
我暂时也不知道这个TRC是啥。
-
-
TIM_ICFilter:输入通道滤波器设置,可选参数为0x0~0xF。决定了多少次边沿变换会触发一次输入捕获。
-
3. 中断函数编写
输入捕获中断与定时器中断共用一个中断NVIC。
uint16_t Up_Capture_Cnt,Down_Capture_Cnt,Up_Capture,Up_Capture_Cnt_Temp,Down_Capture;
uint16_t timer_cnt2,timer_cnt1 = 0;
uint16_t Get_State = 0,Get_State1 = 0;
void TIM2_IRQHandler() // 定时器2中断函数
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET) // 定时器2更新中断
{
timer_cnt1++; // 定时器计数标志量1每溢出一次加一
timer_cnt2++; // 定时器计数标志量2每溢出一次加一
if(timer_cnt1 == 10000) // 定时器计数标志量1溢出时清零
{
timer_cnt1 = 0; // 定时器计数标志量1清零
}
if(timer_cnt2 == 10000) // 定时器计数标志量2溢出时清零
{
timer_cnt2 = 0; // 定时器计数标志量2清零
}
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC4) == SET) // 定时器2输入捕获中断
{
switch(Get_State) // 判断输入捕获状态
{
case 0 :
Up_Capture_Cnt_Temp = Up_Capture_Cnt; // 保存上一次输入捕获通道的值
Down_Capture_Cnt = TIM_GetCapture4(TIM2); // 获取当前输入捕获通道的值
Down_Capture = Down_Capture_Cnt + (timer_cnt2 * 1000) - Up_Capture_Cnt_Temp; // 计算脉冲宽度
timer_cnt1 = 0; // 定时器计数标志量1清零
timer_cnt2 = 0; // 定时器计数标志量2清零
TIM_ClearITPendingBit(TIM2,TIM_IT_CC4); // 清除输入捕获通道的中断标志位
TIM_OC4PolarityConfig(TIM2,TIM_ICPolarity_Falling); // 设置输入捕获通道的极性为下降沿
Get_State = 1; // 设置输入捕获通道的状态为1
break; // 跳出switch语句
case 1:
Up_Capture_Cnt = TIM_GetCapture4(TIM2); // 获取当前输入捕获通道的值
Up_Capture = Up_Capture_Cnt + (timer_cnt1 * 1000) - Down_Capture_Cnt; // 计算脉冲宽度
timer_cnt1 = 0; // 定时器计数标志量1清零
timer_cnt2 = 0; // 定时器计数标志量2清零
TIM_ClearITPendingBit(TIM2,TIM_IT_CC4); // 清除输入捕获通道的中断标志位
TIM_OC4PolarityConfig(TIM2,TIM_ICPolarity_Rising); // 设置输入捕获通道的极性为上升沿
Get_State = 0; // 设置输入捕获通道的状态为0
break; // 跳出switch语句
}
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); // 清除定时器溢出中断标志位
}
4. 中断函数代码具体逻辑解释
光看代码可能捋不清先后关系,来看下图就知道了,如图1所示:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤