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

发布者:TranquilMind最新更新时间:2016-05-25 来源: eefocus关键字:stm32  库函数  通用定时器  输入捕获 手机看文章 扫描二维码
随时随地手机看文章
实现功能:PA8随意延时驱动led灯闪烁,并且将PA8用杜邦线连接到PA7口,PA7是通用定时器TIM3的2通道,在TIM3_CH2触发中断程序中取反连接到PD2口的led灯,指示中断程序运行,并且每次进入中断后改变触发捕获的极性。实现两个led灯会交替闪烁。

 

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

 

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

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

void TIM_ITConfig

(

TIM_TypeDef * 

TIMx,

 

 

uint16_t 

TIM_IT,

 

 

FunctionalState 

NewState 

 

)

 

 

Enables or disables the specified TIM interrupts.

Parameters:

TIMx,:

where x can be 1 to 17 to select the TIMx peripheral.

TIM_IT,:

specifies the TIM interrupts sources to be enabled or disabled. This parameter can be any combination of the following values:

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

我们可以看到此函数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();

  }

}

 

注意定时器3通道2引脚设置为浮空输入。

 

 

 

下面是stm32f10x_it.c文件

 

#include "stm32f10x_it.h"

 u8 flag=0;

extern TIM_ICInitTypeDef  TIM_ICInitStructure;

void TIM3_IRQHandler(void)

{

  if(TIM_GetITStatus(TIM3, TIM_IT_CC2) == SET)

  {

    /* Clear TIM3 Capture compare interrupt pending bit */

    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);

      //每次进入中断就改变捕获触发方式,且翻转PD2的电平

       if(flag==0)

              {

              flag=1;

              TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;

              TIM_ICInit(TIM3, &TIM_ICInitStructure);

              GPIO_WriteBit(GPIOD, GPIO_Pin_2, Bit_RESET);

              }

       else

              {

              flag=0;

              TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;

              TIM_ICInit(TIM3, &TIM_ICInitStructure);

              GPIO_WriteBit(GPIOD, GPIO_Pin_2, Bit_SET);

              }

   }

}

 

程序运行后,可以看到板子上两个led灯交替闪烁。

我并没有对捕获值作任何处理,因为我只是测试程序是否能顺利进入捕获中断。

 

关键字:stm32  库函数  通用定时器  输入捕获 引用地址:stm32库函数学习篇通用定时器输入捕获功能

上一篇:STM32F4——定时器原理及应用中断、输入捕获、PWM输出
下一篇:STM32高级定时器、通用定时器TIMx、基本定时器TIM6和TIM7的区别

推荐阅读最新更新时间:2024-03-16 14:54

【菜鸟入门】stm32 之 DMA
DMA是个好东西,他可以帮助CPU分担好多工作,减轻CPU的工作压力,我们可以一边传输数据,一边干别的事情,很不错! 今天可谓是配置的好艰辛啊,看电视把我看蒙了,好多注意事项都木有看见,浪费了我好多时间。 好吧,开始进入主题! 时钟配置我就不用罗嗦了!大家自己去RCC里面的AHBENR找: RCC- AHBENR |= 1 0;//DAM1 Clock Enable 主要来看看DMAx的控制寄存器CCR 这个寄存器看着很容易理解,今天对控制寄存器有了新的认识,一般的寄存器可能要在控制寄存器的某一位关闭或者打开才能修改,而控制寄存器基本上可以在任意时刻进行修改,所以,在配置控制寄存器的时候我们没必要考
[单片机]
【菜鸟入门】<font color='red'>stm32</font> 之 DMA
STM8|STM32 看门狗使用
STM8和STM32都配备了独立看门狗,其作用之大不言而喻。以下为STM8及STM32的独立看门狗使用例: 对于STM32单片机: #define SYS_IWDG_OPEN IWDG- KR=0xCCCC; #define SYS_IWDG_FEED IWDG- KR=0xAAAA; void SystemIWDG_Config(uint32 OverTime) { RCC- CSR|=RCC_CSR_LSION; while((RCC- CSR&RCC_CSR_LSIRDY)==0); IWDG- KR=0x5555; //使能模块访问 while(IWDG- SR&IWDG_S
[单片机]
stm32的adc总结
在时间应用中对模拟信号的采集非常多,我们经常使用到的是ADC采集,模数转换。stm32自己带有adc采集接口,一些总结如下:
[单片机]
<font color='red'>stm32</font>的adc总结
STM32外部中断解决方法
01 单片机外部中断简介 所谓外部中断,就是通过外部信号所引起的中断,如单片机引脚上的电平变化(高电平、低电平)、边沿变化(上升沿、下降沿)等。51单片机有5个中断源,其中有两个是外部中断,分别为INT0和INT1,INT0被分配在P3.2引脚,INT1被分配在P3.2引脚,也即是说如果使用51单片机的外部中断0,则必须将信号接在P3.2上,否则无效。 02 举例说明什么是中断 单片机在执行程序时有两种方式: 查询方式 中断方式 所谓查询方式就是单片机一遍一遍的扫描,查看所监视的目标有没有发生变化,是一种主动式的监视方法,用一个成语可以很客观的描述:守株待兔。 所谓中断方式就是单片机不主动去监视目标,而是目标主动通知单片机状态
[单片机]
<font color='red'>STM32</font>外部中断解决方法
STM32串口多机通信
从设备采用漏极开路方式级联,从设备的串口TX必须配置为漏极开路,不能是推挽方式,如果配置成推挽方式,会导致灌电流过大,低电平低不下去问题 STM32 的UART数据寄存器是9位,数据传输先传低位(LSB) --实际应用发现9位数据大时候有丢包错包问题?? 利用USART可以进行多机处理器通信,其原理就是使从机处于静默模式,由主机在需要的时候发送指令唤醒从机,并传输数据。STM32静默模式特点:1、所有接收状态位都不会被设置;2、所有的接收中断都被禁止;3、USART_CR1寄存器中的RWU位被置1,RUW可以硬件自动控制或者在某些条件下由软件写。 连接方法很简单,主机的TX输出与从机的RX端口直接相连,从机TX端口要经过与
[单片机]
64脚和小于64脚的STM32进行AD时注意,参照电源处理方法
请注意,ADC_IN17上没有内部基准,将其说成基准电压概念不对。 所以横线以下的理解不对,如果将其做为参考,则其电压假定按1.2V计算,实际测量的数字量是1271~1275,按此推算: 1.2/1275=VDD/4095, 所以VDD=3.85V,很明显供电压换算出来的值与实际3.3V不符,所以不有用其做为参考。 实际上,可以通用ADC_IN1采集某参考源的电压,其它通道按此进行比例换算。 ---------------------------------------------------------------- ADC_IN17是内部参照电压,不是基准电压;它仅仅相当于一个标准电压参照。 STM32的内
[单片机]
配置STM32的PWM输出时没有波形输出的问题
以前在组织代码的时侯都是在初始化系统时钟时就一并初始化了各个外设,如 端口、定时器、串口等, 今天突发奇想,将各外设的初始化放到各外设的模块中去,这样的话没用到的外设就可以不用给时钟,降低能耗。 就这样问题出现了,PWM输出时没有波形输出。 反复检查对比了定时器的功能模块配置、输出IO的设置、RCC配置等,一直没有找到原因。 在准备放弃的时侯,有一搭没一搭的扫代码,突然一看,在设置输出IO代码之前没有给输出IO配置时钟,是在后配置的。 是不是这里的问题呢, 马上试试,果然。 这一记当头棒喝!! :) 所以, 在配置输出IO之前就要先配置IO时钟,谨记之!
[单片机]
RS485通讯中使用STM32串口以DMA方式发送数据丢失字节的问题
1、开发平台 计算机操作系统:WIN7 64位; 开发环境:Keil MDK 5.14; MCU:STM32F407ZET6; STM32F4xx固件库:STM32F4xx_DSP_StdPeriph_Lib_V1.4.0; 串口调试助手; 2、问题描述 在测试用STM32F4xx芯片的串口USART1以DMA方式进行RS485收发通讯时,出现数据字节丢失的现象,一般丢失1~2个字节。 出现问题时测试的简单收发机制:使能串口USART1的DMA收发功能,开启了DMA发送完成中断和USART1空闲中断。通过串口调试助手发送N个字节给MCU,当MCU产生USART1空闲中断时,在USART1空闲中断服务
[单片机]
RS485通讯中使用<font color='red'>STM32</font>串口以DMA方式发送数据丢失字节的问题
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved