STM32:F103/F407定时器主从模式输出精准脉冲个数


项目中需要对步进电机进行较为精准的控制。经过查找资料,可以通过对STM32的定时器采用主从定时器的模式。由主定时器输出方波信号,从定时器对主定时器输出的脉冲进行计数,溢出时触发从定时器的中断服务函数。以此达到控制步进电机转动的圈数的目的。

本文所采用的STM32开发板是正点原子的STM32F103(精英板)、STM32F407(探索者),参考资料多来自正点原子资料下载中心(http://www.openedv.com/docs/index.html)。我依然处于刚入门学习STM32的阶段,程序是在正点原子的例程的基础上修改的。

原理/思路

  • 步进电机:步进电机需要通过步进驱动器进行驱动,STM32通过串口输出一定频率的PWM波信号给步进电机驱动器的脉冲输入引脚(如PU-),输出高低电平给步进电机驱动器的方向控制信号输入引脚(如DR-)。
  • 脉冲数与圈数:我使用的是一般的两相四线步进电机,步距角为1.8°。由此可知,360°/1.8°=200;也就是说,在不细分的情况下,200个脉冲使步进电机转动一圈。如果设置PWM波输出频率为 1kHz,也就使一秒内输出1000个脉冲,相当于步进电机一秒内可以转动5圈。
  • 主从定时器:主定时器输出PWM波脉冲信号,从定时器对主定时器输出的脉冲进行计数。对于STM32,除了基本定时器,高级定时器和通用定时器都可以分别作为主、从定时器,但其中的主从关系要遵循参考手册中所提供的配置。

下图,表74,表78,来自《STM32中文参考手册》P237,P285;适用于STM32F103。

TIM1、TIM8内部触发
TIM2-TIM5内部触发

下图,表72,表79,来自《STM32F4xx中文参考手册》P370,P464;适用于STM32F407。

TIM1、TIM8TIM2-TIM5、TIM9、TIM12

  • 注意:由上表可知,对于STM32F103,最多三组主从定时器;对于STM32F407,最多四组主从定时器。TS值 - ITRx 不能重复使用,定时器也不可重复使用。所以配置要注意选取的定时器的输出I/O,合理分配引脚。

代码实现

  • “主从定时器是高级定时器和通用定时器的组合”,程序上会与“主从定时器都是通用定时器的组合”略有区别。

STM32F103:主要对定时器配置进行展示

  • timer.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
#ifndef __TIMER_H
#define __TIMER_H

#include    "stm32f10x.h"
/* Group A: TIM1 - 主定时器,TIM2 - 从定时器
     TIM1: CH1 - PA8, CH4 - PA11   RCC_APB2Periph_TIM1
   TIM2: RCC_APB1Periph_TIM2
     
     Group B: TIM5 - 主定时器,TIM8 - 从定时器
     TIM5: CH1 - PA0, CH2 - PA1   RCC_APB1Periph_TIM5
   TIM8: RCC_APB2Periph_TIM8
     
     Group C: TIM3 - 主定时器,TIM4 - 从定时器
     TIM3: CH1 - PA6, CH2 - PA7    RCC_APB1Periph_TIM3
   TIM4: RCC_APB1Periph_TIM4   
*/

/*****定时器初始化函数*****/
// Group A
void TIM1_GPIO_Config(uint16_t TIM1_Prescaler, uint16_t TIM1_Period, uint16_t CCR_A, uint16_t DIR_A);
void TIM2_GPIO_Config(u32 PulseNum_A);
void PWM_Output_A(u16 Cycle_A, u32 PulseNum_A, u16 DIR_A);
void TIM2_IRQHandler(void);

// Group B
void TIM5_GPIO_Config(uint16_t TIM5_Prescaler, uint16_t TIM5_Period, uint16_t CCR_B, uint16_t DIR_B);
void TIM8_GPIO_Config(u32 PulseNum_B);
void PWM_Output_B(u16 Cycle_B, u32 PulseNum_B, u16 DIR_B);
void TIM8_UP_IRQHandler(void);

// Group C
void TIM3_GPIO_Config(uint16_t TIM3_Prescaler, uint16_t TIM3_Period, uint16_t CCR_C, uint16_t DIR_C);
void TIM4_GPIO_Config(u32 PulseNum_C);
void PWM_Output_C(u16 Cycle_C, u32 PulseNum_C, u16 DIR_C);
void TIM4_IRQHandler(void);

#endif  /* __TIMER_H */
  • timer.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#include "timer.h"

/*********** Group A ***********/
// 定时器1主模式
void TIM1_GPIO_Config(uint16_t TIM1_Prescaler, uint16_t TIM1_Period, uint16_t CCR_A, uint16_t DIR_A)
{<!-- -->
    GPIO_InitTypeDef    GPIO_InitStructure;
   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE);
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_11;     // TIM1_CH1 - PA8, CH4 - PA11
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
   
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = TIM1_Period - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = TIM1_Prescaler - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;            // 重复计数,一定要 = 0; 高级定时器TIM1,TIM8,这句必须有。
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
   
    TIM_OCInitTypeDef       TIM_OCInitStructure;
    // 设置工作模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                           // PWM1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   // 比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;            // 输出极性
    // PWM通道,TIM1 - 通道1设置函数,50/100,脉冲信号
    TIM_OCInitStructure.TIM_Pulse = CCR_A;                              // 设置待装入捕获寄存器的脉冲值
    TIM_OC1Init( TIM1, &TIM_OCInitStructure);
    TIM_SelectMasterSlaveMode( TIM1, TIM_MasterSlaveMode_Enable);       // 主从模式下,作为主定时器使能
    TIM_SelectOutputTrigger( TIM1, TIM_TRGOSource_Update);      // TIM - EGR寄存器, 定义UG位,产生更新事件
    TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Enable);
    // PWM通道,TIM1 - 通道4设置函数,100/100 or 0/100,方向信号
    TIM_OCInitStructure.TIM_Pulse = DIR_A;                          // 初始化 TIM1-OC4
    TIM_OC4Init( TIM1, &TIM_OCInitStructure);                       // CH4预装载使能,修改
    TIM_OC4PreloadConfig( TIM1, TIM_OCPreload_Enable);
   
    TIM_ARRPreloadConfig(TIM1, ENABLE);             // 预装载使能 
}

//定时器2从模式
void TIM2_GPIO_Config(u32 PulseNum_A)
{<!-- -->
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef    NVIC_InitStructure;
   
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE);
   
    TIM_TimeBaseStructure.TIM_Period = PulseNum_A;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;         // 向上计数
    TIM_TimeBaseInit( TIM2, &TIM_TimeBaseStructure);
   
    TIM_SelectInputTrigger( TIM2, TIM_TS_ITR0);         // TIM1-主,TIM2-从,表中对应 ITR0
    TIM_SelectSlaveMode( TIM2, TIM_SlaveMode_External1);        //主从模式下作为从定时器使能
    TIM_ITConfig( TIM2, TIM_IT_Update, DISABLE);
   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure);
}

// Cycle_A = Preiod_A; PulseNum_A 输出脉冲个数; DIR_A 高/低电平-方向信号
void PWM_Output_A(u16 Cycle_A, u32 PulseNum_A, u16 DIR_A)           // TIM1-主,TIM2-从,输出PWM
{<!-- -->
    TIM2_GPIO_Config(PulseNum_A);
    TIM_Cmd( TIM2, ENABLE);
    TIM_ClearITPendingBit( TIM2, TIM_IT_Update);
    TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE);
    TIM1_GPIO_Config( 72, Cycle_A, Cycle_A / 2, DIR_A);     // 72M / 72 = 1MHz;
    TIM_Cmd( TIM1, ENABLE);
    TIM_CtrlPWMOutputs( TIM1, ENABLE);      // 高级定时器必须有,使能其输出
}

/*********** Group B ***********/
// 定时器5主模式
void TIM5_GPIO_Config(uint16_t TIM5_Prescaler, uint16_t TIM5_Period, uint16_t CCR_B, uint16_t DIR_B)
{<!-- -->
    GPIO_InitTypeDef    GPIO_InitStructure;
    // TIM5通道1\2
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM5, ENABLE);
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;          // TIM5: CH1 - PA0,  CH2 - PA1
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
    // 时钟频率设置
    TIM_TimeBaseStructure.TIM_Period = TIM5_Period - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = TIM5_Prescaler - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM5, &TIM_TimeBaseStructure);
   
    TIM_OCInitTypeDef       TIM_OCInitStructure;
    // 设置工作模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;           // 设置工作模式是PWM,且为PWM1工作模式,TIMx_CNT<TIMx_CCR1时为高电平
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;       // 也就是使能PWM输出到端口                   
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;            // 输出极性
    // PWM通道,TIM5 - 通道1设置函数,50/100,脉冲信号
    TIM_OCInitStructure.TIM_Pulse = CCR_B;                  // 设置待装入捕获寄存器的脉冲值
    TIM_OC1Init( TIM5, &TIM_OCInitStructure);                       // 初始化 TIM5-OC1
    TIM_SelectMasterSlaveMode( TIM5, TIM_MasterSlaveMode_Enable);       // 定时器主从模式使能
    TIM_SelectOutputTrigger( TIM5, TIM_TRGOSource_Update);                      // 选择触发方式:使用更新事件作为触发输出
    TIM_OC1PreloadConfig( TIM5, TIM_OCPreload_Enable);      // CH1预装载使能,修改             
    // PWM通道,TIM5 - 通道2设置函数,100/100 or 0/100,方向信号
    TIM_OCInitStructure.TIM_Pulse = DIR_B;                                  // 初始化 TIM5-OC2
    TIM_OC2Init( TIM5, &TIM_OCInitStructure);                       // CH2预装载使能,修改
    TIM_OC2PreloadConfig( TIM5, TIM_OCPreload_Enable);
   
    TIM_ARRPreloadConfig( TIM5, ENABLE);                    // 使能ARR预装载寄存器
}

//定时器8从模式
void TIM8_GPIO_Config(u32 PulseNum_B)
{<!-- -->
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef    NVIC_InitStructure;
   
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM8, ENABLE);
   
    TIM_TimeBaseStructure.TIM_Period = PulseNum_B;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM8, &TIM_TimeBaseStructure);
   
    TIM_SelectInputTrigger( TIM8, TIM_TS_ITR3);         // TIM5-主,TIM8-从 ITR3
    TIM_SelectSlaveMode( TIM8, TIM_SlaveMode_External1);
    TIM_ITConfig( TIM8, TIM_IT_Update, DISABLE);
   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
    NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure);
}

// Cycle_B = Preiod_B; PulseNum_B 输出脉冲个数; DIR_B 高/低电平-方向信号
void PWM_Output_B(u16 Cycle_B, u32 PulseNum_B, u16 DIR_B)           // TIM5-主,TIM8-从
{<!-- -->
    TIM8_GPIO_Config(PulseNum_B);
    TIM_Cmd( TIM8, ENABLE);
    TIM_ClearITPendingBit( TIM8, TIM_IT_Update);
    TIM_ITConfig( TIM8, TIM_IT_Update, ENABLE);
    TIM5_GPIO_Config( 72, Cycle_B, Cycle_B / 2, DIR_B);
    TIM_Cmd( TIM5, ENABLE);
}

/*********** Group C ***********/
// 定时器3主模式
void TIM3_GPIO_Config(uint16_t TIM3_Prescaler, uint16_t TIM3_Period, uint16_t CCR_C, uint16_t DIR_C)
{<!-- -->
    GPIO_InitTypeDef    GPIO_InitStructure;
    // TIM3通道1\2
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;          // TIM3_CH1 PA6, CH2 - PA7
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
    // 时钟频率设置
    TIM_TimeBaseStructure.TIM_Period = TIM3_Period - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = TIM3_Prescaler - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM3, &TIM_TimeBaseStructure);
   
    TIM_OCInitTypeDef       TIM_OCInitStructure;
    // 设置工作模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;           // 设置工作模式是PWM,且为PWM1工作模式,TIMx_CNT<TIMx_CCR1时为高电平
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;       // 也就是使能PWM输出到端口                   
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;            // 输出极性
    // PWM通道,TIM3 - 通道1设置函数,50/100
    TIM_OCInitStructure.TIM_Pulse = CCR_C ;                 // 设置待装入捕获寄存器的脉冲值
    TIM_OC1Init( TIM3, &TIM_OCInitStructure);                       // 初始化 TIM3-OC1
    TIM_SelectMasterSlaveMode( TIM3, TIM_MasterSlaveMode_Enable);       // 定时器主从模式使能
    TIM_SelectOutputTrigger( TIM3, TIM_TRGOSource_Update);                      // 选择触发方式:使用更新事件作为触发输出
    TIM_OC1PreloadConfig( TIM3, TIM_OCPreload_Enable);      // CH1预装载使能,修改             
    // PWM通道,TIM3 - 通道2设置函数,100/100 or 0/100
    TIM_OCInitStructure.TIM_Pulse = DIR_C;                                  // 初始化 TIM3-OC2
    TIM_OC2Init( TIM3, &TIM_OCInitStructure);                       // CH2预装载使能,修改
    TIM_OC2PreloadConfig( TIM3, TIM_OCPreload_Enable);
   
    TIM_ARRPreloadConfig( TIM3, ENABLE);                    // 使能ARR预装载寄存器
}

// 定时器4从模式
void TIM4_GPIO_Config(u32 PulseNum_C)
{<!-- -->
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef    NVIC_InitStructure;
   
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
   
    TIM_TimeBaseStructure.TIM_Period = PulseNum_C;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM4, &TIM_TimeBaseStructure);
   
    TIM_SelectInputTrigger( TIM4, TIM_TS_ITR2);             // TIM3-主,TIM4-从 ITR2
    TIM_SelectSlaveMode( TIM4,TIM_SlaveMode_External1 );        // 等同 TIM4->SMCR |= 0x07
    TIM_ITConfig( TIM4, TIM_IT_Update, DISABLE);
   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

// Cycle_C = Preiod_C; PulseNum_C 输出脉冲个数; DIR_C 高/低电平-方向信号
void PWM_Output_C(u16 Cycle_C, u32 PulseNum_C, u16 DIR_C)           // TIM3-主,TIM4-从
{<!-- -->
    TIM4_GPIO_Config(PulseNum_C);
    TIM_Cmd( TIM4, ENABLE);
    TIM_ClearITPendingBit( TIM4, TIM_IT_Update);
    TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE);
    TIM3_GPIO_Config(72, Cycle_C, Cycle_C / 2, DIR_C);
    TIM_Cmd( TIM3, ENABLE);
}

// Group A
void TIM2_IRQHandler(void)
{<!-- -->
    if (TIM_GetITStatus( TIM2, TIM_IT_Update) != RESET)
    {<!-- -->
        TIM_ClearITPendingBit( TIM2, TIM_IT_Update);            // 清除中断标志位
        TIM_CtrlPWMOutputs( TIM1, DISABLE);     // 主 输出使能关闭,高级定时器必须有
        TIM_Cmd( TIM1, DISABLE);            // 关闭定时器1
        TIM_Cmd( TIM2, DISABLE);            // 关闭定时器2
        TIM_ITConfig( TIM2, TIM_IT_Update, DISABLE);
    }
}

// Group B
void TIM8_UP_IRQHandler(void)
{<!-- -->
    if (TIM_GetITStatus( TIM8, TIM_IT_Update) != RESET)
    {<!-- -->
        TIM_ClearITPendingBit( TIM8, TIM_IT_Update);            // 清除中断标志位
        TIM_Cmd( TIM5, DISABLE);            // 关闭定时器5
        TIM_Cmd( TIM8, DISABLE);            // 关闭定时器8
        TIM_ITConfig( TIM8, TIM_IT_Update, DISABLE);
    }
}

// Group C
void TIM4_IRQHandler(void)
{<!-- -->
    if (TIM_GetITStatus( TIM4, TIM_IT_Update) != RESET)
    {<!-- -->
        TIM_ClearITPendingBit( TIM4, TIM_IT_Update);            // 清除中断标志位
        TIM_Cmd( TIM3, DISABLE);            // 关闭定时器3
        TIM_Cmd( TIM4, DISABLE);            // 关闭定时器4
        TIM_ITConfig( TIM4, TIM_IT_Update, DISABLE);
    }
}
  • 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
/**
  ******************************************************************************
  * @file    main.c
  * @author  SieYuan
  * @version V1.0
  * @date    2020-12-09
  * @brief   配置主从定时器,输出精确脉冲个数的PWM波
  *
  ******************************************************************************
  */
#include "stm32f10x.h"
#include "timer.h"      // 主从定时器配置
#include "led.h"
#include "exti.h"
#include "delay.h"

int main(void)
{<!-- -->
    // 初始化
    LED_Init();
    KEY_Init();
    EXTIx_Init();

    // 初始化完成
    LED1(0);
    delay_ms(500);
    LED1(1);
    delay_ms(500);
    LED1(0);
    delay_ms(500);
    LED1(1);

    PWM_Output_A(1000, 10, 1000);       // 72M / 72 = 1MHz, 1M / 1k = 1kHz
    PWM_Output_B(500, 10, 0);           // 72M / 72 = 1MHz, 1M / 500 = 2kHz
    PWM_Output_C(100, 10, 0);           // 72M / 72 = 1MHz, 1M / 100 = 10kHz
    while (1);
}
  • 注意事项1:高级定时器作为主定时器,如在 TIM1_GPIO_Config() 函数中需要配置:

TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

大家可以右键 Go To Definition,当采用 TIM1 和 TIM8 时,TIM_RepetitionCounter 才有效。它的作用是当从定时器对脉冲计数溢出时,会产生一个更新事件使得 高级定时器TIM1和TIM8 重复计数寄存器(TIMx_RCR)的REP值减1。当REP_CNT = 0时,又会产生一个更新事件并且计数器REP_CNT重新从设定的REP值开始计数(向下计数)。也就是说,TIM_RepetitionCounter = 0, 从定时器溢出1次(REP+1)就会进入中断;如果设置 TIM_RepetitionCounter = 1, 从定时器溢出2次(REP+1)才会进入中断,如例程中产生20(10*2)次脉冲才会停止。具体规范地说明,参考 stm32f10x_tim.h 或《STM32中文参考手册》P246,如下图。
stm32f10x_tim.h

REP

  • 注意事项2:高级定时器作为主定时器,如在 PWM_Output_A() 函数中需要配置:

TIM_CtrlPWMOutputs( TIM1, ENABLE);
同时,在中断服务函数中也要关闭,如TIM2_IRQHandler()中:
TIM_CtrlPWMOutputs( TIM1, DISABLE);
TIM_Cmd( TIM1, DISABLE);

大家依然可以右键 Go To Definition,当采用 TIM1 和 TIM8 时,要在刹车和死区寄存器(TIMx_BDTR)中使能MOE。具体规范地说明,参考 stm32f10x_tim.c 或《STM32中文参考手册》P248,如下图。
stm32f10x_tim.c
TIMx_BDTR

  • 小程序实验结果:TIM1-CH1输出,10个脉冲,1kHz(这里输出PWM后一直是高电平,这个未找到原因,但输出的是10个脉冲)
    TIM1-CH1
  • 小程序实验结果:TIM5-CH1输出,也是10个脉冲,2kHz。
    TIM5-CH1
  • 小程序实验结果:TIM3-CH1输出,也是10个脉冲,10kHz。
    TIM3-CH1

STM32F407:F407的定时器配置与F103稍有区别,我在移植时想当然了,没有仔细学习,花了很长时间才找到问题。只有少部分与F103不同,我在注释中会添加“F407”以表示。(开始我很奇怪为什么都是F103的主从定时器,没什么人写F407,原来改动很小,而且是常用设置。看来还是要认真仔细,独立思考呀)

  • Timer.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
#ifndef __TIMER_H
#define __TIMER_H

#include "sys.h"

/* Group A: TIM1 - 主定时器,TIM2 - 从定时器
     TIM1: CH3 - PE13, CH4 - PE14   RCC_APB2Periph_TIM1, RCC_AHB1Periph_GPIOE
   TIM2: TIM2: RCC_APB1Periph_TIM2
     
     Group B: TIM4 - 主定时器,TIM8 - 从定时器
     TIM4: CH1 - PB6,  CH2 - PB7        RCC_APB1Periph_TIM4
   TIM8: RCC_APB2Periph_TIM8
     
     Group C: TIM3 - 主定时器,TIM4 - 从定时器
     TIM3: TIM3: CH3 - PB0,  CH4 - PB1      RCC_APB1Periph_TIM3
   TIM5: RCC_APB1Periph_TIM5   
*/

/*****定时器初始化函数*****/
// Group A
void TIM1_GPIO_Config(u16 TIM1_Prescaler, u16 TIM1_Period, u16 CCR_A, u16 DIR_A);
void TIM2_GPIO_Config(u32 PulseNum_A);
void PWM_Output_A(u16 Cycle_A, u32 PulseNum_A, u16 DIR_A);
void TIM2_IRQHandler(void);

// Group B
void TIM4_GPIO_Config(u16 TIM4_Prescaler, u16 TIM4_Period, u16 CCR_B, u16 DIR_B);
void TIM8_GPIO_Config(u32 PulseNum_B);
void PWM_Output_B(u16 Cycle_B, u32 PulseNum_B, u16 DIR_B);
void TIM8_UP_TIM13_IRQHandler(void);

// Group C
void TIM3_GPIO_Config(u16 TIM3_Prescaler, u16 TIM3_Period, u16 CCR_C, u16 DIR_C);
void TIM5_GPIO_Config(u32 PulseNum_C);
void PWM_Output_C(u16 Cycle_C, u32 PulseNum_C, u16 DIR_C);
void TIM5_IRQHandler(void);

#endif  /* __TIMER_H */

/****************************END OF FILE****************************/
  • Timer.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#include "Timer.h"

/*********** Group A ***********/
// 定时器1主模式
void TIM1_GPIO_Config(u16 TIM1_Prescaler, u16 TIM1_Period, u16 CCR_A, u16 DIR_A)
{<!-- -->
    GPIO_InitTypeDef    GPIO_InitStructure;
   
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE);
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOE, ENABLE);          // F407: GPIO 串口初始化 与F103不同
   
    GPIO_PinAFConfig( GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);       // F407 端口复用映射
    GPIO_PinAFConfig( GPIOE, GPIO_PinSource14, GPIO_AF_TIM1);       // F407 端口复用映射
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;        // TIM1_CH1 - PE13, CH4 - PE14
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;            // 复用
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      // 推挽复用输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;            // 上拉
    GPIO_Init(GPIOE, &GPIO_InitStructure);
   
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = TIM1_Period - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = TIM1_Prescaler - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;            // 重复计数,一定要 = 0
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
   
    TIM_OCInitTypeDef       TIM_OCInitStructure;
    // 设置工作模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                           // PWM1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   // 比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;            // 输出极性
    // PWM通道,TIM1 - 通道1设置函数,50/100
    TIM_OCInitStructure.TIM_Pulse = CCR_A;                              // 设置待装入捕获寄存器的脉冲值
    TIM_OC3Init( TIM1, &TIM_OCInitStructure);
    TIM_SelectMasterSlaveMode( TIM1, TIM_MasterSlaveMode_Enable);
    TIM_SelectOutputTrigger( TIM1, TIM_TRGOSource_Update);
    TIM_OC3PreloadConfig( TIM1, TIM_OCPreload_Enable);
    // PWM通道,TIM1 - 通道4设置函数,100/100 or 0/100
    TIM_OCInitStructure.TIM_Pulse = DIR_A;                              // 初始化 TIM1-OC4
    TIM_OC4Init( TIM1, &TIM_OCInitStructure);                       // CH4预装载使能,修改
    TIM_OC4PreloadConfig( TIM1, TIM_OCPreload_Enable);
   
    TIM_ARRPreloadConfig(TIM1, ENABLE);
}

//定时器2从模式
void TIM2_GPIO_Config(u32 PulseNum_A)
{<!-- -->
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef    NVIC_InitStructure;
   
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE);
   
    TIM_TimeBaseStructure.TIM_Period = PulseNum_A;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM2, &TIM_TimeBaseStructure);
   
    TIM_SelectInputTrigger( TIM2, TIM_TS_ITR0);         // TIM1-主,TIM2-从
    TIM_SelectSlaveMode( TIM2, TIM_SlaveMode_External1);
    TIM_ITConfig( TIM2, TIM_IT_Update, DISABLE);
   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure);
}

void PWM_Output_A(u16 Cycle_A, u32 PulseNum_A, u16 DIR_A)           // TIM1-主,TIM2-从
{<!-- -->
    TIM2_GPIO_Config(PulseNum_A);
    TIM_Cmd( TIM2, ENABLE);
    TIM_ClearITPendingBit( TIM2, TIM_IT_Update);
    TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE);
    TIM1_GPIO_Config( 84, Cycle_A, Cycle_A / 2, DIR_A); //F407: 高级定时器是 168MHz, 故168MHz / 84 = 2MHz
    TIM_Cmd( TIM1, ENABLE);
    TIM_CtrlPWMOutputs( TIM1, ENABLE);  // 高级定时器 TIM1 使能 MOE
}

/*********** Group B ***********/
// 定时器4主模式
void TIM4_GPIO_Config(u16 TIM4_Prescaler, u16 TIM4_Period, u16 CCR_B, u16 DIR_B)
{<!-- -->
    GPIO_InitTypeDef    GPIO_InitStructure;
   
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM4, ENABLE);
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE);          // F407: GPIO 串口初始化 与F103不同
   
    GPIO_PinAFConfig( GPIOB, GPIO_PinSource6, GPIO_AF_TIM5);        // F407 端口复用映射
    GPIO_PinAFConfig( GPIOB, GPIO_PinSource7, GPIO_AF_TIM5);        // F407 端口复用映射
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;          // TIM4_CH3 PB0, CH4 - PB1
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;            // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure); 
   
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
    // 时钟频率设置
    TIM_TimeBaseStructure.TIM_Period = TIM4_Period - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = TIM4_Prescaler - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM4, &TIM_TimeBaseStructure);
   
    TIM_OCInitTypeDef       TIM_OCInitStructure;
    // 设置工作模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;           // 设置工作模式是PWM,且为PWM1工作模式,TIMx_CNT<TIMx_CCR1时为高电平
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;       // 也就是使能PWM输出到端口                   
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;            // 输出极性
    // PWM通道,TIM4 - 通道1设置函数,50/100
    TIM_OCInitStructure.TIM_Pulse = CCR_B;                  // 设置待装入捕获寄存器的脉冲值
    TIM_OC1Init( TIM4, &TIM_OCInitStructure);                       // 初始化 TIM4-OC3
    TIM_SelectMasterSlaveMode( TIM4, TIM_MasterSlaveMode_Enable);       // 定时器主从模式使能
    TIM_SelectOutputTrigger( TIM4, TIM_TRGOSource_Update);                      // 选择触发方式:使用更新事件作为触发输出
    TIM_OC1PreloadConfig( TIM4, TIM_OCPreload_Enable);      // CH1预装载使能,修改             
    // PWM通道,TIM4 - 通道2设置函数,100/100 or 0/100
    TIM_OCInitStructure.TIM_Pulse = DIR_B;                                  // 初始化 TIM4-OC4
    TIM_OC2Init( TIM4, &TIM_OCInitStructure);                       // CH2预装载使能,修改
    TIM_OC2PreloadConfig( TIM4, TIM_OCPreload_Enable);
   
    TIM_ARRPreloadConfig( TIM4, ENABLE);                    // 使能ARR预装载寄存器
}

//定时器8从模式
void TIM8_GPIO_Config(u32 PulseNum_B)
{<!-- -->
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef    NVIC_InitStructure;
   
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM8, ENABLE);
   
    TIM_TimeBaseStructure.TIM_Period = PulseNum_B;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM8, &TIM_TimeBaseStructure);
   
    TIM_SelectInputTrigger( TIM8, TIM_TS_ITR2);         // TIM2-主,TIM4-从
    TIM_SelectSlaveMode( TIM8, TIM_SlaveMode_External1);
    TIM_ITConfig( TIM8, TIM_IT_Update, DISABLE);
   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
    NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_TIM13_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure);
}

void PWM_Output_B(u16 Cycle_B, u32 PulseNum_B, u16 DIR_B)           // TIM2-主,TIM4-从
{<!-- -->
    TIM8_GPIO_Config(PulseNum_B);
    TIM_Cmd( TIM8, ENABLE);
    TIM_ClearITPendingBit( TIM8, TIM_IT_Update);
    TIM_ITConfig( TIM8, TIM_IT_Update, ENABLE);
    TIM4_GPIO_Config( 84, Cycle_B, Cycle_B / 2, DIR_B);     //F407:通用定时器是 84MHz, 故84MHz / 84 = 1MHz
    TIM_Cmd( TIM4, ENABLE);
}

/*********** Group C ***********/
// 定时器3主模式
void TIM3_GPIO_Config(u16 TIM3_Prescaler, u16 TIM3_Period, u16 CCR_C, u16 DIR_C)
{<!-- -->
    GPIO_InitTypeDef    GPIO_InitStructure;
    // TIM3通道1\2 - PWM Z轴步进电机脉冲信号
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE);
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE);          // F407: GPIO 串口初始化 与F103不同
   
    GPIO_PinAFConfig( GPIOB, GPIO_PinSource0, GPIO_AF_TIM3);        // F407 端口复用映射
    GPIO_PinAFConfig( GPIOB, GPIO_PinSource1, GPIO_AF_TIM3);        // F407 端口复用映射
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;          // TIM3_CH1 PA6, CH2 - PA7
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;            // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);     
   
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
    // 时钟频率设置
    TIM_TimeBaseStructure.TIM_Period = TIM3_Period - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = TIM3_Prescaler - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM3, &TIM_TimeBaseStructure);
   
    TIM_OCInitTypeDef       TIM_OCInitStructure;
    // 设置工作模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;           // 设置工作模式是PWM,且为PWM1工作模式,TIMx_CNT<TIMx_CCR1时为高电平
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;       // 也就是使能PWM输出到端口                   
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;            // 输出极性
    // PWM通道,TIM3 - 通道1设置函数,50/100
    TIM_OCInitStructure.TIM_Pulse = CCR_C;                  // 设置待装入捕获寄存器的脉冲值
    TIM_OC3Init( TIM3, &TIM_OCInitStructure);                       // 初始化 TIM3-OC1
    TIM_SelectMasterSlaveMode( TIM3, TIM_MasterSlaveMode_Enable);       // 定时器主从模式使能
    TIM_SelectOutputTrigger( TIM3, TIM_TRGOSource_Update);                      // 选择触发方式:使用更新事件作为触发输出
    TIM_OC3PreloadConfig( TIM3, TIM_OCPreload_Enable);      // CH1预装载使能,修改             
    // PWM通道,TIM3 - 通道2设置函数,100/100 or 0/100
    TIM_OCInitStructure.TIM_Pulse = DIR_C;                                  // 初始化 TIM3-OC2
    TIM_OC4Init( TIM3, &TIM_OCInitStructure);                       // CH2预装载使能,修改
    TIM_OC4PreloadConfig( TIM3, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig( TIM3, ENABLE);                    // 使能ARR预装载寄存器
}

// 定时器5从模式
void TIM5_GPIO_Config(u32 PulseNum_Z)
{<!-- -->
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef    NVIC_InitStructure;
   
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
   
    TIM_TimeBaseStructure.TIM_Period = PulseNum_Z;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM5, &TIM_TimeBaseStructure);
   
    TIM_SelectInputTrigger( TIM5, TIM_TS_ITR1);
    TIM_SelectSlaveMode( TIM5,TIM_SlaveMode_External1 );        // 等同下一句 TIM5->SMCR |= 0x07
    TIM_ITConfig( TIM5, TIM_IT_Update, DISABLE);
   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
}

void PWM_Output_C(u16 Cycle_C, u32 PulseNum_C, u16 DIR_C)           // TIM3-主,TIM5-从
{<!-- -->
    TIM5_GPIO_Config(PulseNum_C);
    TIM_Cmd( TIM5, ENABLE);
    TIM_ClearITPendingBit( TIM5, TIM_IT_Update);
    TIM_ITConfig( TIM5, TIM_IT_Update, ENABLE);
    TIM3_GPIO_Config( 56, Cycle_C, Cycle_C / 2, DIR_C);     //84MHz / 56 = 1.5MHz
    TIM_Cmd( TIM3, ENABLE);
}

// Group A
void TIM2_IRQHandler(void)
{<!-- -->
    if (TIM_GetITStatus( TIM2, TIM_IT_Update) != RESET)
    {<!-- -->
        TIM_ClearITPendingBit( TIM2, TIM_IT_Update);            // 清除中断标志位
        TIM_CtrlPWMOutputs( TIM1, DISABLE);     // 高级定时器 TIM1 关闭MOE
        TIM_Cmd( TIM1, DISABLE);            // 关闭定时器1
        TIM_Cmd( TIM2, DISABLE);            // 关闭定时器2
        TIM_ITConfig( TIM2, TIM_IT_Update, DISABLE);
    }
}

// Group B
void TIM8_UP_TIM13_IRQHandler(void)
{<!-- -->
    if (TIM_GetITStatus( TIM8, TIM_IT_Update) != RESET)
    {<!-- -->
        TIM_ClearITPendingBit( TIM8, TIM_IT_Update);            // 清除中断标志位
        TIM_Cmd( TIM4, DISABLE);            // 关闭定时器4
        TIM_Cmd( TIM8, DISABLE);            // 关闭定时器8
        TIM_ITConfig( TIM8, TIM_IT_Update, DISABLE);
    }
}

// Group C
void TIM5_IRQHandler(void)
{<!-- -->
    if (TIM_GetITStatus( TIM5, TIM_IT_Update) != RESET)
    {<!-- -->
        TIM_ClearITPendingBit( TIM5, TIM_IT_Update);            // 清除中断标志位
        TIM_Cmd( TIM3, DISABLE);            // 关闭定时器3
        TIM_Cmd( TIM5, DISABLE);            // 关闭定时器5
        TIM_ITConfig( TIM5, TIM_IT_Update, DISABLE);
    }
}

/****************************END OF FILE****************************/
  • 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
/**
**************************************************************************************
* @file    main.c
* @author  SieYuan
* @version V1.0
* @date    2020-12-09
* @brief   配置主从定时器,输出精确脉冲个数的PWM波
*
**************************************************************************************
*/

#include  "sys.h"
#include    "led.h"
#include    "key.h"
#include    "exti.h"
#include    "Timer.h"
#include    "delay.h"

int main(void)
{<!-- -->
    /* 程序初始化:对【LED】【KEY】【EXIT】【USART】*/
    LED_Init();
    KEY_Init();
    EXTIx_Init();
    delay_init(168);

    LED1 = 0;
    delay_ms(500);
    LED1 = 1;
    delay_ms(500);
    LED1 = 0;
    delay_ms(500);
    LED1 = 1;
    /* 程序初始化完成 !*/

    PWM_Output_A(1000, 10, 1000);       // 168M / 84 = 2MHz, 2M / 1000 = 2kHz
    PWM_Output_B(100, 10, 0);           // 84M / 84 = 1MHz, 1M / 100 = 10kHz
    PWM_Output_C(1000, 10, 0);          // 84M / 56 = 1.5MHz, 1.5M / 1000 = 1.5kHz
    while(1);
}
   
/****************************END OF FILE****************************/
  • 注意事项3:串口(GPIOA—GPIOK)在AHB1总线桥,详见 stm32f4xx_rcc.c 的RCC_AHB1PeriphClockCmd();高级定时器 TIM1\TIM8,通用定时器TIM9\TIM10\TIM11在APB2总线桥,详见 stm32f4xx_rcc.c 的RCC_APB2PeriphClockCmd();通用定时器TIM2—TIM7、TIM12\TIM13\TIM14在APB1总线桥,详见 stm32f4xx_rcc.c 的RCC_APB1PeriphClockCmd() 。

如:
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE);
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOE, ENABLE);

  • 注意事项4:STM32F4端口复用时,要使用函数 GPIO_PinAFConfig(),详见 stm32f4xx_gpio.c ;需要,不是STM32F1配置引脚宏定义格式(如 GPIO_Pin_3),而应该是 GPIO_PinSource3。另外,每次只能配置一个引脚的端口复用映射。

举例:上面TIM1_GPIO_Config()
正确方式:
GPIO_PinAFConfig( GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);
GPIO_PinAFConfig( GPIOE, GPIO_PinSource14, GPIO_AF_TIM1);
错误方式:
GPIO_PinAFConfig( GPIOE, GPIO_Pin_13, GPIO_AF_TIM1);
GPIO_PinAFConfig( GPIOE, GPIO_Pin_14, GPIO_AF_TIM1);

GPIO_PinAFConfig( GPIOE, GPIO_PinSource13 | GPIO_PinSource14, GPIO_AF_TIM1);

  • 小程序实验结果:TIM1-CH3输出,也是10个脉冲,2kHz。
    TIM1-CH3

  • 小程序实验结果:TIM4-CH1输出,也是10个脉冲,10kHz。
    TIM4-CH1

  • 小程序实验结果:TIM3-CH3输出,也是10个脉冲,1.5kHz。
    TIM3-CH3

小结

  • 以上就是我使用主从定时器方式控制PWM波输出给步进电机驱动器来控制步进电机的解决方法(纯开环,无法考虑丢步等问题)。
  • 这种方法很多论坛都有资料,我只是一个借鉴、总结优秀的人提出的方法并复现出来的搬运工、学习者。可能针对我搜索中遇到诸多不便,以我小白的视角做了一定的补充,希望给其他小白提供便利。我还将两份代码压缩上传,供大家下载(其实上面展示出来的已经够用了)。毕竟像我一样不充CSDN会员的很多吧,手动狗头。
  • 第一次写这种交流分享的文档。作为小白,欢迎大家发现文章中的问题,检验我的代码,提出改进的建议,期待你留言与我交流、探讨,共同进步。