STM32——定时器捕获实验

发布时间:2022-12-01 09:00

学习定时器捕获,手撕正点原子的代码,自己重写定时器中断服务函数,记录一哈心得

注:本笔记针对对定时器捕获有一定了解的人或许能看懂,因为比较懒,对很多相关的基础知识没有阐述,推荐一篇其他大牛写的文章,写的很好很好,我主要最开始看不懂正点原子写的中断服务函数,然后自己写了一个,有相同问题的小伙伴可以看看,希望能给你带来帮助

https://blog.csdn.net/qq_38410730/article/details/80011330

输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6、TIM7,其他的定时器都有输入捕获的功能。下面以一个简单的脉冲输入为例,简单地讲述一下输入捕获用于测量脉冲宽度的工作原理:

STM32——定时器捕获实验_第1张图片

先设置输入捕获为上升沿检测,记录发生上升沿时TIMx_CNT的值。然后配置捕获信号为下降沿捕获,当下降沿到来的时候发生捕获,并记录此时的TIMx_CNT的值。这样,前后两次TIMx_CNT的值之差就是高电平的脉宽。同时根据TIM的计数频率,我们就能知道高电平脉宽的准确时间。

定时器计时时间计算

溢出时间= ((重装载值+1)*(分频值+1))/APB1时钟频率;

使用定时器之前都必须开启定时器时钟,基本定时器属于 APB1总线外设。APB1总线外设时钟=72M。

比如我们把定时器设置自动重装载寄存器 arr 的值为4999,设置时钟预分频器寄存器psc的值为7199,则驱动计数器的时钟:

CK_CNT = APB1Periph/ (7199+1)=72M/7200=10K,则计数器计数一次的时间等于:1/CK_CNT=0.0001s=0.1ms=100us,

当计数器从0计数到4999时,产生一次中断,则中断一次的时间为:100usX5000=0.0001sX5000=0.5s=500ms也就是半秒钟。

定时器捕获的思路还是很简单的,下面我们直接上代码

#include "sys.h"
#include "delay.h"
#include "stdio.h"
#include "usart.h"
/*****************
注意事项:使用printf函数要包含stdio.h头文件
还有串口的初始化,printf函数默认的输出为串口

******************/

u8 catchhigh=0;//高电平捕获标志位,0为没有高电平,1为有高电平
u8 temp=0;//定时器溢出次数
u16 value=0;//捕获结束时定时器的值
u8 successful=0;//捕获完成标志位
void tim5init()
{

	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_ICInitTypeDef TIM_ICInitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;//下拉输入,因为按键接的是3.3V的高电平
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_Period=0xFFFF;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Prescaler=71;
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);
	
	TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
	TIM_ICInitStruct.TIM_ICFilter=0x00;
	TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;
	TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
	TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
	TIM_ICInit(TIM5,&TIM_ICInitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel=TIM5_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
	NVIC_Init(&NVIC_InitStruct);
	TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
	TIM_Cmd(TIM5, ENABLE);
}


int main()
{
	u32 sendvalue=0;//发送的值
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	tim5init();
	delay_init();
	uart_init(115200);
  while(1)
	{
		delay_ms(10);//
		if(successful==1)
		{
		sendvalue=65536*temp+value;//
		printf("low:%d us\r\n",sendvalue);
		successful=0;//清除捕获成功标志位
		}
		
	}


}



void TIM5_IRQHandler()
{
	if((TIM_GetITStatus(TIM5, TIM_IT_CC1)==SET)&&(catchhigh==0))//捕获到上升沿,捕获开始
	{
		value=0;//清零
		temp=0;
		TIM_SetCounter(TIM5,0);//定时器清零
		catchhigh=1;//修改标志位
		TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);//修改触发条件,捕获下降沿	
	}
	
	else if((TIM_GetITStatus(TIM5, TIM_IT_CC1)==SET)&&(catchhigh==1))//捕获到下降沿,捕获结束
	{
		value=TIM_GetCapture1(TIM5);//获取定时器的值
		TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//修改中断触发方式
		successful=1;//标记捕获成功
		catchhigh=0;//标记捕获高电平为0
	}
	
	if((TIM_GetITStatus(TIM5,TIM_IT_Update)==SET)&&(catchhigh==1))//产生溢出
	{
		temp++;//溢出次数加一
	}

	TIM_ClearITPendingBit(TIM5,TIM_IT_Update|TIM_IT_CC1);//清除中断标志位


}

小白一枚,能看到这里的前辈,有什么问题,欢迎指出,让我知道自己的不足之处,学习进步。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号