STM32正交编码器接口
STM32四路正交编码器接口
一、主要内容
- 芯片型号、使用引脚及初始化程序源码
- TIM2端口重映射问题
- 与JTAG接口冲突时的现象及解决方法
二、芯片型号、使用引脚及初始化程序源码
芯片型号:STM32F103RET6
使用定时器:TIM2、TIM3、TIM4、TIM5
使用引脚:
TIM2—PA15、PB3(remap)
TIM3—PA6、PA7
TIM4—PB6、PB7
TIM5—PA0、PA1
初始化程序源码:
(其中TIM2的配置有特殊需要注意的地方,其他配置相同,调试时遇到的问题和解决方法见下文)
#include "stm32f10x.h"
#include "encoder.h"
void TIM2_Mode_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//PA15 ch1, PB3 ch2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 关闭JTAG功能
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE); // 重映射TIM2的CH1、CH2到PA15和PB3
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_DeInit(TIM2);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 50000;
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_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 6;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
//Reset counter
TIM2->CNT = 0;
TIM_Cmd(TIM2, ENABLE);
}
void TIM3_Mode_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//PA6 ch1, PA7 ch2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_DeInit(TIM3);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 50000;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 6;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
//Reset counter
TIM3->CNT = 0;
TIM_Cmd(TIM3, ENABLE);
}
void TIM4_Mode_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//PB6 ch1, PB7 ch2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_DeInit(TIM4);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 50000;
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_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 6;
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
//Reset counter
TIM4->CNT = 0;
TIM_Cmd(TIM4, ENABLE);
}
void TIM5_Mode_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//PA0 ch1 A,PA1 ch2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_DeInit(TIM5);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 50000;
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_EncoderInterfaceConfig(TIM5, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 6;
TIM_ICInit(TIM5, &TIM_ICInitStructure);
TIM_ClearFlag(TIM5, TIM_FLAG_Update);
TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
//Reset counter
TIM5->CNT = 0;
TIM_Cmd(TIM5, ENABLE);
}
在使用时,读取TIMx->CNT寄存器中的数据即可。
三、 TIM2端口重映射问题
问题描述
在一开始调试的时候,TIM2的初始化程序和其他定时器的相同,这时旋转TIM2连接的编码器,计数没有变化,旋转TIM5连接的编码器时,TIM2和TIM5的计数同时变化并且数值相同。
解决方法
从手册中可以看出PA15和PB3的TIM2功能需要进行重映射,否则在PA0和PA1上编码器信号既进入TIM2,又进入TIM5,因此会导致TIM2和TIM5的计数相同。
在PA15和PB3作为TIM2编码器信号输入引脚时,需要进行IO重映射:
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE); // 重映射TIM2的CH1、CH2到PA15和PB3
四、与JTAG接口冲突时的现象及解决方法
问题描述
在TIM2进行IO重映射后,仍不能正常使用,无论如何旋转编码器,计数器的值只有0、1、MAX三个值(在0上+1或-1)
解决方法
从手册中编码器模式下的计数器变化过程中可以看出,当两相编码器的一个信号不变,另一个信号变化时,计数器计数值会在某个数值上下波动,和上述问题情况类似,因此猜测是因为编码器其中一相的信号没有捕获到。
再次查阅手册发现PA15和PB3引脚的默认功能为JTAG功能,需要关闭后才能正确使用,否则JTDO为输出引脚,无法捕获到编码器信号,所以会出现计数值只有0,1,MAX三个值的现象。这里仅关闭JTAG功能,保留SWD以便调试使用:
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 关闭JTAG功能
五、参考链接
http://blog.csdn.net/wang328452854/article/details/50579832
http://www.openedv.com/posts/list/54017.htm
http://www.openedv.com/posts/list/0/57077.htm