STM32复习笔记(十六) —— 高级定时器(输入捕获)

STM32复习笔记(十六) —— 高级定时器(输入捕获)

1.配置步骤

1)选择有效输入端, TIMx_CCMRx - CCxS
2)配置输入滤波器, TIMx_CCMRx - ICxF
3)选择有效转换边沿, TIMx_CCER - CCxP
4)配置输入预分频器, TIMx_CCMRx - ICxPS
5)使能捕获, TIMx_CCER - CCxE
6)可允许中断 and DMA, TIMx_DIER - CCxIE and CCxDE

2.本例程软件设计思路

1)配置 TIM1 输入捕获模式, 使用 TIM1_CH1 通道检测输入的脉冲
2)于捕获中断中读取捕获的计数器值, 换算成脉冲宽度后打印输出

3.代码编写

于 main.c 中编写代码

#include "stm32f10x.h"
#include "dr_usart.h"

/* 用于记录进入更新中断次数 */
__IO uint32_t gOverFlowCount = 0;

/* 用于判断上升沿 or 下降沿捕获 */
__IO uint8_t  gCaptureEdge = 0;

/* 用于记录捕获寄存器值 */
__IO uint32_t gCaptureValue = 0;

void TIM1_CH1_GPIO_Config(void)
{
	/* 开启 GPIOA 时钟, TIM1_CH1 对应IO口为 PA8 */
	RCC->APB2ENR |= ((uint16_t)0x01 << 2);
	
	/* 配置 PA8 为上拉/下拉输入 */
	GPIOA->CRH &= ~((uint32_t)0x0F << 0);
	GPIOA->CRH |=  ((uint32_t)0x08 << 0);
	
	/* 初始化引脚为低电平 */
	GPIOA->BRR |= ((uint16_t)0x01 << 8);
}

void TIM1_NVIC_Config(void)
{
	/* 配置 TIM1 优先级 15 */
	NVIC->IP[25] = ((uint8_t)15 << 4);
	NVIC->IP[27] = ((uint8_t)15 << 4);
	
	/* 使能 TIM1 中断 */
	NVIC->ISER[0]|= ((uint32_t)0x01 << 25);
	NVIC->ISER[0]|= ((uint32_t)0x01 << 27);
}

void TIM1_Config(void)
{
	/* 开启 TIM1 时钟, 挂载于 APB2 总线 */
	RCC->APB2ENR |= ((uint32_t)0x01 << 11);
	
	/* 向上计数 */
	TIM1->CR1 &= ~((uint16_t)0x07 << 4);
	
	/* 时钟分频因子 */
	TIM1->CR1 &= ~((uint16_t)0x03 << 8);
	
	/* 重装载值 50000-1, 从0计数到49999, +1溢出 */
	TIM1->ARR = ((uint16_t)49999);
	
	/* 预分频器值 1440-1, 从0计数到1439, +1溢出 */
	TIM1->PSC = ((uint16_t)1439);
	
	/* 重复计数器值 0 */
	TIM1->RCR = ((uint16_t)0);
	
	/* 捕获禁止, 才能写入 CC1S */
	TIM1->CCER &= ~((uint16_t)0x01 << 0);
	
	/* 清除捕获1寄存器 */
	TIM1->CCMR1 &= ~((uint16_t)0xFF << 0);
	
	/* CC1通道配置为输入, IC1映射到TI1上 */
	TIM1->CCMR1 |= ((uint16_t)0x01 << 0);
	
	/** 无输入捕获滤波器
	  * 滤波器以采样频率, 连续采样到N个事件后判定有效, 滤除相对高频信号
	  */
	TIM1->CCMR1 |= ((uint16_t)0x00 << 4);
	
	/* 上升沿捕获 */
	TIM1->CCER &= ~((uint16_t)0x01 << 1);
	
	/* 使能捕获 */
	TIM1->CCER |= ((uint16_t)0x01 << 0);
	
	/* 无预分频器 */
	TIM1->CCMR1 |= ((uint16_t)0x00 << 2);
	
	/* 配置 TIM1 更新中断 and 捕获1中断 */
	TIM1_NVIC_Config();
	
	/* 清除中断标志 */
	TIM1->SR &= ~((uint16_t)0x03 << 0);
	
	/* 开启更新中断 and 捕获1中断 */
	TIM1->DIER |= ((uint16_t)0x03 << 0);	
	
	/* 开始计数 */
	TIM1->CR1 |= ((uint32_t)0x01 << 0);
}

int main(void)
{
	/* --------- (81 = 30 + 51) --------- --------- --------- --------- ------ */
	
	User_Init(); /* 中断优先级分组 (16级抢占优先级) and 配置串口1打印调试信息 */
	
	delay_(1);   /* 粗略延时 (约为ms级), 置于此处, 便于使用时复制调用 */
	
	/* --------- 换行基准 --------- --------- --------- --------- --------- -- */
	
	/* 配置 GPIOA GPIO_Pin_0 */
	TIM1_CH1_GPIO_Config();

	/* 配置 TIM1 */
	TIM1_Config();
	
	while(1);
}

void TIM1_UP_IRQHandler(void)
{
	/* 判断是否产生更新中断 */
	if(0 != (TIM1->SR & ((uint16_t)0x01)))
	{
		/* 定时器计数频率50KHz, 共计数50000次, 1/50KHz * 50000 = 1s 进一次中断 */
		gOverFlowCount++;

		/* 清除更新中断标志 */
		TIM1->SR &= ~((uint16_t)0x01 << 0);
	}
}

void TIM1_CC_IRQHandler(void)
{
	/* 在 IC1 上检测到与所选极性相同的边沿 */
	if(0 != (TIM1->SR & ((uint16_t)0x02)))
	{
		/* 第一次捕获到, 清空计数器 */
		if(0 == gCaptureEdge)
		{
			/* 清0计数器值 */
			TIM1->CNT = ((uint16_t)0);
			
			/* 清空进入更新中断次数 */
			gOverFlowCount = 0;
			
			/* 下降沿捕获 */
			TIM1->CCER |= ((uint16_t)0x01 << 1);
			
			/* 准备第二次捕获 */
			gCaptureEdge = 1;
		}
		else /* 第二次捕获到, 记录捕获寄存器值 */
		{
			/* 记录捕获寄存器值 */
			gCaptureValue = TIM1->CCR1;
			
			/* 建议设置更新中断优先级高于捕获中断, 或使用硬件优先级 */
			
			/* 捕获的脉冲总长度, 计数到(49999+1)进入更新中断 */
			gCaptureValue += (gOverFlowCount * (49999+1));
			
			/* (总长度转化为)时间 = 计数次数 * 计数周期(1/50KHz = 0.00002s = 20us) */
			gCaptureValue *= 20;
			
			/* 串口打印输出脉冲宽度值 (单位: us) */
			printf("The pulse width is %dus.\n", gCaptureValue);
			
			/* 上升沿捕获 */
			TIM1->CCER &= ~((uint16_t)0x01 << 1);
			
			/* 准备下一轮捕获 */
			gCaptureEdge = 0;
		}
		
		/* 清除捕获中断标志 */
		TIM1->SR &= ~((uint16_t)0x02 << 0);
	}
}

点击编译,如无错误可进入仿真界面
SSS16.001
打开串口
STM32复习笔记(十六) —— 高级定时器(输入捕获)_第1张图片
点击运行,并且于 TIM1_CH1 通道对应 IO 口 (PA8) 上施加脉冲
STM32复习笔记(十六) —— 高级定时器(输入捕获)_第2张图片
经验证,程序运行结果与预想一致

你可能感兴趣的:(stm32)