STM32高级定时器-输入捕获脉冲宽度

发布于:2025-08-13 ⋅ 阅读:(17) ⋅ 点赞:(0)

一.高级定时器

高级定时器包含4个寄存器:
1)16位的自动重载寄存器ARR
2)16位的计数器CNT,可向上/向下计数。
3)16位的可编程预分频器PSC,时钟源一般选择内部时钟CK_INT,即来自于芯片内部,等于72MHZ,一般情况下,我们都是使用内部时钟。
4)8位的重复计数器RCR(高级定时器独有,通用定时器没有)。
高级定时器在基本定时器的基础上引入了外部引脚,可以实现输入捕获和输出比较功能

STM32F103ZET6的高级/通用定时器的通道、引脚分布:
在这里插入图片描述

二.时基单元

在这里插入图片描述

1.预分频器PSC

CK_PSC:输入时钟,CK_CNT:输出时钟,CK_CNT用于驱动计数器CNT计数。
PSC可以实现1~65536分频:
f(CK_CNT)=CK_PSC/(PSC+1)

2.计数器CNT

高级控制定时器的计数器有三种计数模式:递增计数模式、递减计数模式、中心对齐计数模式。

  • 递增计数模式:计数器从0开始–>自动重载寄存器ARR的值;计数器生成上溢事件。若禁用重复计数器,马上生成更新事件;若使能重复计数器,每生成一次上溢事件,重复计数器内容减1,直到重复计数器内容为0,生成更新事件。
  • 递减计数模式:计数器从自动重载寄存器ARR值开始->0;计数器生成下溢事件。若禁用重复计数器,马上生成更新事件;若使能重复计数器,计数器每生成一次下溢事件,重复计数器内容减1,直到重复计数器内容为0,生成更新事件。
  • 中心对齐模式:计数器从0开始->ARR-1,生成计数器上溢事件;然后从ARR值开始->1,生成计数器下溢事件。每次发生计数器上溢和下溢事件都会产生更新事件

3.自动重载寄存器ARR

自动重载寄存器 ARR 用来存放与计数器 CNT 比较的值,如果发生上溢或者下溢事件,则递减重复计数器的值。

4.重复计数器RCR

  • 在基本/通用定时器发生上/下溢事件时直接生成更新事件(无重复计数器RCR功能);
  • 高级定时器有重复计数器,在定时器发生上/下溢事件时,递减重复计数器的值;只有当重复计数器为0时才会生成更新事件。发生N+1个上溢或下溢事件(N为RCR的值)时 ,产生更新事件。

三.输入捕获原理

在这里插入图片描述
输入捕获:对输入信号的上升沿、下降沿或者双边沿进行捕获。
当捕获到输入信号的跳变沿,把计数器CNT的值锁存到捕获寄存器CCR中,将前后两次捕获得到的CCR寄存器的值相减,得到脉宽。
特别注意:脉宽的时长超过定时器的周期时,需要记录定时器溢出的所有时间。

1.输入通道:

需要被测量的信号从定时器的外部引脚 TIMx_CH1/2/3/4 进入,通常叫 TI1/2/3/4。

2.输入滤波器和边沿检测器

  • 当输入的信号存在高频干扰的时候,我们需要对输入信号进行滤波,即进行重新采样。
  • 边沿检测器用来设置信号在捕获的时候是什么边沿有效,可以是上升沿,下降沿,或者是双边沿。

3.捕获通道

捕获通道就是图中的 IC1/2/3/4,每个捕获通道都有相对应的捕获寄存器 CCR1/2/3/4,当发生捕获的时候,计数器 CNT 的值就会被锁存到捕获寄存器中。

4.预分频器

ICx 的输出信号会经过一个预分频器,用于决定发生多少个事件时进行一次捕获。如果希望捕获信号的每一个边沿,则不分频

5.捕获寄存器

当发生捕获时(第一次),计数器 CNT 的值会被锁存到捕获寄存器 CCR 中,还会产生 CCxI 中断,相应的中断位 CCxIF(在 SR 寄存器中)会被置位。

四.输入捕获应用-测量脉宽或者频率

在这里插入图片描述

1.测量脉宽:

1)捕获通道ICx出现上升沿,发生第一次捕获,计数器CNT的值锁存到捕获寄存器CCR中,并进入捕获中断
2)中断服务程序中记录一次捕获,并把捕获寄存器的值保存到value1中,设置捕获边沿为下降沿捕获(捕获后面的下降沿)
3)下降沿到来,发生第二次捕获,计数器CNT的值锁存到捕获寄存器CCR中,并进入捕获中断
4)中断服务程序中,把捕获寄存器的值保存到value2中。把捕获边沿设置为上升沿捕获。
利用 value2和 value1 的差值可以算出信号的脉宽

注:如果测量的脉宽时间比较长(超过定时周期),定时器就会发生溢出,溢出的时候会产生更新中断,我们可以在中断里面记录定时器溢出的所有时间

2.测量频率:

1)捕获通道ICx出现上升沿,发生第一次捕获,计数器CNT的值锁存到捕获寄存器CCR中,并进入捕获中断。
2)中断服务程序中记录一次捕获,并把捕获寄存器的值保存到value1中。
3)当出现第二次上升沿时,发生第二次捕获,计数器 CNT的值会再次被锁存到捕获寄存器 CCR 中,并再次进入捕获中断。
4)在捕获中断中,把捕获寄存器的值读取到 value3 中,并清除捕获记录标志。
利用 value3 和 value1 的差值可以算出信号的周期(频率)

五.定时器初始化结构体

1.输入捕获结构体

typedef struct {
	uint16_t TIM_Channel; // 输入通道选择
	uint16_t TIM_ICPolarity; // 输入捕获触发选择
	uint16_t TIM_ICSelection; // 输入捕获选择
	uint16_t TIM_ICPrescaler; // 输入捕获预分频器
	uint16_t TIM_ICFilter; // 输入捕获滤波器
} TIM_ICInitTypeDef;

2.TIM_Channel

捕获通道 ICx 选择,可选 TIM_Channel_1、TIM_Channel_2、TIM_Channel_3 或
TIM_Channel_4 四个通道。

3.TIM_ICPolarity

输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触发.

4.TIM_ICSelection

输入通道选择,捕获通道 ICx 的信号可来自三个输入通道,分别为
TIM_ICSelection_DirectTI、TIM_ICSelection_IndirectTI 或 TIM_ICSelection_TRC

5.TIM_ICPrescaler

输入捕获通道预分频器,如果需要捕获输入信号的每个有效边沿,则设置 1 分频即可。

6.TIM_ICFilter

输入捕获滤波器设置,可选设置 0x0 至 0x0F。一般不使用滤波器,即设置为0。

六.脉宽测量输入捕获

1.源代码:

  • 主函数main.c:
#include "bsp_usartlx.h"
#include "bsp_generaltimer.h"

int main(void)
{	
	//分频因子为72-1  计数器时钟
	uint32_t CNT_CLOCK = 72000000/((72-1)+1);
	//TIM5 初始化
	INIT_NVIC_CONFIG();
	INIT_GPIO_KEY_CONFIG();
	INIT_GENERAL_TIMER_CONFIG();
	
	//串口初始化
	INIT_GPIO_CONFIG();
	INIT_USART_CONFIG();
	
	printf("\r\nTIM5 通用定时器捕获实验\r\n");
	printf("\r\n捕获K1按键按下时高电平脉宽时间\r\n");
	
	while(1)
	{
		if(CAPTURE_STRUCTURE.FLAG_FINISH == 1)
		{
			//获取总计数  重载寄存器的值为0xFFFF
			uint32_t time_count = CAPTURE_STRUCTURE.CAPTURE_COUNT * 0xFFFF + CAPTURE_STRUCTURE.CAPTURE_VALUE;
			
			uint32_t time_value1 = time_count/CNT_CLOCK;
			uint32_t time_value2 = time_count%CNT_CLOCK;
			
			printf("\r\n高电平脉宽时间:%d.%d s\r\n",time_value1,time_value2);
			
			CAPTURE_STRUCTURE.FLAG_FINISH = 0;
		}
	}
}
  • 中断函数:
void TIM5_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM5,TIM_IT_Update) == SET)
	{
		//定时器溢出中断
		TIM_ClearITPendingBit(TIM5,TIM_IT_Update);
		CAPTURE_STRUCTURE.CAPTURE_COUNT++;
	}
	
	if(TIM_GetITStatus(TIM5,TIM_IT_CC1) == SET)
	{
		//捕获中断
		if(CAPTURE_STRUCTURE.FLAG_START == 0)
		{
			CAPTURE_STRUCTURE.CAPTURE_COUNT = 0;
			CAPTURE_STRUCTURE.CAPTURE_VALUE = 0;
			CAPTURE_STRUCTURE.FLAG_START = 1;
			CAPTURE_STRUCTURE.FLAG_FINISH = 0;
			//设置计数寄存器的值为0
			TIM_SetCounter(TIM5,0);
			//设置下降沿捕获
			TIM_OC1PolarityConfig(TIM5,TIM_OCPolarity_Low);
		}
		else
		{
			CAPTURE_STRUCTURE.FLAG_START = 0;
			CAPTURE_STRUCTURE.FLAG_FINISH = 1;
			CAPTURE_STRUCTURE.CAPTURE_VALUE = TIM_GetCapture1(TIM1);//获取捕获寄存器的值
			//设置上升沿捕获
			TIM_OC1PolarityConfig(TIM5,TIM_OCPolarity_High);
		}
		TIM_ClearITPendingBit(TIM5,TIM_IT_CC1);
	}
}
  • 定时器和中断设置
#include "bsp_generaltimer.h"

struct CAPTURE CAPTURE_STRUCTURE = {0,0,0,0};

void INIT_NVIC_CONFIG()
{
	NVIC_InitTypeDef NVIC_InitStructure;
	//设置中断组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	//设置中断源
	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
	//设置主优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	//设置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	
	NVIC_Init(&NVIC_InitStructure);
}

void INIT_GPIO_KEY_CONFIG()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void INIT_GENERAL_TIMER_CONFIG()
{
	//时基结构体初始化
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	//开启定时器时钟,即内部时钟为72MHZ
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 -1;//分频因子
	TIM_TimeBaseInitStructure.TIM_Period = 0xFFFF;//16位自动重载寄存器的值 累计TIM_Period+1个频率 产生一个中断
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);
	
	//输入捕获结构体初始化
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//通道1
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//设置捕获极性,即上升沿捕获  
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//输入通道和捕获通道的映射关系-直连
	TIM_ICInit(TIM5,&TIM_ICInitStructure);
	//清除定时器更新和捕获状态标志位
	TIM_ClearFlag(TIM5,TIM_FLAG_CC1|TIM_FLAG_Update);
	//开启更新和捕获中断
	TIM_ITConfig(TIM5,TIM_IT_CC1|TIM_IT_Update,ENABLE);
	//使能定时器
	TIM_Cmd(TIM5,ENABLE);
}

2.实验现象

在这里插入图片描述
通过串口调试助手,显示按键按下时高电平的脉宽时间。