STM32F407通用定时器输入捕获

发布时间 : 星期二 文章STM32F407通用定时器输入捕获更新完毕开始阅读

10:tDTS= 4 × tCK_INT??

11:保留

-------------------------------------------------------------------------------

最后再来看看捕获/比较寄存器 1:TIMx_CCR1,该寄存器用来存储捕获发生时,TIMx_CNT的值,我们从TIMx_CCR1就可以读出通道1捕获发生时刻的TIMx_CNT值,通过两次捕获(一次上升沿捕获,一次下降沿捕获)的差值,就可以计算出高电平脉冲的宽度(注意,对于脉宽太长的情况,还要计算定时器溢出的次数)。

===================================================================================输入捕获库函数配置:

1)开启TIM5时钟,配置PA0为复用功能(AF2),并开启下拉电阻。

要使用TIM5,我们必须先开启TIM5的时钟。同时我们要捕获TIM5_CH1上面的高电平脉宽,所以先配置PA0为带下拉的复用功能,同时,为了让PA0的复用功能选择连接到TIM5,所以设置PA0的复用功能为AF2,即连接到TIM5上面。 开启 IM5时钟的方法为:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5 时钟使能 当然,这里我们也要开启PA0对应的GPIO的时钟。

配置PA0为复用功能,所以我们首先要设置PA0引脚映射AF2,方法为: GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5);

最后,我们还要初始化GPIO的模式为复用功能,同时这里我们还要设置为开启下拉。方法为: GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度 100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA0

跟上一讲PWM输出类似,这里我们使用的是定时器5的通道 1,所以我们从STM32F4对应的数据手册可以查看到对应的IO口为PA0:

2)初始化TIM5,设置TIM5的ARR和PSC。

在开启了TIM5的时钟之后,我们要设置ARR和PSC两个寄存器的值来设置输入捕获的自动重装载值和计数频率。这在库函数中是通过TIM_TimeBaseInit函数实现的, TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频

TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);//初始化TIM5 3)设置TIM5的输入捕获参数,开启输入捕获。

TIM5_CCMR1寄存器控制着输入捕获1和2的模式,包括映射关系,滤波和分频等。这里我们需要设置通道1为输入模式,且IC1映射到TI1(通道1)上面,并且不使用滤波器(提高响应速度)。库函数是通过TIM_ICInit函数来初始化输入比较参数的:

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct) 同样,我们来看看参数设置结构体TIM_ICInitTypeDef的定义: typedefstruct {

uint16_t TIM_Channel; //通道 uint16_t TIM_ICPolarity; //捕获极性 uint16_t TIM_ICSelection;//映射 uint16_t TIM_ICPrescaler;//分频系数 uint16_t TIM_ICFilter; //滤波器长度 } TIM_ICInitTypeDef;

参数TIM_Channel很好理解,用来设置通道。我们设置为通道1,为TIM_Channel_1。 参数TIM_ICPolarit是用来设置输入信号的有效捕获极性,这里我们设置为TIM_ICPolarity_Rising,上升沿捕获。同时库函数还提供了单独设置通道1捕获极性的函数为: TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);

这表示通道1为上升沿捕获,我们后面会用到,同时对于其他三个通道也有一个类似的函数, 使用的时候一定要分清楚使用的是哪个通道该调用哪个函数,格式为TIM_OCxPolarityConfig()。 参数TIM_ICSelection是用来设置映射关系,我们配置IC1直接映射在TI1上,选择 TIM_ICSelection_DirectTI。

参数TIM_ICPrescaler用来设置输入捕获分频系数,我们这里不分频,所以选中TIM_ICPSC_DIV1,还有2,4,8分频可选。

参数TIM_ICFilter设置滤波器长度,这里我们不使用滤波器,所以设置为0。 我们的配置代码是:

TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端IC1 映射到TI1上 TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获 TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上 TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器不滤波 TIM_ICInit(TIM5, &TIM5_ICInitStructure);

4)使能捕获和更新中断(设置TIM5的DIER寄存器)

因为我们要捕获的是高电平信号的脉宽,所以,第一次捕获是上升沿,第二次捕获时下降沿,必须在捕获上升沿之后,设置捕获边沿为下降沿,同时,如果脉宽比较长,那么定时器就会溢出,对溢出必须做处理,否则结果就不准了,不过,由于STM32F4的TIM5是32位定时器,假设计数周期为1us,那么需要4294秒才会溢出一次,这基本上是不可能的。这两件事,我们都在中断里面做,所以必须开启捕获中断和更新中断。

这里我们使用定时器的开中断函数TIM_ITConfig即可使能捕获和更新中断: TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断和捕获中断 5)设置中断优先级,编写中断服务函数

因为我们要使用到中断,所以我们在系统初始化之后,需要先设置中断优先级分组,这里方法跟我们前面讲解一致,调用NVIC_PriorityGroupConfig()函数即可,我们系统默认设置都是分组2。设置中断优先级的方法前面多次提到这里我们不做讲解,主要是通过函数NVIC_Init()来完成。设置优先级完成后,我们还需要在中断函数里面完成数据处理和捕获设置等关键操作,从而实现高电平脉宽统计。

在中断服务函数里面,跟以前的外部中断和定时器中断实验中一样,

我们在中断开始的时候要进行中断类型判断,在中断结束的时候要清除中断标志位。使用到的

函数在上面的实验已经讲解过,分别为TIM_GetITStatus()函数和TIM_ClearITPendingBit()函数。 if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判断是否为更新中断 if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判断是否发生捕获事件 TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);//清除中断和捕获标志位 在我们实验的中断服务函数中,我们还使用到了一个设置计数器值的函数为: TIM_SetCounter(TIM5,0);

上面语句的意思是将TIM5的计数值设置为0。这个相信是比较好理解的。 6)使能定时器(设置TIM5的CR1寄存器)

最后,必须打开定时器的计数器开关,启动TIM5的计数器,开始输入捕获。 TIM_Cmd(TIM5,ENABLE ); //使能定时器 5

通过以上6步设置,定时器5的通道1就可以开始输入捕获了,同时因为还用到了串口输出结果,所以还需要配置一下串口。

我们在timer.c和timer.h中主要是添加了输入捕获初始化函数TIM5_CH1_Cap_Init 以及中断服务函数 TIM5_IRQHandler。

接下来我们来看看timer.c文件中,我们添加的两个函数的内容: TIM_ICInitTypeDef TIM5_ICInitStructure; //定时器5通道1输入捕获配置

//arr:自动重装值(TIM2,TIM5 是 32 位的!!) psc:时钟预分频数 void TIM5_CH1_Cap_Init(u32 arr,u16 psc) {

GPIO_InitTypeDefGPIO_InitStructure;

TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure; NVIC_InitTypeDefNVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5 时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能 PORTA 时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度 100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA0

GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //PA0 复用位定时器 5

TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频

TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);

TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上 TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获

TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上 TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器不滤波 TIM_ICInit(TIM5, &TIM5_ICInitStructure); //初始化 TIM5 输入捕获参数

TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新和捕获中断 TIM_Cmd(TIM5,ENABLE ); //使能定时器 5

NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级 2 NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;//响应优先级 0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器、 }

//捕获状态

//[7]:0,没有成功的捕获;1,成功捕获到一次. //[6]:0,还没捕获到低电平;1,已经捕获到低电平了.

//[5:0]:捕获低电平后溢出的次数(对于32位定时器来说,1us计数器加1,溢出时间:4294秒) u8 TIM5CH1_CAPTURE_STA=0; //定时器5中断服务程序 void TIM5_IRQHandler(void) {

{

if(TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)//溢出 { }

if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件 {

if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿 {

if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了 { }

if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了 {

TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次 TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;

if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获

//输入捕获状态

u32 TIM5CH1_CAPTURE_VAL; //输入捕获值(TIM2/TIM5是32位)

}else TIM5CH1_CAPTURE_STA++;

TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获到一次高电平脉宽

TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0设为上升沿捕获

TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);//获取当前的捕获值.

联系合同范文客服:xxxxx#qq.com(#替换为@)