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
#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
#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
/**
  ******************************************************************************
  * @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
#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
#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
/**
**************************************************************************************
* @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下载链接: STM32:F103/F407定时器主从模式输出精准脉冲个数.

  • 26
    点赞
  • 173
    收藏
    觉得还不错? 一键收藏
  • 37
    评论
要使用STM32F103ZET6主从定时器模式输出固定脉冲个数的PWM波,可以按照以下步骤进行操作: 1. 首先,配置主从定时器的基本参数。选择一个主定时器和一个从定时器,使它们工作在定时器模式和PWM输出模式下。 2. 配置主定时器的参数,例如周期、预分频系数等。这些参数将决定PWM波的频率。 3. 配置从定时器的参数,例如周期、预分频系数等。这些参数将决定PWM波的占空比。 4. 使用主定时器来触发从定时器的计数开始,使从定时器开始生成PWM波。 5. 在程序中使用计数器变量来记录生成的脉冲个数,当达到指定的脉冲个数后,停止从定时器的计数。 下面是一个简单的示例代码,展示了如何使用STM32Cube HAL库在STM32F103芯片上实现主从定时器模式输出固定脉冲个数的PWM波: ```c #include "main.h" #include "stm32f1xx_hal.h" // 定义主从定时器句柄 TIM_HandleTypeDef htim1; TIM_HandleTypeDef htim2; // 记录脉冲个数 volatile uint32_t pulseCount = 0; const uint32_t targetPulseCount = 100; // 指定的脉冲个数 // 主定时器中断回调函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM1) { // 主定时器中断触发从定时器的计数开始 HAL_TIM_Base_Start(&htim2); } } // 从定时器中断回调函数 void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { pulseCount++; // 记录脉冲个数 if (pulseCount >= targetPulseCount) { // 达到指定的脉冲个数后,停止从定时器的计数 HAL_TIM_Base_Stop(&htim2); pulseCount = 0; // 重置脉冲计数 } } } // 初始化主从定时器 void MX_TIM_Init(void) { // 初始化主定时器 TIM1 htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 999; // 设置周期为1000 htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim1); // 初始化从定时器 TIM2 htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 999; // 设置周期为1000,即占空比为50% htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim2); // 配置从定时器为PWM输出模式 TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500; // 设置初始占空比为50% sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1); } int main(void) { // 初始化HAL库 HAL_Init(); // 初始化主从定时器 MX_TIM_Init(); // 启动主定时器 HAL_TIM_Base_Start(&htim1); while (1) { // 主循环 // TODO: 其他任务 } } ``` 上述代码中,主定时器 TIM1 负责触发从定时器 TIM2 的计数开始,从定时器 TIM2 生成PWM波。在从定时器的中断回调函数中,通过记录脉冲个数并与目标脉冲个数进行比较,来控制生成的脉冲个数。 注意,以上代码仅为示例,实际应用中可能需要根据具体需求进行修改和适配。另外,确保在使用 STM32Cube HAL 库时已经正确配置了时钟和引脚相关的设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值