首页 > 其他分享 >STM32标准库通用定时器输入捕获

STM32标准库通用定时器输入捕获

时间:2024-03-11 21:23:21浏览次数:28  
标签:Capture 定时器 捕获 STM32 TIM 输入 通道

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所示:

TIM_Period,即1000TIM_Period,即1000003.3v3.3v00Down_Capture_CntDown_Captu...Up_Capture_CntUp_Capture...tim_cnt1*溢出次数tim_cnt1*溢出次数Up_Capture_CntUp_Capture...Down_Capture_CntDown_Captu...tim_cnt2*溢出次数tim_cnt2*溢出次数Text is not SVG - cannot display

在图中可以看到,当输入捕获通道的信号周期要长于输入捕获的通道时钟周期时,会导致第二次读取的值比第一次读取的值小,如果不使用定时器溢出次数进行辅助运算会导致算出来的是负数。之后第一次读取的值+溢出时间-第二次读取的值,得到的结果就是脉冲宽度,第二次读取的值+溢出时间-第一次读取的值,得到的就是周期中另一部分的宽度。有了这些信息,就可以得到频率、周期和占空比了。

标签:Capture,定时器,捕获,STM32,TIM,输入,通道
From: https://www.cnblogs.com/tqht7h/p/18067071

相关文章

  • STM32移植完FATFS的ROM不够解决方法
    1.移植完FatFs之后会有语言包的支持,在map文件中也可以查看到也就是cc936.c这个文件现在cc936占用ROM大约为175030,在本项目中不需要中文支持所以取消掉即可,取消方法如下第一种方法(通过CubeMX配置的代码)不要使能中文文件名称就好了,记得改这个 第二种方法(库函数或者HAL库没有......
  • 同个线程里,如果线程正在忙过程中,定时器时间到了会被延迟触发吗?
    同个线程里,如果线程正在忙过程中,定时器时间到了会被延迟触发吗?在同一线程中,如果线程正在忙过程中,定时器的触发事件会被延迟,直到线程空闲下来才会被触发。这是因为在QT中,线程和定时器的处理都是通过事件循环来完成的。当线程处于忙碌状态时,事件循环将会被阻塞,直到线程执行完当前的......
  • STM32的3种启动模式
    STM32的3种启动模式STM32启动模式介绍各种模式介绍boot0=0Flashmemory启动方式启动地址:0x08000000是STM32内置的Flash,一般我们使用JTAG或者SWD模式下载程序时,就是下载到这个里面,重启后也直接从这启动程序。基本上都是采用这种模式。boot0=1;boot1=0System......
  • DNA 突变可信度评估升级(支持捕获、扩增子、UMI三种类型 )
    2022-11-2012:09:06星期日目的原先写过DNAgermline变异可信度判定(证据项收集)和DNAgermline变异可信度判定,基于pysam对bam文件的解析,从突变相关的reads收集一些统计指标,再根据各指标人工划分阈值进行评分的增减,从最终得分的高低进而评估突变的可信度。这一年......
  • STM32硬件IIC使用
    概述虽然STM32的硬件IIC据说有设计缺陷,但是经过我的实践,至少STM32F103的硬件IIC是没问题的。这里给出STM32的硬件IIC的使用以及编程思路。1.STM32硬件IIC引脚在这里给出STM32F103的硬件IIC引脚,方便查阅使用2.STM32硬件IIC使用流程STM32的硬件IIC我认为是非常具有借鉴意义的,......
  • Unity3D 多线程定时器的原理与实现详解
    Unity3D提供了丰富的功能和工具,让开发者可以轻松地创建各种类型的游戏。其中,定时器是一个非常重要的功能,在游戏开发中经常会被使用到。Unity3D中并没有提供原生的多线程定时器功能,但我们可以通过一些技巧和方法来实现一个多线程定时器。对啦!这里有个游戏开发交流小组里面聚集了......
  • RT-THREAD的STM32F4系列移植
    RT-Thread:RT-Thread,全称是RealTime-Thread,顾名思义,它是一个嵌入式实时多线程操作系统,基本属性之一是支持多任务,但允许多个任务同时运行并不意味着处理器在同一时刻真的执行了多个任务。事实上,一个处理器核心在某一时刻只能运行一个任务,由于每次对一个任务的执行时间很短、任务......
  • 米尔电子STM32MP135开放式高实时高性能PLC控制器解决方案发布
    前言随着工业数字化进程加速与IT/OT深入融合,不断增加的OT核心数据已经逐步成为工业自动化行业的核心资产,而OT层数据具备高实时、高精度、冗余度高、数据量大等等特点,如何获取更加精准的OT数据对数字化进程起到至关重要的作用,同时随着国内工业控制系统逐步进入中高端应用,更加精准......
  • 揭秘阿里巴巴:如何通过API实时捕获中国市场商品数据
    阿里巴巴提供了丰富的API接口,使得第三方开发者可以实时捕获中国市场商品数据。以下是一些关键步骤和要点,帮助你揭秘如何通过阿里巴巴的API实现这一目标:注册并登录阿里巴巴开放平台:首先,你需要在阿里巴巴开放平台注册一个账号,并登录到开发者中心。这一步是获取API使用权限的基础,......
  • STM32标准库通用定时器计数
    STM32标准库通用定时器计数1.定时器初始化voidTIM2_Init(){ TIM_TimeBaseInitTypeDefTIM2_Initstructure;//定义结构体 NVIC_InitTypeDefNVIC_InitStructure;//定义结构体 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE......