STM32标准库通用定时器输入捕获
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所示:

在图中可以看到,当输入捕获通道的信号周期要长于输入捕获的通道时钟周期时,会导致第二次读取的值比第一次读取的值小,如果不使用定时器溢出次数进行辅助运算会导致算出来的是负数。之后第一次读取的值+溢出时间-第二次读取的值,得到的结果就是脉冲宽度,第二次读取的值+溢出时间-第一次读取的值,得到的就是周期中另一部分的宽度。有了这些信息,就可以得到频率、周期和占空比了。
STM32标准库通用定时器输入捕获的更多相关文章
- 单片机stm32零基础入门之--初识STM32 标准库
CMSIS 标准及库层次关系 因为基于Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难.为了解决不同的芯片厂商生产的Co ...
- STM32 标准库
CMSIS 标准及库层次关系 因为基于Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难.为了解决不同的芯片厂商生产的Co ...
- stm32cube--通用定时器--输入捕获
用定时器输入捕获做红外线接收实验.(此次试验以通道2为例) ①stm32cube配置 ② ③ ④程序中主要用到的输入捕获相关寄存器 uint16_t tim_sr,tim_ccer,tim_ccr; ...
- STM32标准库GPIO操作
STM32标准库GPIO操作 STM32任何外围设备的使用都分为两部分:初始化和使用.体现在代码上就是:(1)有一个初始化函数(2)main函数中的使用 1.初始化GPIO 初始化GPIO函数代码: ...
- 初识STM32标准库
1.CMSIS 标准及库层次关系 CMSIS 标准中最主要的为 CMSIS 核心层,它包括了: STM32标准库可以从官网获得: 在使用库开发时,我们需要把 libraries 目录下的库函数文件添加 ...
- STM32之定时器输入捕获
1.输入捕获模式可以用来测量脉冲宽度或者测量频率.STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能.STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿 ...
- stm32f103_高级定时器——输入捕获/输出比较中断+pwm=spwm生成
****************************首选我们了解一下它们的功能吧********************************************************** ...
- STM32 标准库V3.5启动文件startup_stm32f10xxx.s分析
layout: post tags: [STM32] comments: true 文章目录 layout: post tags: [STM32] comments: true 前言 分析startu ...
- STM32 标准库3.5修改默认外部8M晶振为16M晶振
ST官方标准库V3.5默认的外部晶振频率为8M,实际使用中外部晶振需要修改为16M: 经过实验,修改有效,具体的patch如下: 修改 HSE_VALUE 值 diff --git "a/L ...
- STM32 HAL库的定时器中断回调函数跟串口中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { //添加回调后的程序逻辑 if (htim->Instance == ...
随机推荐
- NLP涉及技术原理和应用简单讲解【二】:paddle(分布式训练、AMP自动混合精度训练、模型量化、模型性能分析)
参考链接: https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/06_distributed_training/cluster_q ...
- Midjourney|文心一格 Prompt:完整参数列表、风格汇总、文生图词典合集
Midjourney|文心一格 Prompt:完整参数列表.风格汇总.文生图词典合集 1.Midjourney 完整参数列表 参数名称 调用方法 使用案例 注意事项 V5 V4 V3 niji 版本 ...
- RabbitMQ高级知识(消息可靠性,死信交换机,惰性队列,MQ集群)
服务异步通信-高级篇 消息队列在使用过程中,面临着很多实际问题需要思考: 1.消息可靠性 消息从发送,到消费者接收,会经历多个过程: 其中的每一步都可能导致消息丢失,常见的丢失原因包括: 发送时丢失: ...
- LLM面面观之RLHF平替算法DPO
1. 背景 最近本qiang~老看到一些关于大语言模型的DPO.RLHF算法,但都有些云里雾里,因此静下心来收集资料.研读论文,并执行了下开源代码,以便加深印象. 此文是本qiang~针对大语言模型的 ...
- C语言中如何使两个整型变量计算出浮点型结果
遭遇的问题 在学习时有一个课后题要求计算两个变量的加减乘除以及取余,想到除法可能会计算出小数,就用浮点型接收除法的结果 int a,b: double div; div = a / b; 但是算出来的 ...
- Collectors.toMap的暗坑与避免方式
使用Java的stream中的Collectors可以很方便地做容器间的转换,可以少写很多代码.但是其中有暗含的坑需要注意和避免,本文探讨Collectors.toMap(JDK8版本). Colle ...
- delphi TThread.WaitFor 用法
在 Delphi 中,TThread.WaitFor 方法用于等待一个线程完成执行.当你创建一个线程并希望主线程(或其他线程)等待这个线程结束时,你可以使用这个方法. 以下是 TThread.Wait ...
- [Java][Spring]spring profile与maven profile多环境管理
spring profile 与 maven profile 多环境管理 spring profile Spring profile是Spring提供的多环境管理方案. 如下图: 每种环境都对应一个y ...
- IIS创建和管理虚拟网站
实验介绍: 本文会详细介绍创建虚拟站点的三种方法 一:IP地址建立站点 1.打开安装了IIS的windows,进入ip配置页面. 添加几个ip,我这里添加的是192.168.1.209,192.168 ...
- NC14402 求最大值
题目链接 题目 题目描述 给出一个序列,你的任务是求每次操作之后序列中 (a[j]-a[i])/(j-i)[1<=i<j<=n]的最大值. 操作次数有Q次,每次操作需要将位子p处的数 ...