stm32库函数学习篇---通用定时器(输入捕获功能)

2019-09-23来源: eefocus关键字:stm32库函数  通用定时器  输入捕获功能

实现功能:PA8随意延时驱动led灯闪烁,并且将PA8用杜邦线连接到PA7口,PA7是通用定时器TIM3的2通道,在TIM3_CH2触发中断程序中取反连接到PD2口的led灯,指示中断程序运行,并且每次进入中断后改变触发捕获的极性。实现两个led灯会交替闪烁。


先有必要了解stm32定时器的输入触发模块,如下图:

需要注意的是,一眼望去一个定时器似乎有8个通道,左边四个,右边四个,但其实左边和右边是共用相同的IO引脚,所以名称标注是一模一样。也就是说,每个通用定时器都只有四个独立通道,当某一通道作为了输入触发功能那就不能再作为输出匹配功能。这一点我们也可以从其他地方找到印证。比如TIM_ITConfig()函数中如下:

image.png

Enables or disables the specified TIM interrupts.

Parameters:

image.png

我们可以看到此函数TIM_IT参数的取值范围如下:


TIM_IT_Update: TIM update Interrupt source


TIM_IT_CC1: TIM Capture Compare 1 Interrupt source


TIM_IT_CC2: TIM Capture Compare 2 Interrupt source


TIM_IT_CC3: TIM Capture Compare 3 Interrupt source


TIM_IT_CC4: TIM Capture Compare 4 Interrupt source


TIM_IT_COM: TIM Commutation Interrupt source


TIM_IT_Trigger: TIM Trigger Interrupt source


TIM_IT_Break: TIM Break Interrupt source


也就是说每个通道的捕获和比较功能是共用一个中断标志。


stm32定时器输入触发功能其实挺简单的,与AVR单片机几乎一样。就是单片机引脚上一旦出现一个有效边沿(可以配置为上升、下降或者上升下降均触发),那么定时器计数器CNT里面的值就会被相应的Capture/Compare X Register保存下来。这里X可以是1,2,3,4任何一个。并且中断标志位被置位。但是此时TIM的计数寄存器CNT却不管这一事件的发生,继续自己的计数。此功能可以用来测量外部信号的脉宽或者是周期。


对于定时器的时基单元TIM_TimeBaseStructure就不作说明了,在我前面的文章有专门介绍。下面就重点讲解输入触发单元TIM_ICInitStructure。


首先看次结构体原型的定义如下:


typedef struct

{

   uint16_t TIM_Channel;      /*!< Specifies the TIM channel.

                                  This parameter can be a value of @ref TIM_Channel */

   uint16_t TIM_ICPolarity;   /*!< Specifies the active edge of the input signal.

                                   This parameter can be a value of @ref TIM_Input_Capture_Polarity */

   uint16_t TIM_ICSelection;  /*!< Specifies the input.

                                  This parameter can be a value of @ref TIM_Input_Capture_Selection */

   uint16_t TIM_ICPrescaler;  /*!< Specifies the Input Capture Prescaler.

                                   This parameter can be a value of @ref TIM_Input_Capture_Prescaler */

  uint16_t TIM_ICFilter;     /*!< Specifies the input capture filter.

                                   This parameter can be a number between 0x0 and 0xF */

} TIM_ICInitTypeDef;

 

它一共有5个成员,5个成员具体作用,我们只要看看3.5版本固件库的说明就清楚了。


uint16_t TIM_ICInitTypeDef::TIM_Channel


Specifies the TIM channel. This parameter can be a value of TIM_Channel


其中TIM_Channel的取值范围如下:


TIM_Channel_1.


TIM_Channel_2


TIM_Channel_3


TIM_Channel_4


uint16_t TIM_ICInitTypeDef::TIM_ICFilter


Specifies the input capture filter. This parameter can be a number between 0x0 and 0xF


说实话这个成员具体作用我没有深入了解,仅仅知道是作为对输入信号的滤波作用,估计是让用户设定用多少个采样时钟来确定最终输入信号,起到滤波作用,避免高频信号干扰,反正不管它了。


uint16_t TIM_ICInitTypeDef::TIM_ICPolarity


Specifies the active edge of the input signal. This parameter can be a value of TIM_Input_Capture_Polarity


这个就是触发边沿的极性选择了,取值范围如下:


TIM_ICPolarity_BothEdge


TIM_ICPolarity_Rising


TIM_ICPolarity_Falling


uint16_t TIM_ICInitTypeDef::TIM_ICPrescaler


Specifies the Input Capture Prescaler. This parameter can be a value of TIM_Input_Capture_Prescaler


这个成员是对外部信号进行分频,也即是设置上图中的Prescaler,可以设置为1/2/4/8分频。


uint16_t TIM_ICInitTypeDef::TIM_ICSelection


Specifies the input. This parameter can be a value of TIM_Input_Capture_Selection


这个成员的作用就必须要对照上面的示意图才能明白。仔细看上面的图,可以发现定时器的4个通道并不是完全独立的,而是1、2一组,3、4一组,同组之间的通道是有联系的。也就是可以出现交叉触发。而TIM_ICSelection就是选择要不要使用交叉来触发,如果不明白可以看固件库的说明文档,如下是此结构体成员的取值范围:


#define TIM_ICSelection_DirectTI   ((uint16_t)0x0001)


TIM Input 1, 2, 3 or 4 is selected to be connected to IC1, IC2, IC3 or IC4, respectively


#define TIM_ICSelection_IndirectTI   ((uint16_t)0x0002)


TIM Input 1, 2, 3 or 4 is selected to be connected to IC2, IC1, IC4 or IC3, respectively.


#define TIM_ICSelection_TRC   ((uint16_t)0x0003)


TIM Input 1, 2, 3 or 4 is selected to be connected to TRC.


也就是说,根据不同的取值,可以讲外部引脚的触发信号连到内部不同的单元,这样就使得单片机更加灵活了。


下面是main.c文件


#include "stm32f10x.h"


 GPIO_InitTypeDef GPIO_InitStructure;


TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;


TIM_ICInitTypeDef  TIM_ICInitStructure;


NVIC_InitTypeDef NVIC_InitStructure;


 void delay()


{


u32 i,j;


for(i=0;i<1000;i++)


for(j=0;j<5000;j++)


;


}


 void rcc_cfg()


{


 ;


}


 void gpio_cfg()


{


  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOA, ENABLE);



  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //随意延时led取反,且将PA8作为触发定时器电平


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;


  GPIO_Init(GPIOA, &GPIO_InitStructure);


 


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;                       //触发中断时,取反PD2


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;


  GPIO_Init(GPIOD, &GPIO_InitStructure);


 


  /* TIM3 channel 2 pin (PA.07) configuration */


   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;


   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;


   GPIO_Init(GPIOA, &GPIO_InitStructure);


}


 


void nvic_cfg()


{


        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);


              /* Enable the TIM3 global Interrupt */


       NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断


       NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级


       NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级


       NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能


       NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器


}


 


void tim3_cfg()


{


  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);


   TIM_DeInit(TIM3);


  TIM_InternalClockConfig(TIM3);


  //预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz


  TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;


  //设置时钟分割


  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;


  //设置计数器模式为向上计数模式


  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;


  //设置计数溢出大小,每计2000个数就产生一个更新事件


  TIM_TimeBaseStructure.TIM_Period = 2000 - 1;


  //将配置应用到TIM2中


  TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);


   //禁止ARR预装载缓冲器


  TIM_ARRPreloadConfig(TIM3, DISABLE);


 


 //下面是对 TIM_ICInitStructure的配置


   TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;


   TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;


   TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;


   TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;    


   TIM_ICInitStructure.TIM_ICFilter = 0x0;       /*选择输入比较滤波器,滤波设置,经历几个周期跳变认定波形稳定0x0~0xF*/


    TIM_ICInit(TIM3, &TIM_ICInitStructure);


 


  //开启TIM2的中断


  TIM_ClearFlag(TIM3, TIM_IT_CC2);


  TIM_ITConfig(TIM3,TIM_IT_CC2,ENABLE);


 


  TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设


}


 


/**


  * @brief  Main program.


  * @param  None


  * @retval None


  */


int main(void)


{


      rcc_cfg();


      gpio_cfg();


      nvic_cfg();


      tim3_cfg();


  while (1)


  {


    /* Set PA8 */


    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);


       delay();


    /* Reset PA8 */


    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);


       delay();


  }


}


 


[1] [2]
关键字:stm32库函数  通用定时器  输入捕获功能 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic475375.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:(STM32)GPIO库函数使用一览
下一篇:STM32的官方库函数调用

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32F4 SPI2初始化及收发数据【使用库函数】
我的STM32F4 Discovery上边有一个加速度传感器LIS302DL。在演示工程中,ST的工程师使用这个传感器做了个很令人羡慕的东西:解算开发板的姿态。当开发板倾斜时候,处于最上边的LED点亮,其他LED不亮。同时,用MicroUSB数据线将开发板连接电脑时,开发板就会虚拟成一个鼠标。倾斜开发板时,鼠标指针会向倾斜的方向移动。归根结底,就是牛B的ST工程师用加速度传感器完成了姿态解算。在开发板上,加速度传感器使用了SPI方式用STM32F4芯片进行通信。STM32F4的SPI1 作为主机,与LIS302Dl进行通信,读取或者写入数据。由于我没有使用过STM32的SPI口,因此在板子的空余资源中找到了SPI2接口来做实验
发表于 2019-10-19
小用stm32f4-CAN控制器(使用库函数)
需要用到哪些函数。这也是一个很重要的学习使用STM32外设的方法,就是阅读每一个库文件的源代码及其介绍。一个经验就是,现在网上STM32的代码和相关资料大部分是针对STM32F10x芯片的,这里使用的F407的寄存器以及库函数与他们有一些不同,如果生搬硬套,首先就可能无法通过编译,提示某些变量或者函数没有定义。即使通过了编译,也很有可能因为某些在F10x中没有的函数没有使用而导致外设无法正常运行。void CAN_Config(){  CAN_GPIO_Init();  CAN_ModeAndFilterInit();}void CAN_GPIO_Init(){  RCC_APB1PeriphClockCm
发表于 2019-09-30
小用stm32f4-CAN控制器(使用库函数)
stm32库函数学习篇----通用定时器(PWM功能)
相等,那么就产生相应的动作。这点和AVR单片机很类似。既然这样,我们要产生需要的PWM信号,就需要设定PWM的频率和PWM的占空比。首先说频率的确定。由于通用定时器的时钟来源是PCLK1,而我又喜欢用固件库的默认设置,那么定时器的时钟频率就这样来确定了,如下:AHB(72MHz)→APB1分频器(默认2)→APB1时钟信号(36MHz)→倍频器(*2倍)→通用定时器时钟信号(72MHz)。这里为什么是这样,在RCC模块学习记录里有详细记载,不多说。因此图中的CK_PSC就是72MHz了。下面的资料也是网上一搜一大把,我就罗列了:STM32的PWM输出有两种模式,模式1(PWM1)和模式2(PWM2),由TIMx_CCMRx寄存器
发表于 2019-09-29
stm32库函数学习篇----通用定时器(PWM功能)
再造STM32---第六部分:自己写库—构建库函数雏形
是兼容的, F1 和 F4 之间的程序移植,只需要小修改即可。而如果要移植用寄存器写的程序,我只想说:“呵呵”。       用库来进行开发,市场已有定论,用户群说明了一切,但对于 STM32 的学习仍然有人认为用寄存器好,而且汇编不是还没退出大学教材么?认为这种方法直观,能够了解到是配置了哪些寄存器,怎样配置寄存器。事实上,库函数的底层实现恰恰是直接配置寄存器方式的最佳例子,它代替我们完成了寄存器配置的工作,而想深入了解芯片是如何工作的话,只要直接查看库函数的最底层实现就能理解,相信你会为它严谨、优美的实现方式而陶醉, 要想修炼 C 语言,就从 ST 的库开始吧。 所以在以后的章节中,使用软件库
发表于 2019-09-29
再造STM32---第六部分:自己写库—构建库函数雏形
STM32F1库函数初始化系列:定时器中断
(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否29   {30       TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除 TIM3 更新中断标志31   }32 }
发表于 2019-09-28
STM32 TIM定时器 库函数学习笔记
一些库函数的用法手册上讲得不甚详细,网上也几乎没有资料,把我个人理解的一些东西和大家分享一下,如有错漏请批评指正。  TIM_DeInit(TIM2); //注意:按缺省值复位后,时钟源为内部时钟,不必再调用函数设置。如需要更改定时器计时的时钟源, //调用后面的那几个相关函数就行。定时器的时钟不是直接来自APB1/2,而是来自于输入为APB1/2的一个倍频器。 //当APB1/2的预分频系数为1时,定时器的时钟频率等于APB1/2的频率; //当APB1/2的预分频系数为其它数值时,定时器的时钟频率等于APB1/2的频率两倍。 TIM_TimeBaseInitTypeDef TIM_TimeBaseSt
发表于 2019-09-28
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved