tim_time - CSDN
精华内容
参与话题
  • STM32系统学习——TIM(基本定时器)

    万次阅读 多人点赞 2017-12-11 10:22:19
    基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个...

    一、定时器分类
    STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。高级定时器 TIM1/8是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。
    这里写图片描述

    二、功能框图剖析
    这里写图片描述
    基本定时器的核心是时基,通用计时器和高级定时器也有。
    1、时钟源
    定时器时钟TIMxCLK,即内部时钟CK_INT,经APB1预分频器后分频提供,如果APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M 。
    2、计数器时钟
    定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。
    具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)。
    3.计数器
    计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
    4、自动重装载寄存器
    自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
    5. 定时时间的计算
    定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在 CK_CNT 的驱动下,计一个数的时间则是 CK_CLK 的倒数,等于:1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于:1/(CK_CLK * ARR)。如果在中断服务程序里面设置一个变量 time,用来记录中断的次数,那么就可以计算出我们需要的定时时间等于: 1/CK_CLK *(ARR+1)*time。
    三、定时器初始化结构体详解
    在标准库函数头文件stm32f10x_tim.h中对定时器外设建立了四个初始化结构体,基本定时器只用到其中一个即TIM_TimeBaseInitTypeDef,其他三个在高级定时器章节讲解。

     typedef struct {
     uint16_t TIM_Prescaler; // 预分频器
     uint16_t TIM_CounterMode; // 计数模式
     uint32_t TIM_Period; // 定时器周期
     uint16_t TIM_ClockDivision; // 时钟分频
     uint8_t TIM_RepetitionCounter; // 重复计算器
     } TIM_TimeBaseInitTypeDef;

    (1) TIM_Prescaler:定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定TIMx_PSC 寄存器的值。可设置范围为 0 至 65535,实现 1至 65536 分频。
    (2) TIM_CounterMode:定时器计数方式,可是在为向上计数、向下计数以及三种中心对齐模式。基本定时器只能是向上计数,即 TIMx_CNT只能从 0开始递增,并且无需初始化。
    (3) TIM_Period:定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄存器。可设置范围为 0至 65535。
    (4) TIM_ClockDivision:时钟分频,设置定时器时钟 CK_INT 频率与数字滤波器采样时钟频率分频比,基本定时器没有此功能,不用设置。
    (5) TIM_RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出 PWM 的个数。这里不用设置。
    虽然定时器基本初始化结构体有 5 个成员,但对于基本定时器只需设置其中两个就可以。
    四、基本定时器实验
    本实验利用基本定时器 TIM6/7 定时 1s,1s 时间到 LED 翻转一次。基本定时器是单片机内部的资源,没有外部 IO,不需要接外部电路,现只需要一个 LED 即可 。
    软件设计
    编写两个定时器驱动文件,bsp_TiMbase.h 和bsp_TiMbase.h,用来配置定时器中断优先级和和初始化定时器 。

    1、 编程要点
    (1) 开定时器时钟 TIMx_CLK, x[6,7] ;
    (2) 初始化时基初始化结构体 ;
    (3) 使能 TIMx, x[6,7] update 中断;
    (4) 打开定时器;
    (5) 编写中断服务程序
    通用定时器和高级定时器的定时编程要点跟基本定时器差不多,只是还要再选择下计数器的计数模式,是向上还是向下。因为基本定时器只能向上计数,且没有配置计数模式的寄存器,默认是向上。
    2.、软件分析
    基本 定时器宏定义

    1 /********************基本定时器 TIM 参数定义,只限 TIM6、7************/
    2 #define BASIC_TIM6 // 如果使用 TIM7,注释掉这个宏即可
    3 
    4 #ifdef BASIC_TIM6 // 使用基本定时器 TIM6
    5 #define BASIC_TIM TIM6
    6 #define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
    7 #define BASIC_TIM_CLK RCC_APB1Periph_TIM6
    8 #define BASIC_TIM_IRQ TIM6_IRQn
    9 #define BASIC_TIM_IRQHandler TIM6_IRQHandler
    10 
    11 #else // 使用基本定时器 TIM7
    12 #define BASIC_TIM TIM7
    13 #define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
    14 #define BASIC_TIM_CLK RCC_APB1Periph_TIM7
    15 #define BASIC_TIM_IRQ TIM7_IRQn
    16 #define BASIC_TIM_IRQHandler TIM7_IRQHandler
    17 
    18 #endif

    基本定时器有 TIM6 和 TIM7,我们可以有选择的使用,为了提高代码的可移植性,我们把当需要修改定时器时需要修改的代码定义成宏,默认使用的是定时器 6,如果想修改成定时器 7,只需要把宏 BASIC_TIM6 注释掉即可。

    基本定时器设定

    void BASIC_TIM_Config(void)
    2 {
    3 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    4 
    5 // 开启定时器时钟,即内部时钟 CK_INT=72M
    6 BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
    7 
    8 // 自动重装载寄存器周的值(计数值)
    9 TIM_TimeBaseStructure.TIM_Period=1000;
    10 
    11 // 累计 TIM_Period 个频率后产生一个更新或者中断
    12 // 时钟预分频数为 71,则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M
    13 TIM_TimeBaseStructure.TIM_Prescaler= 71;
    14 
    15 // 时钟分频因子 ,基本定时器没有,不用管
    16 //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    17 
    18 // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
    19 //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    20 
    21 // 重复计数器的值,基本定时器没有,不用管
    22 //TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
    23 
    24 // 初始化定时器
    25 TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);
    26 
    27 // 清除计数器中断标志位
    28 TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
    29 
    30 // 开启计数器中断
    31 TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
    32 
    33 // 使能计数器
    34 TIM_Cmd(BASIC_TIM, ENABLE);
    35 
    36 // 暂时关闭定时器的时钟,等待使用
    37 BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, DISABLE)
    38 }

    我们把定时器设置自动重装载寄存器 ARR 的值为 1000,设置时钟预分频器为 71,则驱动计数器的时钟:CK_CNT = CK_INT / (71+1)=1M,则计数器计数一次的时间等于:1/CK_CNT=1us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间为:1/CK_CNT*ARR=1ms。
    在初始化定时器的时候,我们定义了一个结构体:TIM_TimeBaseInitTypeDef,TIM_TimeBaseInitTypeDef 结构体里面有 5 个成员,TIM6 和 TIM7 的寄存器里面只有TIM_Prescaler 和 TIM_Period,另外三个成员基本定时器是没有的,所以使用 TIM6 和TIM7的时候只需初始化这两个成员即可, 另外三个成员是通用定时器和高级定时器才有,具体说明如下:

    1 typedef struct {
    2 TIM_Prescaler // 都有
    3 TIM_CounterMode // TIMx,x[6,7]没有,其他都有
    4 TIM_Period // 都有
    5 TIM_ClockDivision // TIMx,x[6,7]没有,其他都有
    6 TIM_RepetitionCounter // TIMx,x[1,8,15,16,17]才有
    7 } TIM_TimeBaseInitTypeDef;

    定时器中断优先级配置

    1 // 中断优先级配置
    2 void BASIC_TIM_NVIC_Config(void)
    3 {
    4 NVIC_InitTypeDef NVIC_InitStructure;
    5 // 设置中断组为 0
    6 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    7 // 设置中断来源
    8 NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQ ;
    9 // 设置主优先级为 0
    10 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    11 // 设置抢占优先级为 3
    12 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    13 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    14 NVIC_Init(&NVIC_InitStructure);
    15 }

    定时器中断服务程序

    1 void BASIC_TIM_IRQHandler (void)
    2 {
    3 if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ) {
    4 time++;
    5 TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);
    6 }
    7 }

    定时器中断一次的时间是 1ms,我们定义一个全局变量 time,每当进一次中断的时候,让 time 来记录进入中断的次数。如果我们想实现一个 1s 的定时,我们只需要判断time 是否等于 1000 即可,1000 个 1ms 就是 1s。然后把 time 清 0,重新计数,以此循环往复。在中断服务程序的最后,要把相应的中断标志位清除掉,切记。

    主函数

    1 int main(void)
    2 {
    3 /* led 端口配置 */
    4 LED_GPIO_Config();
    5 
    6 /* 基本定时器 TIMx,x[6,7] 定时配置 */
    7 BASIC_TIM_Config();
    8 
    9 /* 配置基本定时器 TIMx,x[6,7]的中断优先级 */
    10 BASIC_TIM_NVIC_Config();
    11 
    12 /* 基本定时器 TIMx,x[6,7] 重新开时钟,开始计时 */
    13 BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
    14 
    15 while (1) {
    16 if ( time == 1000 ) { /* 1000 * 1 ms = 1s 时间到 */
    17 time = 0;
    18 /* LED1 取反 */
    19 LED1_TOGGLE;
    20 }
    21 }
    22 }

    函数做一些必须的初始化,然后在一个死循环中不断的判断 time 的值,time 的值在定时器中断改变,每加一次表示定时器过了 1ms,当 time 等于 1000 时,1s 时间到,LED1翻转一次,并把 time 清 0。

    四、思考
    1. 计算基本定时器一次最长定时时间,如果需要使用基本定时器产生 100s 周期事件有什么办法实现?
    2. 修改实验程序,在保使其每 0.5s 翻转一次 LED1的同时在每 10s 翻转 LED2。

    引用《STM32库开发实战指南》

    展开全文
  • TIM——基本定时器

    2019-06-26 21:58:01
    stm32f1系列,有基本定时器、通用定时器、高级定时器三类TIM定时器。其中,TIM6/7是本文要讲的基本定时器。 基本定时器TIM6/7是16位的只能向上计数的定时器,只能用于定时。而通用定时器和高级定时器有更多的功能,...

     

    stm32f1系列,有基本定时器、通用定时器、高级定时器三类TIM定时器。其中,TIM6/7是本文要讲的基本定时器。

    基本定时器TIM6/7是16位的只能向上计数的定时器,只能用于定时。而通用定时器和高级定时器有更多的功能,如还可以进行输出比较、输入捕捉等功能,相关的介绍会写在后面的文章,这里只讲基本定时器。

    先看看基本定时器的框图,如图24-1。

    图24-1

    时钟源

    我们查阅参考手册RCC章节的时钟树可以知道,RCC的定时器时钟TIMxCLK,即内部时钟CK_INT是由APB1预分频器分频后提供。如图24-2所示,如果APB1预分频系数为1,,则频率不变,否则频率为2倍。即此时用于分频的APB1的预分频系数为2,所以TIMxCLK = 36 * 2 = 72MHz。

    图24-2

    计数器时钟

    如图24-1的框图,计数器时钟由内部时钟CK_INT提供,经过PSC预分频器后得到CK_CNT。PSC是一个16位的预分频器,可以对定时器时钟TIMxCLK进行1~65536之间的任何一个数进行分频。分频后的CK_CNT值的计算在参考手册TIMx_PSC寄存器描述里有提到,如图24-3。

    图24-3

    即CK_CNT = CK_PSC/(PSC[15:0]+1)。

    计数器

    计数器CNT是一个16位的计数器,只能往上计数,最大计数值为65535。

    自动重装载寄存器TIMx_ARR

    TIMx_ARR寄存器里存着最大的计数值,当计数到该值时,会产生中断。当然了你得使能了中断才可以。

    定时时间计算

    计一个数的时间是1/CK_CNT,产生一次中断的时间为(ARR+1)/CK_CNT。如果在中断服务程序里设置一个变量time用于记录中断次数,则定时时间为:(ARR+1)/CK_CNT*time。

     

    TIM_TimeBaseInitTypeDef

    如图24-4为基本定时器TIM_TimeBaseInitTypeDef结构体定义。

    图24-4

    • TIM_Prescaler:指定定时器预分频器数值,由TIMx_PSC寄存器配置,可设置范围为0x0000~0xFFFF,即0~65535;
    • TIM_CounterMode:计数模式,可分为向上计数、向下计数以及三种中心对齐模式。而基本定时器只能向上计数;
    • TIM_Period:计数器周期,即自动重装载寄存器TIMx_ARR的值,在事件生成时更新到影子寄存器,由TIMx_CR1寄存器的ARPE位配置是否使能缓冲;
    • TIM_ClockDivision:时钟分频,配置定时器时钟CK_INT频率与数字滤波器采样时钟频率分频比,基本定时器没有这个功能,不用设置;
    • TIM_RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以很容易控制输出PWM个数,这里不用设置。

     

    定时1s实验

    例如,需要做一个1s的定时,CK_PSC=72MHz,则PSC=71,那么CK_CNT=1MHz,

    • 计一个数时间:1/CK_CNT = 1/1MHz = 1us,
    • 中断一次的时间:(ARR+1)/CK_CNT = (999+1)/1MHz = 1ms,
    • 则定时时间:(ARR+1)/CK_CNT*time = 1ms*1000 = 1s

    我们用led的亮灭状态变化来展示1s的定时。

    初始化TIM_TimeBaseInitTypeDef

    前文提到的TIM_TimeBaseInitTypeDef结构体有5个成员,但基本定时器TIM6/7只用到了TIM_Prescaler和TIM_Period这两个成员,其他三个是通用定时器和高级定时器才会用到的。

    /**
      * @brief  基本定时器配置
      * @param  无
      * @retval 无
      */
    static void BASIC_TIM_Mode_Config(void)
    {
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);   // 内部时钟72MHz
    
        TIM_TimeBaseStructure.TIM_Period = 999;                // 自动重装载寄存器的值	
        TIM_TimeBaseStructure.TIM_Prescaler= 71;               // 预分频器数值
        TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
    
        TIM_ClearFlag(TIM6, TIM_FLAG_Update);                  // 清除计数器中断标志位
        TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
    
        TIM_Cmd(TIM6, ENABLE);	
    }
    

    中断优先级配置

    有关中断配置相关已经在之前的文章介绍过,有不清楚的地方可移步阅读。这里只说几个配置的关键点。可配置中断优先级分组为0,即0位抢占优先级,4位子优先级。配置中断源为TIM6_IRQn。

    /**
      * @brief  中断优先级配置
      * @param  无
      * @retval 无
      */
    static void BASIC_TIM_NVIC_Config(void)
    {
        NVIC_InitTypeDef NVIC_InitStructure; 
    
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		
        NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;	
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    }
    

    中断函数

    中断函数在stm32f10x_it.c文件里配置。

    extern volatile uint32_t time;            // 该变量定义在main()函数里
    
    void TIM6_IRQHandler(void)
    {
        if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) 
        {	
            time++;                           // 每中断一次,time值加1,中断一次时间为1ms,需要中断1000次才可定时1s,即time值为1000
    	TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update);  		 
        }		 	
    }
    

    最后在main()函数里调用led和定时器的初始化配置函数,在一个循环里判断time变量的值是否为1000,如果已经达到1000,则led灯状态变化(亮或灭)一次,并且time变量值重赋为0,以便继续判断及定时。

    转载于:https://www.cnblogs.com/fire909090/p/8890971.html

    展开全文
  • 【STM库应用】stm32 之 TIM (详解一 通用定时器)

    万次阅读 多人点赞 2013-12-09 12:08:22
    STM32的TIM一般有高级定时器TIM1,(TIM8只有在互联性产品有),普通定时器TIM2,TIM3,TIM4,(TIM5,TIM6,TIM7有点设备中没有);今天就只介绍普通定时器,因为高级定时器我还不会!每一个普通定时器都有4路通道! ...

    比赛终于结束了,好几天没有更新了,今天重新开始!进入深入学习TIM!

    定时器,中断这两样东西是学习一个MCU必须掌握的,也是非常有用的!

    STM32的TIM一般有高级定时器TIM1,(TIM8只有在互联性产品有),普通定时器TIM2,TIM3,TIM4,(TIM5,TIM6,TIM7有点设备中没有);今天就只介绍普通定时器,因为高级定时器我还不会!每一个普通定时器都有4路通道!


    我们先看看这个逻辑图吧!我们今天先讨论讨论定时器的问题!我用红色笔标过的路线就是定时器的工作路线,时钟有内部时钟产生,到PSC哪里进行分频处理,然后CNT进行计数,上面还有一个自动重装载寄存器APP。


    这个是分频器的工作原理,我们可以看,分频器设定之前分频系数为1[1],后面的[2][3][4]分频系数为2,分频系数改变后,计数周期也跟着改变了;同时预分频设置生效时,他还会产生一个中断信号,这个中断信号不要管他,一个系统时钟周期后会自动消失,跟I2C的差不多!


    这个是计数过程,上面说过了,计数跟分频后的周期有关;当计数达到装载的数值之后,系统会产生一个三个信号,其中溢出信号和更新事件一个时钟周期后会自动消失,而这时候触发了更新中断标志位UIF,我们可以用这个UPDATE来做定时器的中断标志信号!

    TIM_ITConfig(TIM2, TIM_IT_UPDATE, ENABLE);

    另外还有4个中断,我们知道PWM的产生把,他就跟PWM的产生有着血缘关系!


    如果我们在OC模式选择的时候,TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;选择了Timing那么我们就可以做定时器了。

    有时候我们会发现当UPdate中断信号产生时,其他四个中断信号也产生,什么原因呢?因为我们在设置tim.TIM_Period = period;时,period时间太短,就错觉的以为他们是一群产生中断信号的!来我们分析下:

    假设分频因子为71,即72分频,PCLK为72M,我们设置的周期为1000;那么我们产生定时器的Upddate信号频率为1000Hz,周期为1ms,假设我们这里设置的CCR1 = 100;CCR2 = 500;CCR3 = 600;CCR4 = 900;

    那么update信号产生后0.1ms产生CCR1的中断信号,0.5ms后产生CCR2的中断信号,0.6ms后产生CCR3的中断信号,这些中断标志位是:

    #define TIM_FLAG_Update                    ((uint16_t)0x0001)
    #define TIM_FLAG_CC1                       ((uint16_t)0x0002)
    #define TIM_FLAG_CC2                       ((uint16_t)0x0004)
    #define TIM_FLAG_CC3                       ((uint16_t)0x0008)
    #define TIM_FLAG_CC4                       ((uint16_t)0x0010)
    #define TIM_FLAG_COM                       ((uint16_t)0x0020)
    #define TIM_FLAG_Trigger                   ((uint16_t)0x0040)
    #define TIM_FLAG_Break                     ((uint16_t)0x0080)
    #define TIM_FLAG_CC1OF                     ((uint16_t)0x0200)
    #define TIM_FLAG_CC2OF                     ((uint16_t)0x0400)
    #define TIM_FLAG_CC3OF                     ((uint16_t)0x0800)
    #define TIM_FLAG_CC4OF                     ((uint16_t)0x1000)

    [OF为溢出]后面做研究!

    对于这些CCR1在定时方面的应用我还没有想出什么好的点子,但是他确实存在,如果想验证的话,我们可以把周期设置长一点,比如设置为1s,然后通过设置CCR的值,来看看效果,呵呵,不过这是不容易实现的,因为CCRx 最大为0xffff = 65535跟72M比比,还能说什么?好吧,谁有什么好办法,可以跟我说下!

    void tim_init(u32 period,u32 psc)
    {
    	TIM_TimeBaseInitTypeDef tim;
    	TIM_OCInitTypeDef  TIM_OCInitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    	
    	tim.TIM_Period = period;
      tim.TIM_Prescaler = psc;
      tim.TIM_ClockDivision = 0;
      tim.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInit(TIM2, &tim);
    	
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    	
    	TIM_OCInitStructure.TIM_Pulse = 1*period/4;
      TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);
    	
    	TIM_OCInitStructure.TIM_Pulse = 2*period/4;
      TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    	TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);
    	
    	TIM_OCInitStructure.TIM_Pulse = 3*period/4;
      TIM_OC4Init(TIM2, &TIM_OCInitStructure);
    	TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);
    	
    	TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4, ENABLE);
    	TIM_Cmd(TIM2,ENABLE);
    	
    
      /* Enable the TIM2 global Interrupt */
      NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    
      NVIC_Init(&NVIC_InitStructure);
    }

    void TIM2_IRQHandler(void)
    {
    	static u32 cc2 = 0,cc3 = 0,cc4 = 0,cc5 = 0;
    	static u8 flag2 = 0,flag3 = 0,flag4 = 0,flag5 = 0;
    	u32 capture;
    	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_CC2) == SET)
    	{
    		cc2 ++;
    		if(cc2 > 1000)
    		{
    			flag2 = ~flag2;
    			if(flag2)	led_on(4);
    			else			led_off(4);
    			cc2 = 0;
    		}
    		TIM_ClearFlag(TIM2,TIM_FLAG_CC2);
    		capture = TIM_GetCapture2(TIM2);
        TIM_SetCompare2(TIM2, capture + 255);
    	}
    	
    	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_CC3) == SET)
    	{
    		cc3 ++;
    		if(cc3 > 1000)
    		{
    			flag3 = ~flag3;
    			if(flag3)	led_on(5);
    			else			led_off(5);
    			cc3 = 0;
    		}
    		TIM_ClearFlag(TIM2,TIM_FLAG_CC3);
    		capture = TIM_GetCapture3(TIM2);
        TIM_SetCompare3(TIM2, capture + 500);
    	}
    	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_CC4) == SET)
    	{
    		cc4 ++;
    		if(cc4 > 1000)
    		{
    			flag4 = ~flag4;
    			if(flag4)	led_on(6);
    			else			led_off(6);
    			cc4 = 0;
    		}
    		TIM_ClearFlag(TIM2,TIM_FLAG_CC4);
    		capture = TIM_GetCapture4(TIM2);
        TIM_SetCompare4(TIM2, capture + 725);
    	}
    	
    	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update) == SET)
    	{
    		cc5 ++;
    		if(cc5 > 1000)
    		{
    			flag5 = ~flag5;
    			if(flag5)	led_on(7);
    			else			led_off(7);
    			cc5 = 0;
    		}
    		TIM_ClearFlag(TIM2,TIM_FLAG_Update);
    	}
    }

    蓝桥杯-嵌入式交流群 147520657

    展开全文
  • stm32的TIM定时器HAL库函数的使用

    万次阅读 2019-07-22 10:19:48
    相关具体内容参考 stm32f4xx_hal_time.h 几种模式函数的类型都差不多,包括基本类型(Base),输出比较(OC),输入捕获(IC),pwm(PWM),单脉冲(One_Pulse)和编码器(Encoder)。 /****** xxx使用上述几...HAL_TIM_xxx_Msp...

    相关具体内容参考 stm32f4xx_hal_time.h
    几种模式函数的类型都差不多,包括基本类型(Base),输出比较(OC),输入捕获(IC),pwm(PWM),单脉冲(One_Pulse)和编码器(Encoder)。

    /****** xxx使用上述几种模式的英文替换即可*******/
    HAL_TIM_xxx_Init
    HAL_TIM_xxx_DeInit

    HAL_TIM_xxx_MspInit
    HAL_TIM_xxx_MspDeInit
    /***轮询方式启动/停止/
    HAL_TIM_xxx_Start
    HAL_TIM_xxx_Stop
    /***中断方式启动/停止/
    HAL_TIM_xxx_Start_IT
    HAL_TIM_xxx_Stop_IT
    /****DMA方式启动/停止/
    HAL_TIM_xxx_Start_DMA
    HAL_TIM_xxx_Stop_DMA

    定时器基本函数:

    /* Time Base functions ********************************************************/
    HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_Base_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef htim);
    /
    Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef htim);
    /
    Non-Blocking mode: DMA */
    HAL_StatusTypeDef HAL_TIM_Base_Start_DMA(TIM_HandleTypeDef *htim, uint32_t *pData, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_Base_Stop_DMA(TIM_HandleTypeDef *htim);

    输出比较模式:

    /* Timer Output Compare functions **********************************************/
    HAL_StatusTypeDef HAL_TIM_OC_Init(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_OC_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_OC_MspInit(TIM_HandleTypeDef htim);
    void HAL_TIM_OC_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling 轮询模式
    /

    HAL_StatusTypeDef HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_OC_Stop(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: Interrupt 中断模式 */

    HAL_StatusTypeDef HAL_TIM_OC_Start_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_OC_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: DMA DMA模式
    /

    HAL_StatusTypeDef HAL_TIM_OC_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_OC_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);

    PWM模式:
    /* Timer PWM functions *********************************************************/
    HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_PWM_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_PWM_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: DMA */
    HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_PWM_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);

    输入捕获模式:
    /* Timer Input Capture functions ***********************************************/
    HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_IC_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_IC_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_IC_Stop(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_IC_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: DMA */
    HAL_StatusTypeDef HAL_TIM_IC_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_IC_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);
    单脉冲模式:

    /* Timer One Pulse functions ***************************************************/
    HAL_StatusTypeDef HAL_TIM_OnePulse_Init(TIM_HandleTypeDef *htim, uint32_t OnePulseMode);
    HAL_StatusTypeDef HAL_TIM_OnePulse_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_OnePulse_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_OnePulse_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_OnePulse_Start(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
    HAL_StatusTypeDef HAL_TIM_OnePulse_Stop(TIM_HandleTypeDef *htim, uint32_t OutputChannel);

    /* Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_OnePulse_Start_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
    HAL_StatusTypeDef HAL_TIM_OnePulse_Stop_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel);

    编码器模式

    /* Timer Encoder functions *****************************************************/
    HAL_StatusTypeDef HAL_TIM_Encoder_Init(TIM_HandleTypeDef htim, TIM_Encoder_InitTypeDef sConfig);
    HAL_StatusTypeDef HAL_TIM_Encoder_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_Encoder_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_Encoder_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_Encoder_Stop(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_Encoder_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_Encoder_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: DMA */
    HAL_StatusTypeDef HAL_TIM_Encoder_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData1, uint32_t *pData2, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_Encoder_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);
    中断处理函数:

    /* Interrupt Handler functions **********************************************/
    void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim);

    控制函数:
    /* Control functions *********************************************************/
    HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef htim, TIM_OC_InitTypeDef sConfig, uint32_t Channel);//配置输出比较通道
    HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef htim, TIM_OC_InitTypeDef sConfig, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef htim, TIM_IC_InitTypeDef sConfig, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_OnePulse_ConfigChannel(TIM_HandleTypeDef htim, TIM_OnePulse_InitTypeDef sConfig, uint32_t OutputChannel, uint32_t InputChannel);

    HAL_StatusTypeDef HAL_TIM_ConfigOCrefClear(TIM_HandleTypeDef *htim, TIM_ClearInputConfigTypeDef * sClearInputConfig, uint32_t Channel);
    //时钟源配置函数
    HAL_StatusTypeDef HAL_TIM_ConfigClockSource(TIM_HandleTypeDef *htim, TIM_ClockConfigTypeDef * sClockSourceConfig);

    HAL_StatusTypeDef HAL_TIM_ConfigTI1Input(TIM_HandleTypeDef *htim, uint32_t TI1_Selection);
    HAL_StatusTypeDef HAL_TIM_SlaveConfigSynchronization(TIM_HandleTypeDef *htim, TIM_SlaveConfigTypeDef * sSlaveConfig);
    HAL_StatusTypeDef HAL_TIM_SlaveConfigSynchronization_IT(TIM_HandleTypeDef *htim, TIM_SlaveConfigTypeDef * sSlaveConfig);
    HAL_StatusTypeDef HAL_TIM_DMABurst_WriteStart(TIM_HandleTypeDef *htim, uint32_t BurstBaseAddress, uint32_t BurstRequestSrc, uint32_t *BurstBuffer, uint32_t BurstLength);
    HAL_StatusTypeDef HAL_TIM_DMABurst_WriteStop(TIM_HandleTypeDef *htim, uint32_t BurstRequestSrc);
    HAL_StatusTypeDef HAL_TIM_DMABurst_ReadStart(TIM_HandleTypeDef *htim, uint32_t BurstBaseAddress, uint32_t BurstRequestSrc, uint32_t *BurstBuffer, uint32_t BurstLength);
    HAL_StatusTypeDef HAL_TIM_DMABurst_ReadStop(TIM_HandleTypeDef *htim, uint32_t BurstRequestSrc);

    HAL_StatusTypeDef HAL_TIM_GenerateEvent(TIM_HandleTypeDef *htim, uint32_t EventSource);
    uint32_t HAL_TIM_ReadCapturedValue(TIM_HandleTypeDef *htim, uint32_t Channel);

    回调函数:

    /* Callback in non blocking modes (Interrupt and DMA) *************************/
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);//周期结束时调用。
    void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim); //CCR匹配即翻转时,发生调用。
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);
    void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim);
    void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim);
    void HAL_TIM_ErrorCallback(TIM_HandleTypeDef *htim);

    状态函数:

    /* Peripheral State functions 就是获取相应TIM_HandleTypeDef句柄结构的state成员**************************************************/
    HAL_TIM_StateTypeDef HAL_TIM_Base_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_OC_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_PWM_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_IC_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_OnePulse_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_Encoder_GetState(TIM_HandleTypeDef *htim);
    还有几个宏定义是为了获取和设置计时器相关的寄存器的值(CCR ,CNT,ARR )

    Capture Compare Register(CCR):
    #define __HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE)
    (*(__IO uint32_t *)(&((HANDLE)->Instance->CCR1) + ((CHANNEL) >> 2U)) = (COMPARE))

    #define __HAL_TIM_GET_COMPARE(HANDLE, CHANNEL)
    (*(__IO uint32_t *)(&((HANDLE)->Instance->CCR1) + ((CHANNEL) >> 2U)))
    Counter Register(CNT):
    #define __HAL_TIM_SET_COUNTER(HANDLE, COUNTER) ((HANDLE)->Instance->CNT = (COUNTER))
    #define __HAL_TIM_GET_COUNTER(HANDLE) ((HANDLE)->Instance->CNT)
    Autoreload Register(ARR):
    #define __HAL_TIM_SET_AUTORELOAD(HANDLE, AUTORELOAD)
    do{
    (HANDLE)->Instance->ARR = (AUTORELOAD);
    (HANDLE)->Init.Period = (AUTORELOAD);
    } while(0U)
    #define __HAL_TIM_GET_AUTORELOAD(HANDLE) ((HANDLE)->Instance->ARR)
    TIM Clock Division value:
    #define __HAL_TIM_GET_CLOCKDIVISION(HANDLE) ((HANDLE)->Instance->CR1 & TIM_CR1_CKD)

    #define __HAL_TIM_SET_CLOCKDIVISION(HANDLE, CKD)
    do{
    (HANDLE)->Instance->CR1 &= (uint16_t)(~TIM_CR1_CKD);
    (HANDLE)->Instance->CR1 |= (CKD);
    (HANDLE)->Init.ClockDivision = (CKD);
    } while(0U)
    TIM Input Capture prescaler:

    #define __HAL_TIM_SET_ICPRESCALER(HANDLE, CHANNEL, ICPSC)
    do{
    TIM_RESET_ICPRESCALERVALUE((HANDLE), (CHANNEL));
    TIM_SET_ICPRESCALERVALUE((HANDLE), (CHANNEL), (ICPSC));
    } while(0U)

    #define __HAL_TIM_GET_ICPRESCALER(HANDLE, CHANNEL)
    (((CHANNEL) == TIM_CHANNEL_1) ? ((HANDLE)->Instance->CCMR1 & TIM_CCMR1_IC1PSC) :
    ((CHANNEL) == TIM_CHANNEL_2) ? (((HANDLE)->Instance->CCMR1 & TIM_CCMR1_IC2PSC) >> 8U) :
    ((CHANNEL) == TIM_CHANNEL_3) ? ((HANDLE)->Instance->CCMR2 & TIM_CCMR2_IC3PSC) :
    (((HANDLE)->Instance->CCMR2 & TIM_CCMR2_IC4PSC)) >> 8U)

    具体代码分析:

    一、针对初始化函数 HAL_TIM_xxx_Init():

    对于基本类型(Base),输出比较(OC),输入捕获(IC),pwm(PWM) 四种基本类型,
    HAL_TIM_xxx_Init函数具有相同的函数结构,下面以两个例子说明
    以IC模式的源代码为例:
    HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef htim)
    {
    /
    Check the TIM handle allocation */
    if(htim == NULL)
    {
    return HAL_ERROR;
    }

    /* Check the parameters */
    assert_param(IS_TIM_INSTANCE(htim->Instance));
    assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));

    if(htim->State == HAL_TIM_STATE_RESET)
    {
    /* Allocate lock resource and initialize it /
    htim->Lock = HAL_UNLOCKED;
    /
    Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
    HAL_TIM_XXX_MspInit(htim); //这里有区别
    }

    /* Set the TIM state */
    htim->State= HAL_TIM_STATE_BUSY;

    /* Init the base time for the input capture */
    TIM_Base_SetConfig(htim->Instance, &htim->Init); //重要部分

    /* Initialize the TIM state*/
    htim->State= HAL_TIM_STATE_READY;

    return HAL_OK;
    }
    关键代码步骤说明:
    (1)HAL_TIM_xxx_MspInit(htim)
    (2)将状态设置为BUSY。 htim->State= HAL_TIM_STATE_BUSY;
    (3)TIM_Base_SetConfig(htim->Instance, &htim->Init); //主要函数
    (4)将状态设置为READY。htim->State= HAL_TIM_STATE_READY;

    TIM_Base_SetConfig(htim->Instance, &htim->Init)函数功能:

    (1)设置控制寄存器 CR1(包括计数方向、计数对齐模式、时钟分频三个)
    (2)设置自动重载寄存器 ARR 。// TIMx->ARR = (uint32_t)Structure->Period ;
    (3)设置预分频寄存器 PSC
    (4)设置重复计数器寄存器RCR
    (5)触发更新事件,加载预分频器与重复计数器的值。TIMx->EGR = TIM_EGR_UG;

    单脉冲(One_Pulse)和编码器(Encoder)与上函数具有相似的结构,

    对于单脉冲模式,初始化函数为:
    HAL_StatusTypeDef HAL_TIM_OnePulse_Init(TIM_HandleTypeDef htim, uint32_t OnePulseMode)
    在TIM_Base_SetConfig(htim->Instance, &htim->Init);相对于前面的基本函数,后面还需要加上一步:
    /
    Reset the OPM Bit /
    htim->Instance->CR1 &= ~TIM_CR1_OPM;
    /
    Configure the OPM Mode */
    htim->Instance->CR1 |= OnePulseMode;
    即设置CR1的第三位:
    OPM:单脉冲模式 (One pulse mode)
    0:计数器在发生更新事件时不会停止计数
    1:计数器在发生下一更新事件时停止计数(将CEN位清零)
    函数参数的第二个参数就是为了设置CR1的第三位。
    可以使用的值为:

         #define TIM_OPMODE_SINGLE                    0x00001000U
         #define TIM_OPMODE_REPETITIVE              0x00000000U
    

    对于编码器模式,初始化函数为:
    HAL_StatusTypeDef HAL_TIM_Encoder_Init(TIM_HandleTypeDef htim, TIM_Encoder_InitTypeDef sConfig);
    针对编码器模式,相对于第一种简单的初始化模式,还需要添加以下的初始化代码:
    /1、SMCR的SMS位来选择编码器模式************************/
    /* Reset the SMS bits /
    htim->Instance->SMCR &= ~TIM_SMCR_SMS;
    /
    Get the TIMx SMCR register value /
    tmpsmcr = htim->Instance->SMCR;
    /
    Set the encoder Mode */
    tmpsmcr |= sConfig->EncoderMode;

    /2、通道映射 CC1通道为输入,IC1映射到TI1上C2通道为输入,IC2映射到TI2上/
    /* Get the TIMx CCMR1 register value /
    tmpccmr1 = htim->Instance->CCMR1;
    /
    Select the Capture Compare 1 and the Capture Compare 2 as input */
    tmpccmr1 &= ~(TIM_CCMR1_CC1S | TIM_CCMR1_CC2S); //先清零

    tmpccmr1 |= (sConfig->IC1Selection | (sConfig->IC2Selection << 8U)); //通道映射

    /* 3、设置预分频和滤波 Set the Capture Compare 1 and the Capture Compare 2 prescalers and filters */
    tmpccmr1 &= ~(TIM_CCMR1_IC1PSC | TIM_CCMR1_IC2PSC);
    tmpccmr1 &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_IC2F);//后面6位全部清零

    tmpccmr1 |= sConfig->IC1Prescaler | (sConfig->IC2Prescaler << 8U); //预分频
    tmpccmr1 |= (sConfig->IC1Filter << 4U) | (sConfig->IC2Filter << 12U); //无滤波

    /* 4、Set the TI1 and the TI2 Polarities 设置极性 上升沿触发*/
    /* Get the TIMx CCER register value */
    tmpccer = htim->Instance->CCER;
    tmpccer &= ~(TIM_CCER_CC1P | TIM_CCER_CC2P); //先清零
    tmpccer &= ~(TIM_CCER_CC1NP | TIM_CCER_CC2NP); //先清零

    tmpccer |= sConfig->IC1Polarity | (sConfig->IC2Polarity << 4U);

    /* Write to TIMx SMCR */
    htim->Instance->SMCR = tmpsmcr;

    /* Write to TIMx CCMR1 */
    htim->Instance->CCMR1 = tmpccmr1;

    /* Write to TIMx CCER */
    htim->Instance->CCER = tmpccer;

    寄存器的配置步骤如下:

    (1)SMCR的SMS位来选择编码器模式
    tmpsmcr |= sConfig->EncoderMode;
    (2)通道映射 CC1通道为输入,IC1映射到TI1上 C2通道为输入,IC2映射到TI2上
    tmpccmr1 |= (sConfig->IC1Selection | (sConfig->IC2Selection << 8U));

    (3)设置预分频和滤波
    tmpccmr1 |= sConfig->IC1Prescaler |(sConfig->IC2Prescaler << 8U);//预分频
    tmpccmr1 |= (sConfig->IC1Filter << 4U) | (sConfig->IC2Filter << 12U);//无滤波
    (4)设置触发极性 上升沿触发
    tmpccer |= sConfig->IC1Polarity | (sConfig->IC2Polarity << 4U);
    (6)将配置好的参数写入到寄存器中
    上面参数的参数的传递是使用TIM_Encoder_InitTypeDef结构体(九个参数全部用到)。结构体的具体定义如下:

    typedef struct
    {
    uint32_t EncoderMode; /*!< Specifies the active edge of the input signal.
    This parameter can be a value of @ref TIM_Encoder_Mode */

    uint32_t IC1Polarity; /*!< Specifies the active edge of the input signal.
    This parameter can be a value of @ref TIM_Input_Capture_Polarity */

    uint32_t IC1Selection; /*!< Specifies the input.
    This parameter can be a value of @ref TIM_Input_Capture_Selection */

    uint32_t IC1Prescaler; /*!< Specifies the Input Capture Prescaler.
    This parameter can be a value of @ref TIM_Input_Capture_Prescaler */

    uint32_t IC1Filter; /*!< Specifies the input capture filter.
    This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF */

    uint32_t IC2Polarity; /*!< Specifies the active edge of the input signal.
    This parameter can be a value of @ref TIM_Input_Capture_Polarity */

    uint32_t IC2Selection; /*!< Specifies the input.
    This parameter can be a value of @ref TIM_Input_Capture_Selection */

    uint32_t IC2Prescaler; /*!< Specifies the Input Capture Prescaler.
    This parameter can be a value of @ref TIM_Input_Capture_Prescaler */

    uint32_t IC2Filter; /*!< Specifies the input capture filter.
    This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF */
    } TIM_Encoder_InitTypeDef;
    各种功能的配置只需要按照结构体结构来填充内容,然后调用相应的初始化函数即可。

    二、针对轮询启动函数

    1、对于基本模型,具体代码如下:

    HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef htim)
    {
    /
    Check the parameters */
    assert_param(IS_TIM_INSTANCE(htim->Instance));

    /* Set the TIM state */
    htim->State= HAL_TIM_STATE_BUSY;

    /* Enable the Peripheral */
    __HAL_TIM_ENABLE(htim);

    /* Change the TIM state*/
    htim->State= HAL_TIM_STATE_READY;

    return HAL_OK;
    }

    整个函数的核心代码只有一行 __HAL_TIM_ENABLE(htim);。
    跳转到__HAL_TIM_ENABLE函数的具体实现,可以看到函数其实是一个宏定义:

    #define __HAL_TIM_ENABLE(HANDLE) ((HANDLE)->Instance->CR1|=(TIM_CR1_CEN)) //设置CR1的计数器使能位为1即可。
    函数实现步骤:__HAL_TIM_ENABLE(htim); //计数器使能位为1即可

    2、对于输出比较模式,
    HAL_StatusTypeDef HAL_TIM_OC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)

    TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);

    if(IS_TIM_ADVANCED_INSTANCE(htim->Instance) != RESET)
    {
    /* Enable the main output */
    __HAL_TIM_MOE_ENABLE(htim);
    }
    函数实现步骤:
    (1)使能定时器的输出比较通道。 TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    (2)主输出使能。 __HAL_TIM_MOE_ENABLE(htim);----针对高级计数器TIM1和TIM8。
    (3)计数器使能位为1即可。 __HAL_TIM_ENABLE(htim);
    3、对于PWM模式,启动函数与上相同。

    HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    4、对于输入捕获模式,启动函数比上面少一步。

    HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
    函数实现步骤:
    (1)使能定时器的输入捕获通道。 TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    (2)计数器使能位为1即可。 __HAL_TIM_ENABLE(htim);

    5、对于单脉冲模式,需要使能 两个通道。

    HAL_StatusTypeDef HAL_TIM_OnePulse_Start(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
    模式说明:
    (1)在OPM模式下,可以使用的两个可能的通道是TIM_CHANNEL_1和TIM_CHANNEL_2。
    (2)如果TIM_CHANNEL_1被用作输出,TIM_CHANNEL_2将被用作输入,并且如果TIM_CHANNEL_1被用作输入,则TIM_CHANNEL_2将被用作所有组合的输出,
    (3)应同时使能TIM_CHANNEL_1和TIM_CHANNEL_2,无需启用计数器,硬件会自动启用该计数器。计数器会响应刺激而启动并生成一个脉冲
    函数实现步骤:
    (1)使能通道1。 TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
    (2)使能通道2。 TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);
    (3)使能主输出通道。 __HAL_TIM_MOE_ENABLE(htim);

    6、对于编码器模式,需要根据编码器计数的方式选择使能合适的通道。

    HAL_StatusTypeDef HAL_TIM_Encoder_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    (1)使能输入输出通道。使能一个或者两个都使能。
    TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
    TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);
    (2)计数器使能位为1即可。 __HAL_TIM_ENABLE(htim);

    二、针对中断方式的启动函数

    各种模式的代码与上相同,只不过针对需要使能通道的中断函数,
    对于基本函数,需要使能相应的更新中断;
    对于其他几类模式,需要添加一个switch结构,使能相应通道的比较捕获中断,
    即TIMx_DIER函数的各位置1即可,
    switch (Channel)
    {case TIM_CHANNEL_1:
    {
    /* Enable the TIM Capture/Compare 1 interrupt */
    __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
    }
    break;

    case TIM_CHANNEL_2:
    {
      /* Enable the TIM Capture/Compare 2 interrupt */
      __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC2);
    }
    break;
    
    case TIM_CHANNEL_3:
    {
      /* Enable the TIM Capture/Compare 3 interrupt */
      __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC3);
    }
    break;
    
    case TIM_CHANNEL_4:
    {
      /* Enable the TIM Capture/Compare 4 interrupt */
      __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC4);
    }
    break;
    
    default:
    break;
    

    }
    这里有一个大的前提,就是要在配置定时器的中断。

    /* 配置定时器中断优先级并使能 */
    HAL_NVIC_SetPriority(STEPMOTOR_TIMx_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(STEPMOTOR_TIMx_IRQn);
    在每次发生更新事件就会调用下面的回调函数:

    void HAL_TIM_PeriodEla相关具体内容参考 stm32f4xx_hal_time.h
    几种模式函数的类型都差不多,包括基本类型(Base),输出比较(OC),输入捕获(IC),pwm(PWM),单脉冲(One_Pulse)和编码器(Encoder)。

    /****** xxx使用上述几种模式的英文替换即可*******/
    HAL_TIM_xxx_Init
    HAL_TIM_xxx_DeInit

    HAL_TIM_xxx_MspInit
    HAL_TIM_xxx_MspDeInit
    /***轮询方式启动/停止/
    HAL_TIM_xxx_Start
    HAL_TIM_xxx_Stop
    /***中断方式启动/停止/
    HAL_TIM_xxx_Start_IT
    HAL_TIM_xxx_Stop_IT
    /****DMA方式启动/停止/
    HAL_TIM_xxx_Start_DMA
    HAL_TIM_xxx_Stop_DMA

    定时器基本函数:

    /* Time Base functions ********************************************************/
    HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_Base_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef htim);
    /
    Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef htim);
    /
    Non-Blocking mode: DMA */
    HAL_StatusTypeDef HAL_TIM_Base_Start_DMA(TIM_HandleTypeDef *htim, uint32_t *pData, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_Base_Stop_DMA(TIM_HandleTypeDef *htim);

    输出比较模式:

    /* Timer Output Compare functions **********************************************/
    HAL_StatusTypeDef HAL_TIM_OC_Init(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_OC_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_OC_MspInit(TIM_HandleTypeDef htim);
    void HAL_TIM_OC_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling 轮询模式
    /

    HAL_StatusTypeDef HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_OC_Stop(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: Interrupt 中断模式 */

    HAL_StatusTypeDef HAL_TIM_OC_Start_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_OC_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: DMA DMA模式
    /

    HAL_StatusTypeDef HAL_TIM_OC_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_OC_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);

    PWM模式:
    /* Timer PWM functions *********************************************************/
    HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_PWM_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_PWM_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: DMA */
    HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_PWM_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);

    输入捕获模式:
    /* Timer Input Capture functions ***********************************************/
    HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim);
    HAL_StatusTypeDef HAL_TIM_IC_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_IC_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_IC_Stop(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_IC_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: DMA */
    HAL_StatusTypeDef HAL_TIM_IC_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_IC_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);
    单脉冲模式:

    /* Timer One Pulse functions ***************************************************/
    HAL_StatusTypeDef HAL_TIM_OnePulse_Init(TIM_HandleTypeDef *htim, uint32_t OnePulseMode);
    HAL_StatusTypeDef HAL_TIM_OnePulse_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_OnePulse_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_OnePulse_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_OnePulse_Start(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
    HAL_StatusTypeDef HAL_TIM_OnePulse_Stop(TIM_HandleTypeDef *htim, uint32_t OutputChannel);

    /* Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_OnePulse_Start_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
    HAL_StatusTypeDef HAL_TIM_OnePulse_Stop_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel);

    编码器模式

    /* Timer Encoder functions *****************************************************/
    HAL_StatusTypeDef HAL_TIM_Encoder_Init(TIM_HandleTypeDef htim, TIM_Encoder_InitTypeDef sConfig);
    HAL_StatusTypeDef HAL_TIM_Encoder_DeInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef *htim);
    void HAL_TIM_Encoder_MspDeInit(TIM_HandleTypeDef htim);
    /
    Blocking mode: Polling */
    HAL_StatusTypeDef HAL_TIM_Encoder_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_Encoder_Stop(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: Interrupt */
    HAL_StatusTypeDef HAL_TIM_Encoder_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_Encoder_Stop_IT(TIM_HandleTypeDef htim, uint32_t Channel);
    /
    Non-Blocking mode: DMA */
    HAL_StatusTypeDef HAL_TIM_Encoder_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData1, uint32_t *pData2, uint16_t Length);
    HAL_StatusTypeDef HAL_TIM_Encoder_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);
    中断处理函数:

    /* Interrupt Handler functions **********************************************/
    void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim);

    控制函数:
    /* Control functions *********************************************************/
    HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef htim, TIM_OC_InitTypeDef sConfig, uint32_t Channel);//配置输出比较通道
    HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef htim, TIM_OC_InitTypeDef sConfig, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef htim, TIM_IC_InitTypeDef sConfig, uint32_t Channel);
    HAL_StatusTypeDef HAL_TIM_OnePulse_ConfigChannel(TIM_HandleTypeDef htim, TIM_OnePulse_InitTypeDef sConfig, uint32_t OutputChannel, uint32_t InputChannel);

    HAL_StatusTypeDef HAL_TIM_ConfigOCrefClear(TIM_HandleTypeDef *htim, TIM_ClearInputConfigTypeDef * sClearInputConfig, uint32_t Channel);
    //时钟源配置函数
    HAL_StatusTypeDef HAL_TIM_ConfigClockSource(TIM_HandleTypeDef *htim, TIM_ClockConfigTypeDef * sClockSourceConfig);

    HAL_StatusTypeDef HAL_TIM_ConfigTI1Input(TIM_HandleTypeDef *htim, uint32_t TI1_Selection);
    HAL_StatusTypeDef HAL_TIM_SlaveConfigSynchronization(TIM_HandleTypeDef *htim, TIM_SlaveConfigTypeDef * sSlaveConfig);
    HAL_StatusTypeDef HAL_TIM_SlaveConfigSynchronization_IT(TIM_HandleTypeDef *htim, TIM_SlaveConfigTypeDef * sSlaveConfig);
    HAL_StatusTypeDef HAL_TIM_DMABurst_WriteStart(TIM_HandleTypeDef *htim, uint32_t BurstBaseAddress, uint32_t BurstRequestSrc, uint32_t *BurstBuffer, uint32_t BurstLength);
    HAL_StatusTypeDef HAL_TIM_DMABurst_WriteStop(TIM_HandleTypeDef *htim, uint32_t BurstRequestSrc);
    HAL_StatusTypeDef HAL_TIM_DMABurst_ReadStart(TIM_HandleTypeDef *htim, uint32_t BurstBaseAddress, uint32_t BurstRequestSrc, uint32_t *BurstBuffer, uint32_t BurstLength);
    HAL_StatusTypeDef HAL_TIM_DMABurst_ReadStop(TIM_HandleTypeDef *htim, uint32_t BurstRequestSrc);

    HAL_StatusTypeDef HAL_TIM_GenerateEvent(TIM_HandleTypeDef *htim, uint32_t EventSource);
    uint32_t HAL_TIM_ReadCapturedValue(TIM_HandleTypeDef *htim, uint32_t Channel);

    回调函数:

    /* Callback in non blocking modes (Interrupt and DMA) *************************/
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);//周期结束时调用。
    void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim); //CCR匹配即翻转时,发生调用。
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);
    void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim);
    void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim);
    void HAL_TIM_ErrorCallback(TIM_HandleTypeDef *htim);

    状态函数:

    /* Peripheral State functions 就是获取相应TIM_HandleTypeDef句柄结构的state成员**************************************************/
    HAL_TIM_StateTypeDef HAL_TIM_Base_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_OC_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_PWM_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_IC_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_OnePulse_GetState(TIM_HandleTypeDef *htim);
    HAL_TIM_StateTypeDef HAL_TIM_Encoder_GetState(TIM_HandleTypeDef *htim);
    还有几个宏定义是为了获取和设置计时器相关的寄存器的值(CCR ,CNT,ARR )

    Capture Compare Register(CCR):
    #define __HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE)
    (*(__IO uint32_t *)(&((HANDLE)->Instance->CCR1) + ((CHANNEL) >> 2U)) = (COMPARE))

    #define __HAL_TIM_GET_COMPARE(HANDLE, CHANNEL)
    (*(__IO uint32_t *)(&((HANDLE)->Instance->CCR1) + ((CHANNEL) >> 2U)))
    Counter Register(CNT):
    #define __HAL_TIM_SET_COUNTER(HANDLE, COUNTER) ((HANDLE)->Instance->CNT = (COUNTER))
    #define __HAL_TIM_GET_COUNTER(HANDLE) ((HANDLE)->Instance->CNT)
    Autoreload Register(ARR):
    #define __HAL_TIM_SET_AUTORELOAD(HANDLE, AUTORELOAD)
    do{
    (HANDLE)->Instance->ARR = (AUTORELOAD);
    (HANDLE)->Init.Period = (AUTORELOAD);
    } while(0U)
    #define __HAL_TIM_GET_AUTORELOAD(HANDLE) ((HANDLE)->Instance->ARR)
    TIM Clock Division value:
    #define __HAL_TIM_GET_CLOCKDIVISION(HANDLE) ((HANDLE)->Instance->CR1 & TIM_CR1_CKD)

    #define __HAL_TIM_SET_CLOCKDIVISION(HANDLE, CKD)
                            do{                                                             
                                  (HANDLE)->Instance->CR1 &= (uint16_t)(~TIM_CR1_CKD); 
                                  (HANDLE)->Instance->CR1 |= (CKD);                 
                                  (HANDLE)->Init.ClockDivision = (CKD);             
                              } while(0U)
    TIM Input Capture prescaler:

    #define __HAL_TIM_SET_ICPRESCALER(HANDLE, CHANNEL, ICPSC)
                            do{                                                   
                                  TIM_RESET_ICPRESCALERVALUE((HANDLE), (CHANNEL)); 
                                  TIM_SET_ICPRESCALERVALUE((HANDLE), (CHANNEL), (ICPSC));
                              } while(0U)

    #define __HAL_TIM_GET_ICPRESCALER(HANDLE, CHANNEL
      (((CHANNEL) == TIM_CHANNEL_1) ? ((HANDLE)->Instance->CCMR1 & TIM_CCMR1_IC1PSC) :
       ((CHANNEL) == TIM_CHANNEL_2) ? (((HANDLE)->Instance->CCMR1 & TIM_CCMR1_IC2PSC) >> 8U) :
       ((CHANNEL) == TIM_CHANNEL_3) ? ((HANDLE)->Instance->CCMR2 & TIM_CCMR2_IC3PSC) :
       (((HANDLE)->Instance->CCMR2 & TIM_CCMR2_IC4PSC)) >> 8U)

    具体代码分析:

    一、针对初始化函数  HAL_TIM_xxx_Init():

    对于基本类型(Base),输出比较(OC),输入捕获(IC),pwm(PWM)  四种基本类型,
    HAL_TIM_xxx_Init函数具有相同的函数结构,下面以两个例子说明
    以IC模式的源代码为例:
    HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef htim)
    {
      /
    Check the TIM handle allocation */
      if(htim == NULL)
      {
        return HAL_ERROR;
      }

    /* Check the parameters */
      assert_param(IS_TIM_INSTANCE(htim->Instance));
      assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
      assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));

    if(htim->State == HAL_TIM_STATE_RESET)
      { 
        /* Allocate lock resource and initialize it /
        htim->Lock = HAL_UNLOCKED;
        /
    Init the low level hardware : GPIO, CLOCK, NVIC and DMA /
        HAL_TIM_XXX_MspInit(htim); //这里有区别
      }
      
      /
    Set the TIM state /
      htim->State= HAL_TIM_STATE_BUSY;   
      
      /
    Init the base time for the input capture /  
      TIM_Base_SetConfig(htim->Instance, &htim->Init);  //重要部分
       
      /
    Initialize the TIM state*/
      htim->State= HAL_TIM_STATE_READY;
      
      return HAL_OK;
    }
    关键代码步骤说明:
    (1)HAL_TIM_xxx_MspInit(htim)  
    (2)将状态设置为BUSY。  htim->State= HAL_TIM_STATE_BUSY;
    (3)TIM_Base_SetConfig(htim->Instance, &htim->Init);              //主要函数
    (4)将状态设置为READY。htim->State= HAL_TIM_STATE_READY;

    TIM_Base_SetConfig(htim->Instance, &htim->Init)函数功能:

    (1)设置控制寄存器 CR1(包括计数方向、计数对齐模式、时钟分频三个)
    (2)设置自动重载寄存器 ARR 。// TIMx->ARR = (uint32_t)Structure->Period ;
    (3)设置预分频寄存器 PSC
    (4)设置重复计数器寄存器RCR
    (5)触发更新事件,加载预分频器与重复计数器的值。TIMx->EGR = TIM_EGR_UG;

    单脉冲(One_Pulse)和编码器(Encoder)与上函数具有相似的结构,

    对于单脉冲模式,初始化函数为:
    HAL_StatusTypeDef HAL_TIM_OnePulse_Init(TIM_HandleTypeDef htim, uint32_t OnePulseMode)
    在TIM_Base_SetConfig(htim->Instance, &htim->Init);相对于前面的基本函数,后面还需要加上一步:
    /
    Reset the OPM Bit /
    htim->Instance->CR1 &= ~TIM_CR1_OPM;
    /
    Configure the OPM Mode */
    htim->Instance->CR1 |= OnePulseMode;
    即设置CR1的第三位:
        OPM:单脉冲模式 (One pulse mode)
            0:计数器在发生更新事件时不会停止计数
            1:计数器在发生下一更新事件时停止计数(将CEN位清零)
    函数参数的第二个参数就是为了设置CR1的第三位。
    可以使用的值为:

    #define TIM_OPMODE_SINGLE                    0x00001000U
             #define TIM_OPMODE_REPETITIVE              0x00000000U

    对于编码器模式,初始化函数为:
    HAL_StatusTypeDef HAL_TIM_Encoder_Init(TIM_HandleTypeDef htim,  TIM_Encoder_InitTypeDef sConfig);
    针对编码器模式,相对于第一种简单的初始化模式,还需要添加以下的初始化代码:
    /1、SMCR的SMS位来选择编码器模式************************/
    /* Reset the SMS bits /
    htim->Instance->SMCR &= ~TIM_SMCR_SMS;
    /
    Get the TIMx SMCR register value /
    tmpsmcr = htim->Instance->SMCR;
    /
    Set the encoder Mode */
    tmpsmcr |= sConfig->EncoderMode;

    /2、通道映射 CC1通道为输入,IC1映射到TI1上C2通道为输入,IC2映射到TI2上/
    /* Get the TIMx CCMR1 register value /
    tmpccmr1 = htim->Instance->CCMR1;
    /
    Select the Capture Compare 1 and the Capture Compare 2 as input */
    tmpccmr1 &= ~(TIM_CCMR1_CC1S | TIM_CCMR1_CC2S); //先清零

    tmpccmr1 |= (sConfig->IC1Selection | (sConfig->IC2Selection << 8U)); //通道映射

    /* 3、设置预分频和滤波 Set the Capture Compare 1 and the Capture Compare 2 prescalers and filters */
    tmpccmr1 &= ~(TIM_CCMR1_IC1PSC | TIM_CCMR1_IC2PSC);
    tmpccmr1 &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_IC2F);//后面6位全部清零

    tmpccmr1 |= sConfig->IC1Prescaler | (sConfig->IC2Prescaler << 8U); //预分频
    tmpccmr1 |= (sConfig->IC1Filter << 4U) | (sConfig->IC2Filter << 12U); //无滤波

    /* 4、Set the TI1 and the TI2 Polarities 设置极性 上升沿触发*/
    /* Get the TIMx CCER register value */
    tmpccer = htim->Instance->CCER;
    tmpccer &= ~(TIM_CCER_CC1P | TIM_CCER_CC2P); //先清零
    tmpccer &= ~(TIM_CCER_CC1NP | TIM_CCER_CC2NP); //先清零

    tmpccer |= sConfig->IC1Polarity | (sConfig->IC2Polarity << 4U);

    /* Write to TIMx SMCR */
    htim->Instance->SMCR = tmpsmcr;

    /* Write to TIMx CCMR1 */
    htim->Instance->CCMR1 = tmpccmr1;

    /* Write to TIMx CCER */
    htim->Instance->CCER = tmpccer;

    寄存器的配置步骤如下:

    (1)SMCR的SMS位来选择编码器模式   
                   tmpsmcr |=  sConfig->EncoderMode;
    (2)通道映射    CC1通道为输入,IC1映射到TI1上  C2通道为输入,IC2映射到TI2上 
                   tmpccmr1 |= (sConfig->IC1Selection | (sConfig->IC2Selection << 8U));
                         
    (3)设置预分频和滤波
                   tmpccmr1 |= sConfig->IC1Prescaler |(sConfig->IC2Prescaler << 8U);//预分频
                   tmpccmr1 |= (sConfig->IC1Filter << 4U) | (sConfig->IC2Filter << 12U);//无滤波
    (4)设置触发极性  上升沿触发
                   tmpccer |= sConfig->IC1Polarity | (sConfig->IC2Polarity << 4U);
    (6)将配置好的参数写入到寄存器中
    上面参数的参数的传递是使用TIM_Encoder_InitTypeDef结构体(九个参数全部用到)。结构体的具体定义如下:

    typedef struct
    {
    uint32_t EncoderMode; /*!< Specifies the active edge of the input signal.
    This parameter can be a value of @ref TIM_Encoder_Mode */

    uint32_t IC1Polarity; /*!< Specifies the active edge of the input signal.
    This parameter can be a value of @ref TIM_Input_Capture_Polarity */

    uint32_t IC1Selection; /*!< Specifies the input.
    This parameter can be a value of @ref TIM_Input_Capture_Selection */

    uint32_t IC1Prescaler; /*!< Specifies the Input Capture Prescaler.
    This parameter can be a value of @ref TIM_Input_Capture_Prescaler */

    uint32_t IC1Filter; /*!< Specifies the input capture filter.
    This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF */

    uint32_t IC2Polarity; /*!< Specifies the active edge of the input signal.
    This parameter can be a value of @ref TIM_Input_Capture_Polarity */

    uint32_t IC2Selection; /*!< Specifies the input.
    This parameter can be a value of @ref TIM_Input_Capture_Selection */

    uint32_t IC2Prescaler; /*!< Specifies the Input Capture Prescaler.
    This parameter can be a value of @ref TIM_Input_Capture_Prescaler */

    uint32_t IC2Filter; /*!< Specifies the input capture filter.
    This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF */
    } TIM_Encoder_InitTypeDef;
    各种功能的配置只需要按照结构体结构来填充内容,然后调用相应的初始化函数即可。

    二、针对轮询启动函数

    1、对于基本模型,具体代码如下:

    HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef htim)
    {
    /
    Check the parameters */
    assert_param(IS_TIM_INSTANCE(htim->Instance));

    /* Set the TIM state */
    htim->State= HAL_TIM_STATE_BUSY;

    /* Enable the Peripheral */
    __HAL_TIM_ENABLE(htim);

    /* Change the TIM state*/
    htim->State= HAL_TIM_STATE_READY;

    return HAL_OK;
    }

    整个函数的核心代码只有一行 __HAL_TIM_ENABLE(htim);。  
      跳转到__HAL_TIM_ENABLE函数的具体实现,可以看到函数其实是一个宏定义:

    #define __HAL_TIM_ENABLE(HANDLE) ((HANDLE)->Instance->CR1|=(TIM_CR1_CEN)) //设置CR1的计数器使能位为1即可。
    函数实现步骤:__HAL_TIM_ENABLE(htim);   //计数器使能位为1即可

    2、对于输出比较模式,
    HAL_StatusTypeDef HAL_TIM_OC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)

    TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);

    if(IS_TIM_ADVANCED_INSTANCE(htim->Instance) != RESET)
    {
    /* Enable the main output */
    __HAL_TIM_MOE_ENABLE(htim);
    }
    函数实现步骤:
    (1)使能定时器的输出比较通道。  TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    (2)主输出使能。    __HAL_TIM_MOE_ENABLE(htim);----针对高级计数器TIM1和TIM8。
    (3)计数器使能位为1即可。 __HAL_TIM_ENABLE(htim);   
    3、对于PWM模式,启动函数与上相同。

    HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    4、对于输入捕获模式,启动函数比上面少一步。

    HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
    函数实现步骤:
    (1)使能定时器的输入捕获通道。  TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    (2)计数器使能位为1即可。 __HAL_TIM_ENABLE(htim);

    5、对于单脉冲模式,需要使能 两个通道。

    HAL_StatusTypeDef HAL_TIM_OnePulse_Start(TIM_HandleTypeDef *htim, uint32_t OutputChannel);
    模式说明:
    (1)在OPM模式下,可以使用的两个可能的通道是TIM_CHANNEL_1和TIM_CHANNEL_2。
    (2)如果TIM_CHANNEL_1被用作输出,TIM_CHANNEL_2将被用作输入,并且如果TIM_CHANNEL_1被用作输入,则TIM_CHANNEL_2将被用作所有组合的输出,
    (3)应同时使能TIM_CHANNEL_1和TIM_CHANNEL_2,无需启用计数器,硬件会自动启用该计数器。计数器会响应刺激而启动并生成一个脉冲
    函数实现步骤:
    (1)使能通道1。    TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE); 
    (2)使能通道2。     TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE); 
    (3)使能主输出通道。      __HAL_TIM_MOE_ENABLE(htim);

    6、对于编码器模式,需要根据编码器计数的方式选择使能合适的通道。

    HAL_StatusTypeDef HAL_TIM_Encoder_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
    (1)使能输入输出通道。使能一个或者两个都使能。
        TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
         TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);
    (2)计数器使能位为1即可。 __HAL_TIM_ENABLE(htim);

    二、针对中断方式的启动函数

    各种模式的代码与上相同,只不过针对需要使能通道的中断函数,
        对于基本函数,需要使能相应的更新中断;
        对于其他几类模式,需要添加一个switch结构,使能相应通道的比较捕获中断,
         即TIMx_DIER函数的各位置1即可,
    switch (Channel)
    {case TIM_CHANNEL_1:
    {
    /* Enable the TIM Capture/Compare 1 interrupt */
    __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
    }
    break;

    case TIM_CHANNEL_2:
    {
      /* Enable the TIM Capture/Compare 2 interrupt */
      __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC2);
    }
    break;
    
    case TIM_CHANNEL_3:
    {
      /* Enable the TIM Capture/Compare 3 interrupt */
      __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC3);
    }
    break;
    
    case TIM_CHANNEL_4:
    {
      /* Enable the TIM Capture/Compare 4 interrupt */
      __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC4);
    }
    break;
    
    default:
    break;
    

    }
    这里有一个大的前提,就是要在配置定时器的中断。

    /* 配置定时器中断优先级并使能 */
    HAL_NVIC_SetPriority(STEPMOTOR_TIMx_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(STEPMOTOR_TIMx_IRQn);
    在每次发生更新事件就会调用下面的回调函数:

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
    在每次发生输出翻转是就会调用下面的回调函数:
    void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
    我们可以在中断中对定时器的参数进行实时修改。


    作者:luowei_memory
    来源:CSDN
    原文:https://blog.csdn.net/qq_30567891/article/details/78994480
    版权声明:本文为博主原创文章,转载请附上博文链接!psedCallback(TIM_HandleTypeDef *htim);
    在每次发生输出翻转是就会调用下面的回调函数:
    void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
    我们可以在中断中对定时器的参数进行实时修改。


    作者:luowei_memory
    来源:CSDN
    原文:https://blog.csdn.net/qq_30567891/article/details/78994480
    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  •  二、普通定时器详细介绍TIM2-TIM5 ——> 三、定时器代码实例 一、定时器基本介绍 之前有用过野火的学习板上面讲解很详细,所以直接上野火官方的资料吧,作为学习参考笔记发出来 二...
  • Ubuntu18.04 下安装TIM

    万次阅读 2019-07-20 21:44:19
    转载https://blog.csdn.net/u011469138/article/details/82320761 。 https://blog.csdn.net/u011469138/article/details/823207...
  • TIM的一些配置参数

    千次阅读 2016-08-11 15:07:24
    1、使能TIM时钟  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM*,ENABLE); 2、基础设置  TIM_TimeBaseStructure.TIM_Period 计数值   TIM_TimeBaseStructure.TIM_Pres
  • STM32之TIM1高级定时器

    万次阅读 2017-10-28 11:52:07
    定时器应用之PWM输出 1.1 TIM1_CH1N 与 TIM1_CH1 的区别 在刚准备使用定时器的时候,我看了下原理图,...TIM1是一个完整的电机控制用定时器外设,TIM1_CH1和TIM1_CH1N,用于驱动上下两个功率管。如果Deadtime为0,
  • TIM输出比较的三种模式

    万次阅读 2016-08-13 11:35:52
    TIM输出比较的三种模式 TIMx的输出比较模式是用来控制一个输出波形或者指示何时一段给定的的时间已经到时。 当计数器与捕获/比较寄存器的内容相同时,输出比较功能做如下操作: ● 将输出比较模式(TIMx_CCMRx寄存器...
  • 一、基本概念理解1. 输出比较:打开一个TIMx计数器,再打开TIMx的一路或几路输出比较器(共4路),都配置好以后,计数器开始计数,当计数器里的值和 比较寄存器里的值相等时,产生输出比较中断,在中断中将计数器中...
  • 【STM32】TIM---基本定时器

    千次阅读 多人点赞 2020-10-22 12:11:06
    TIM——基本定时器,基本定时器简介,定时周期的计算,基本定时器实验。定时器计数溢出后,进入定时器中断服务函数,进而实现 LED 状态的翻转。
  • STM32 TIM1 PWM 输出

    万次阅读 2018-01-26 19:51:12
    STM32F103x包含最多两个高级定时器(TIM1和TIM8),每个高级定时器可同时产生多达7路PWM输出,以TIM1为例,有TIM1_CH1和TIM1_CH1N、TIM1_CH2和TIM1_CH2N、TIM1_CH3和TIM1_CH3N、TIM1_CH4。通道1其实有两个输出通道...
  • TIM_Pulse

    万次阅读 2016-08-11 17:43:39
    PWM输出 这是输出部分的传统了。所有的开发板的TIM例子都是一个PWM输出。 时基单元好了,设置一下输出模式,反转时机(TIM_Pulse)。...TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM2也行 TIM_OCI
  • 输出比较模式时的TIM_OCMode_PWM1和TIM_OCMode_PWM2区别

    万次阅读 多人点赞 2017-09-07 09:28:13
    配合结构体成员TIM_OCInitTypeDef.TIM_OCPolarity来一起使用。  现在假定TIM_OCInitTypeDef.TIM_OCPolarity = TIM_OCPolarity_High,则起始波形为高电位。 若TIM_OCInitTypeDef.TIM_OCMode = TIM_OCMode_PWM1时...
  • stm32高级定时器TIM1,更新中断初始化配置和普通定时器差别不大,需要注意的是结构TIM_TimeBaseInitTypeDef中TIM_RepetitionCounter配置问题。TIM_RepetitionCounte是用来配置重复计数,就是重复溢出多少次才给你来...
  • STM32-12路舵机控制

    万次阅读 2018-10-29 12:12:37
    一:材料准备 12个9G舵机、1个STM32单片机 二:程序 3个定时器的配置,每个定时器4个通道的配置(本文使用的是STM32f103vet6): //PWM输出初始化 //arr:自动重装值 //psc:时钟预分频数 ... TIM_T...
  • 学习需要使用linux系统,但是团队沟通很不方便,网上很多都是很老的版本的QQ,而且安装麻烦,安利一个简单粗暴的点击打开链接
  • STM32 多路PWM

    万次阅读 2013-01-30 21:05:17
    #include "pwm.h" #include "led.h" //PWM输出初始化 //arr:自动重装值 //psc:时钟预分频数 void PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_... TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TI
  • 图一 图二 PWM应用非常广泛,但是不同的项目对输出的PWM又有特殊要求,为满足这些要求我们需要更多的实验来验证。接下来讲述图一显示波形的输出方法步骤(图二为异常波形)。...1、初始化配置TIM4_CH3对应管脚的PWM
  • stm32 高级定时器产生PWM

    千次阅读 2017-03-15 19:44:56
    用stm32的高级定时器TIM1和TIM8产生PWM,需要注意: 1.都有TIM1,但只有flash容量大于256K的大容量单片机才有TIM8 2.高级定时器相对于通用定时器,多了TIM_CtrlPWMOutputs(TIM8, ENABLE);  TIM1产生四路PWM...
1 2 3 4 5 ... 20
收藏数 82,173
精华内容 32,869
关键字:

tim