因为我们公司的软件和硬件是分开的,硬件人员在设计电路板的时候,为了布线方便,往往会使用一些引脚的重映射功能。
这次使用的单片机是stm32F103ZGT6,使用PB4和PB5捕获正交编码器的数据。
因为这两个引脚本身没有定时器,只有在重映射时候才能使用TIM3的ch1和ch2。
因此,我使用重映射配置,将这两个引脚配置了以下,这是一开始的代码:
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3 ,ENABLE ); //重映射相应的外设
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseStructInit(&TIM_TimBaseStructure);
TIM_TimBaseStructure.TIM_Prescaler = 0x0;
TIM_TimBaseStructure.TIM_Period = 2400;
TIM_TimBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3,&TIM_TimBaseStructure);
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM3,&TIM_ICInitStructure);
TIM_ClearFlag(TIM3,TIM_FLAG_Update);
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3,ENABLE);
通过读取TIM3的CNT寄存器获取当前数值。
然而无论怎样旋转编码器,都无法得到计数,计数始终为0。因此开始进行排查:
猜测1:引脚是否能够捕获到高低电平
试验:将两个引脚设置为开入,然后旋转编码器,可以正确的读到两个引脚高低电平的变换,证明是配置的问题
猜测2:是否和未开启AFIO时钟有关?
试验:开启AFIO时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
还是不能捕获电平,证明不是由这个引起的。
猜测3:是否其他地方使用了TIM3,导致重映射功能没有正确开启?
试验:屏蔽其他程序,在重映射之前添加一行程序
TIM_DeInit(TIM3);
问题仍然没有解决。
猜测4:该引脚复用后是否具备捕获编码器脉冲的功能?
试验:百度上搜索,然后获取到了部分重映射和全部重映射的概念。在我的认知当中,部分重映射应该是只映射部分功能,我这里配置的是全部重映射,认为应该是可以实现捕获编码器功能的。
然而问题没有办法解决。只能寻求参考手册的帮助。
在AFIO寄存器这一章看到了这个概念:
看到这里,我瞬间明白了,stm32中的重映射,也是针对端口的,并不是说每个端口都具备映射的全部功能。在开启这个端口重映射的时候,不能够配置成FullRemap,否则是配置失败的。
因此改成了以下样子:
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 ,ENABLE ); //重映射相应的外设
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseStructInit(&TIM_TimBaseStructure);
TIM_TimBaseStructure.TIM_Prescaler = 0x0;
TIM_TimBaseStructure.TIM_Period = 2400;
TIM_TimBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3,&TIM_TimBaseStructure);
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM3,&TIM_ICInitStructure);
TIM_ClearFlag(TIM3,TIM_FLAG_Update);
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3,ENABLE);
stm32由于由库函数的支持,导致我们在使用的过程中越来越忽略掉了底层的一些运作方式。知其然而不知其所以然,在技术道路上,所有忽略掉的小细节以后都会成倍的返还给你。