项目中需要对步进电机进行较为精准的控制。经过查找资料,可以通过对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。
下图,表72,表79,来自《STM32F4xx中文参考手册》P370,P464;适用于STM32F407。
- 注意:由上表可知,对于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,如下图。
- 注意事项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,如下图。
- 小程序实验结果:TIM1-CH1输出,10个脉冲,1kHz(这里输出PWM后一直是高电平,这个未找到原因,但输出的是10个脉冲)
- 小程序实验结果:TIM5-CH1输出,也是10个脉冲,2kHz。
- 小程序实验结果:TIM3-CH1输出,也是10个脉冲,10kHz。
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。
-
小程序实验结果:TIM4-CH1输出,也是10个脉冲,10kHz。
-
小程序实验结果:TIM3-CH3输出,也是10个脉冲,1.5kHz。
小结
- 以上就是我使用主从定时器方式控制PWM波输出给步进电机驱动器来控制步进电机的解决方法(纯开环,无法考虑丢步等问题)。
- 这种方法很多论坛都有资料,我只是一个借鉴、总结优秀的人提出的方法并复现出来的搬运工、学习者。可能针对我搜索中遇到诸多不便,以我小白的视角做了一定的补充,希望给其他小白提供便利。我还将两份代码压缩上传,供大家下载(其实上面展示出来的已经够用了)。毕竟像我一样不充CSDN会员的很多吧,手动狗头。
- 第一次写这种交流分享的文档。作为小白,欢迎大家发现文章中的问题,检验我的代码,提出改进的建议,期待你留言与我交流、探讨,共同进步。