一个项目需要对电机闭环控制,采用的霍尔编码电机。

本来用的STM32F103ZET6,然后不知道咋回事芯片发热烧坏了,然后正好有一批STM32F207ZET6,对比了下IO口发现一样,就直接干上去了,干上去后发现3.3和GND处于短路状态,开始怀疑是3.3V电压出问题了,就把3.3V供电部分全部拆除了,发现还是短路,就又把芯片引脚仔细对了一遍,发现供电引脚有几个对不上。如下图


由于VSS和VDD芯片能不是相连的,所以少一路供电应该问题不大,就直接把这几个引脚掰断干上去了,烧下测试代码,成功运行,至此换芯片结束。
代码部分直接换库文件,移植过程还算简单。
但当调到编码器时,一直没有读数。一度怀疑是不是掰断那几个引脚引起的问题,无奈之下用STM32CubeMX生成的代码测试一下,发现可以正常读数,遂排除了硬件问题。然后对比发现了问题
调整前的代码
GPIO_PinAFConfig(GPIOA,GPIO_Pin_9,GPIO_AF_4);
GPIO_PinAFConfig(GPIOA,GPIO_Pin_10,GPIO_AF_4);
调整后的代码
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_4);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_4);
不难看出,调整的就是上面红色参数部分。一个是GPIO_Pin_N,一个是GPIO_PinSourceN,其实这2个参数是不一样的。
GPIO_Pin_n可以理解为某端口脚在整个端口的位置。比方某GPIO口的第6管脚位置编码GPIO_Pin_6 被定义为 ((uint16_t)0x0040) ,在对相应GPIO管脚做基本属性配置时会用到,如配置输入输出模式、模拟输入模式的选择等。有兴趣的话,可以点击GPIO_Init( )进去看看。
而GPIO_PinSourceN一般是在对某GPIO口相应pin脚的复用功能进行选择配置才会用到。它是根据端口各脚位的位置按顺序从0开始依次递增编号,可以理解为该管脚在该端口的序号。比方某GPIO口的第6号复用功能脚的序号GPIO_PinSource6 被定义为 ((uint8_t)0x06) 。有兴趣的话,也可以打开GPIO_PinAFConfig( )函数看看。显然,GPIO_PinSource6跟上面的GPIO_Pin_6的值相差甚远。
下面是ST官方库代码中有关GPIO_Pin_N的定义:
#define GPIO_Pin_0 ((uint16_t)0x0001)
#define GPIO_Pin_1 ((uint16_t)0x0002)
#define GPIO_Pin_2 ((uint16_t)0x0004)
#define GPIO_Pin_3 ((uint16_t)0x0008)
#define GPIO_Pin_4 ((uint16_t)0x0010)
#define GPIO_Pin_5 ((uint16_t)0x0020)
#define GPIO_Pin_6 ((uint16_t)0x0040)
#define GPIO_Pin_7 ((uint16_t)0x0080)
#define GPIO_Pin_8 ((uint16_t)0x0100)
#define GPIO_Pin_9 ((uint16_t)0x0200)
#define GPIO_Pin_10 ((uint16_t)0x0400)
。。。。。。
#define GPIO_Pin_15 ((uint16_t)0x8000)
#define GPIO_Pin_All ((uint16_t)0xFFFF)
下面是有关GPIO_PinSourceN的定义:
#define GPIO_PinSource0 ((uint8_t)0x00)
#define GPIO_PinSource1 ((uint8_t)0x01)
#define GPIO_PinSource2 ((uint8_t)0x02)
#define GPIO_PinSource3 ((uint8_t)0x03)
#define GPIO_PinSource4 ((uint8_t)0x04)
#define GPIO_PinSource5 ((uint8_t)0x05)
#define GPIO_PinSource6 ((uint8_t)0x06)
#define GPIO_PinSource7 ((uint8_t)0x07)
#define GPIO_PinSource8 ((uint8_t)0x08)
#define GPIO_PinSource9 ((uint8_t)0x09)
#define GPIO_PinSource10 ((uint8_t)0x0A)
。。。。。。
#define GPIO_PinSource15 ((uint8_t)0x0F)
贴出编码器驱动代码
void Encoder3_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = TIM3_CH1_PIN | TIM3_CH2_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(TIM3_CH1_GPIO, &GPIO_InitStructure);
//引脚映射
GPIO_PinAFConfig(TIM3_CH1_GPIO, GPIO_PinSource6, GPIO_AF_TIM3);
GPIO_PinAFConfig(TIM3_CH1_GPIO, GPIO_PinSource7, GPIO_AF_TIM3);
//定时器设置
TIM_DeInit(TIM3);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0; //时钟分频
TIM_TimeBaseStructure.TIM_Period = 65535;//计数器最大值
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_Rising , TIM_ICPolarity_Rising );
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 15;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3, ENABLE);
}
方向读取
encoder_1 = (TIM3->CR1 & 0X10)>>4;
数据读取
num = TIM3->CNT;
读取后清零
TIM3->CNT = 0;