如图为STM32高级定时器TIM1的四个不同通道(通用定时器和基础定时器同理)
在配置定时器时,我可以随便使用GPIO口吗?
- 不行!
- 在MCU出厂时,不同的定时器已经设定好对应的通道,并连接了对应的GPIO口,不可自己随意更改。(当然还有一次修改机会——重映射,参照下文)
TIMx_CHx不同通道有什么区别?TIMx_CHx与TIMx_CHxN?
- TIMx_CHx不同的通道没有本质区别,只是连接了不同的GPIO引脚。在配置定时器TIM1过程中,初始化GPIO时,初始化了对应的某个引脚,定时器会自动选择对应通道,不会在代码中出现
_CHx
字样(函数名或注释除外) - 但是:TIMx_CHxN就有区别了:TIMx_CHxN为互补通道,通常用于高级定时器功能,如互补输出PWM。
- 例如:TIM1_CH3N通常与TIM1_CH3配合使用,以实现死区控制或中心对齐的PWM模式
这么多通道,如何选择?
- GPIO口富余的时候,看谁好看就用哪个通道
- GPIO口不富余时,目标定时器通道的GPIO口被其他外设占用后,可以使用重映射功能,将该定时器通道重新连接到其他GPIO口上
- 如上表:重映射需要参照《STM32中文参考手册》,不能自己随意指定
- 例如:我现在要使用TIM1_CH1,它的默认引脚为PA8,但是PA8引脚已经被USART的
USART1_CK
通道使用,那么我就需要将TIM1_CH1换一个GPIO引脚以使用该定时器功能通道,参考《参考手册》的上表,我们可以使用完全重映射将TIM1_CH1重新连接在PE9这一GPIO引脚上,进而使用定时器TIM1的功能。(部分重映射与完全重映射的区别 见下文) - 重映射通常调用
GPIO_PinRemapConfig()
函数,虽然函数名带有GPIO字样,但函数配置时,通常以对应外设为主体对象(啥意思?可参考下面部分重映射与完全重映射部分帮助理解) - 文章末尾附有重映射代码示例以参考
注意
- STM32原理图上只展示没有重映像的GPIO口的功能接口,如下图的PA11引脚,它的USART1_CTS、CAN_RX、TIM1_CH4、USB通道都是没有开启重映射时的默认引脚接口,如需找到对应的重映射接口,需参照《参考手册》对应章节(《8.3 复用功能 复用功能I/O 和调试配置》)
部分重映射与完全重映射?
- 部分重映射与完全重映射的概念:
- 部分重映射:顾名思义,在开启部分重映射时,只将目标外设的部分通道从默认引脚修改到新引脚上;
- 完全重映射:就是将该外设的所有通道全部都从默认引脚修改到新引脚上
- 以图示的TIM3为例:
- 使用部分重映射时:TIM3_CH1与TIM3_CH2两个通道的引脚分别从默认引脚PA6、PA7修改到PB4、PB5两个新引脚上。而TIM_CH3与TIM3_CH4两个通道的引脚仍然为PB0、PB1引脚不变。
- 使用完全重映射时:从TIM3_CH1到TIM3_CH4这四个通道,它们的管脚全部都从默认引脚PA6、PA7、PB0、PB1修改到了新的引脚PC6、PC7、PC8、PC9上
定时器TIM3_CH2配置重映射参考代码
该函数使用TIM3_CH2用于配置PWM,并将输出管脚从默认引脚映射到了新的引脚PB5上(代码部分参考引用自普中科技)
void TIM3_CH2_PWM_Init(u16 per,u16 psc)
{
//定义结构体变量,用于下面的初始化配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* 开启时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//改变指定管脚的映射
//时基配置
TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
//输出比较配置
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC2Init(TIM3,&TIM_OCInitStructure); //输出比较通道2初始化
//使能
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIMx在 CCR2 上的预装载寄存器
TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器
TIM_Cmd(TIM3,ENABLE); //使能定时器
}