STM32标准外设库TIM应用SPL篇9


添加库函数

  • 打开 Manage Run-Time Environment
  • 选择Device->StdPeriph Drivers->TIM

定时器分类

分类 定时器 计数器分辨率 计数器类型 捕获/比较通道 互补输出
基本定时器 TIM6 16位 向上 0
基本定时器 TIM7 16位 向上 0
通用定时器 TIM2 16位 向上/向下 4
通用定时器 TIM3 16位 向上/向下 4
通用定时器 TIM4 16位 向上/向下 4
通用定时器 TIM5 16位 向上/向下 4
高级定时器 TIM1 16位 向上/向下 4
高级定时器 TIM8 16位 向上/向下 4

TIM初始化

TIM宏定义

  • my_tim.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#ifndef __MY_TIME_H
#define __MY_TIME_H
#include "stm32f10x.h"

//使用那个定时器就把那个写1
#define BASIC_TIM6 0
#define BASIC_TIM7 0
#define ADVANCE_TIM1 0
#define ADVANCE_TIM8 0
#define GENERAL_TIM2 1
#define GENERAL_TIM3 0
#define GENERAL_TIM4 0
#define GENERAL_TIM5 0

#if  BASIC_TIM6
#define            MY_TIM                   TIM6
#define            MY_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            MY_TIM_CLK               RCC_APB1Periph_TIM6
#define            MY_TIM_Period            1000-1
#define            MY_TIM_Prescaler         72-1
#define            MY_TIM_IRQ               TIM6_IRQn
#define            MY_TIM_IRQHandler        TIM6_IRQHandler
#elif BASIC_TIM7
#define            MY_TIM                   TIM7
#define            MY_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            MY_TIM_CLK               RCC_APB1Periph_TIM7
#define            MY_TIM_Period            1000-1
#define            MY_TIM_Prescaler         72-1
#define            MY_TIM_IRQ               TIM7_IRQn
#define            MY_TIM_IRQHandler        TIM7_IRQHandler
#elif ADVANCE_TIM1
#define            MY_TIM                   TIM1
#define            MY_TIM_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define            MY_TIM_CLK               RCC_APB2Periph_TIM1
#define            MY_TIM_Period            (1000-1)
#define            MY_TIM_Prescaler         72-1
#define            MY_TIM_IRQ               TIM1_UP_IRQn
#define            MY_TIM_IRQHandler        TIM1_UP_IRQHandler

#elif  ADVANCE_TIM8
#define            MY_TIM                   TIM8
#define            MY_TIM_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define            MY_TIM_CLK               RCC_APB2Periph_TIM8
#define            MY_TIM_Period            (1000-1)
#define            MY_TIM_Prescaler         72-1
#define            MY_TIM_IRQ               TIM8_UP_IRQn
#define            MY_TIM_IRQHandler        TIM8_UP_IRQHandler
#elif  GENERAL_TIM2
#define            MY_TIM                   TIM2
#define            MY_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            MY_TIM_CLK               RCC_APB1Periph_TIM2
#define            MY_TIM_Period            (1000-1)
#define            MY_TIM_Prescaler         72-1
#define            MY_TIM_IRQ               TIM2_IRQn
#define            MY_TIM_IRQHandler        TIM2_IRQHandler
#elif  GENERAL_TIM3
#define            MY_TIM                   TIM3
#define            MY_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            MY_TIM_CLK               RCC_APB1Periph_TIM3
#define            MY_TIM_Period            (1000-1)
#define            MY_TIM_Prescaler         72-1
#define            MY_TIM_IRQ               TIM3_IRQn
#define            MY_TIM_IRQHandler        TIM3_IRQHandler

#elif  GENERAL_TIM4
#define            MY_TIM                   TIM4
#define            MY_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            MY_TIM_CLK               RCC_APB1Periph_TIM4
#define            MY_TIM_Period            (1000-1)
#define            MY_TIM_Prescaler         72-1
#define            MY_TIM_IRQ               TIM4_IRQn
#define            MY_TIM_IRQHandler        TIM4_IRQHandler

#elif  GENERAL_TIM5
#define            MY_TIM                   TIM5
#define            MY_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            MY_TIM_CLK               RCC_APB1Periph_TIM5
#define            MY_TIM_Period            (1000-1)
#define            MY_TIM_Prescaler         72-1
#define            MY_TIM_IRQ               TIM5_IRQn
#define            MY_TIM_IRQHandler        TIM5_IRQHandler
#endif
void MY_TIM_Init(void);
#endif

TIM中断配置和初始化设置

  • my_tim.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "my_tim.h"
/**
 * @brief  配置嵌套向量中断控制器NVIC
 * @param  无
 * @retval 无
 */
static void MY_TIM_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    // 设置中断组为0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    // 设置中断来源
    NVIC_InitStructure.NVIC_IRQChannel = MY_TIM_IRQ ;
    // 设置主优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    // 使能中断
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
/**
 * @brief  TIM配置
 *         定时时间TIME=(TIM_Period+1)*(TIM_Prescaler+1)/CLK
 * @param  无
 * @retval 无
 */
static void MY_TIM_Mode_Config(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    // 开启定时器时钟,即内部时钟CK_INT=72M
    MY_TIM_APBxClock_FUN(MY_TIM_CLK, ENABLE);
    // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    TIM_TimeBaseStructure.TIM_Period=MY_TIM_Period;
    // 时钟预分频数
    TIM_TimeBaseStructure.TIM_Prescaler= MY_TIM_Prescaler;
    // 时钟分频因子 ,没用到不用管
    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    // 计数器计数模式,设置为向上计数
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    // 重复计数器的值,没用到不用管
    TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
    // 初始化定时器
    TIM_TimeBaseInit(MY_TIM, &TIM_TimeBaseStructure);
    // 清除计数器中断标志位
    TIM_ClearFlag(MY_TIM, TIM_FLAG_Update);
    // 开启计数器中断
    TIM_ITConfig(MY_TIM,TIM_IT_Update,ENABLE);
    // 使能计数器
    TIM_Cmd(MY_TIM, ENABLE);
}
/**
 * @brief  TIM工作参数配置
 * @param  无
 * @retval 无
 */
void MY_TIM_Init(void)
{
    MY_TIM_NVIC_Config();
    MY_TIM_Mode_Config();
}

TIM结构体分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/** 
  * @brief  TIM Time Base Init structure definition
  * @note   This structure is used with all TIMx except for TIM6 and TIM7.    
  */

typedef struct
{
  uint16_t TIM_Prescaler;         /*!< Specifies the prescaler value used to divide the TIM clock.
                                       This parameter can be a number between 0x0000 and 0xFFFF */

  uint16_t TIM_CounterMode;       /*!< Specifies the counter mode.
                                       This parameter can be a value of @ref TIM_Counter_Mode */

  uint16_t TIM_Period;            /*!< Specifies the period value to be loaded into the active
                                       Auto-Reload Register at the next update event.
                                       This parameter must be a number between 0x0000 and 0xFFFF.  */ 

  uint16_t TIM_ClockDivision;     /*!< Specifies the clock division.
                                      This parameter can be a value of @ref TIM_Clock_Division_CKD */

  uint8_t TIM_RepetitionCounter;  /*!< Specifies the repetition counter value. Each time the RCR downcounter
                                       reaches zero, an update event is generated and counting restarts
                                       from the RCR value (N).
                                       This means in PWM mode that (N+1) corresponds to:
                                          - the number of PWM periods in edge-aligned mode
                                          - the number of half PWM period in center-aligned mode
                                       This parameter must be a number between 0x00 and 0xFF. 
                                       @note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef; 
  • 预分频器TIM_Prescaler

可设置范围为0 至65535,实现1 至65536 分频。

  • 计数模式TIM_CounterMode
1
2
3
4
5
6
7
8
9
/** @defgroup TIM_Counter_Mode 
  * @{
  */

#define TIM_CounterMode_Up                 ((uint16_t)0x0000) //向上计数
#define TIM_CounterMode_Down               ((uint16_t)0x0010) //向下计数
#define TIM_CounterMode_CenterAligned1     ((uint16_t)0x0020) //中心对齐,只在计数器向下计数时被设置
#define TIM_CounterMode_CenterAligned2     ((uint16_t)0x0040) //中心对齐,只在计数器向上计数时被设置
#define TIM_CounterMode_CenterAligned3     ((uint16_t)0x0060) //中心对齐,在计数器向上和向下计数时均被设置
  • 定时器周期TIM_Period

可设置范围为0 至65535,实现1 至65536 计数

  • 时钟分频TIM_ClockDivision

设置定时器时钟CK_INT 频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择1、2、4 分频。

1
2
3
4
5
6
7
/** @defgroup TIM_Clock_Division_CKD 
  * @{
  */

#define TIM_CKD_DIV1                       ((uint16_t)0x0000)
#define TIM_CKD_DIV2                       ((uint16_t)0x0100)
#define TIM_CKD_DIV4                       ((uint16_t)0x0200)
  • 重复计数器TIM_RepetitionCounter

只在高级定时器使用,高级定时器发生上溢或下溢事件是递减重复计数器的值,只有当重复计数器为0 时才会生成更新事

中断函数

添加TIM头文件和变量到stm32f10x_it.c

1
2
#include "my_tim.h"
extern __IO uint32_t time;

添加时间中断函数

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
  * @brief  This function handles TIM interrupt request.
  * @param  None
  * @retval None
  */
void  MY_TIM_IRQHandler (void)
{
	if ( TIM_GetITStatus( MY_TIM, TIM_IT_Update) != RESET ) 
	{	
		time++;
		TIM_ClearITPendingBit(MY_TIM , TIM_FLAG_Update);  		 
	}		 	
}

调试

添加TIM头文件main.c和调用初始化TIM

  • main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include "stm32f10x.h"
#include "my_gpio.h"
#include "my_usart.h"
#include "my_data_queue.h"
#include "my_process_data.h"
#include "my_adc.h"
#include "my_tim.h"
extern __IO uint16_t ADC_ConvertedValue[NOFCHANEL];
Channel ch[2];
float VREF,VSENSE;
float temp;
float adcValue;
__IO uint32_t time = 0; // ms 计时变量
int main(void)
{
    /* LED 端口初始化 */
    LED_GPIO_Config();
    Key_GPIO_Config();
    /* 初始化USART 配置模式为 9600 8-N-1 */
    USART_Config();
    /*初始化接收数据队列*/
    RX_Queue_Init();
    /*初始化ADC*/
    ADCx_Init();
    /*初始化TIM 1ms*/
    MY_TIM_Init();
    printf( "\r\n Print current Temperature  \r\n");
    while (1)
    {
        if ( time >= 1000 ) /* 1000 * 1 ms = 1s 时间到 */
        {
            time = 0;
            /* LED1 取反 */
            LED1_TOGGLE;
            VREF=1.2f*4096/ADC_ConvertedValue[2];
            VSENSE=VREF*ADC_ConvertedValue[1]/4096;
            temp=(1.43f-VSENSE)/4.3+25;
            adcValue=VREF*ADC_ConvertedValue[0]/4096;
            printf( "\r\n The IC current tem= %.2fC\r\n", temp);
            printf( "\r\n The IC current VDDA= %.2fV\r\n", VREF);
            printf( "\r\n The IC current ADC= %.2fV\r\n", adcValue);
        }
        Process_Usart_Data(ch);
        if (Key_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY_ON)
        {
            /*LED1反转*/
            LED1_TOGGLE;
        }

        if (Key_Scan(KEY2_GPIO_PORT, KEY2_GPIO_PIN) == KEY_ON)
        {
            LED2_TOGGLE;
        }
        if(ch[0].state==1&&ch[0].start_up==0)
        {
            ch[0].stop_up=0;
            ch[0].start_up=1;
            LED1(ON);
        }
        if(ch[0].state==2&&ch[0].stop_up==0)
        {
            ch[0].stop_up=1;
            ch[0].start_up=0;
            LED1(OFF);
        }
        if(ch[1].state==1&&ch[1].start_up==0)
        {
            ch[1].stop_up=0;
            ch[1].start_up=1;
            LED2(ON);
        }
        if(ch[1].state==2&&ch[1].stop_up==0)
        {
            ch[1].stop_up=1;
            ch[1].start_up=0;
            LED2(OFF);
        }
    }
}

下载调试

  • 编译之后下载到开发板
  • 连接开发板串口
  • 打开串口助手
  • 可以看到串口每1秒接收到数据,开发板上LED在1s间隔闪烁