编码器接口测速接线图

参考引脚定义表,PA6和PA7是TIM3的通道1和通道2,我们计划用TIM3接编码器。
编码器计数代码

第一步,RCC开启时钟,开启GPIO和定时器的时钟。
第二步,配置GPIO,这里需要把PA6和PA7配置成输入模式。
第三步,配置时基单元,这里预分频器我们一般选择不分频。自动重装器一般给最大65535,只需要CNT执行计数就行了。
第四步,配置输入捕获单元。不过这里输入捕获单元只有滤波器和极性这两个参数有用。后面的参数没有用到,与编码器无关。
第五步,配置编码器接口模式。这个直接调用一个库函数就可以了。
第六步,调用TIM_Cmd()函数,启动定时器。
电路初始化完成之后,CNT就会随着编码器的旋转而自增自减了。如果想要测量编码器的位置,直接读出CNT的值就行了,如果想要测量编码器的速度和方向,那就需要每隔一段固定的闸门时间取出一次CNT,然后再把CNT清零。这样就是测频法测量速度了。
流程看完了,我们再看一下库函数:
TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);
第一个参数是选择定时器。
第二个参数选择编码器模式。
后面两个参数,分别选择通道1和通道2的电平极性。
void Encoder_Init()
{
//开启TIM3、GPIOA的时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//配置GPIO,PA6/PA7改成上拉输入。
GPIO_InitTypeDef GPIO_InitStruture;
GPIO_InitStruture.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruture.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_6;
GPIO_Init(GPIOA,&GPIO_InitStruture);
//不需要选择时基单元时钟,因为编码器接口会托管时钟。
//编码器接口本身就是一个带方向控制的外部时钟。
//TIM_InternalClockConfig(TIM3);
//配置时基单元。
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruture;
TIM_TimeBaseStruture.TIM_ClockDivision=TIM_CKD_DIV1;
//计数器模式目前没有作用,因为计数方向也是被编码器接口托管了。
TIM_TimeBaseStruture.TIM_CounterMode=TIM_CounterMode_Up;
//这里给最大值65536-1,这样计数范围是最大的,而且方便换算为负数。
TIM_TimeBaseStruture.TIM_Period=65536 -1;
//预分频器给0,不分频。
TIM_TimeBaseStruture.TIM_Prescaler=1-1;
TIM_TimeBaseStruture.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruture);
//初始化输入捕获单元。
//编码器接口只用到了滤波器和极性选择,剩下的不用写。
TIM_ICInitTypeDef TIM_ICInitStruture;
/* 因为结构体是不完整的,为了防止结构体出现不确定的值可能会造成的问题,
我们最好使用StrucInit给结构体赋一个初始值。*/
TIM_ICStructInit(&TIM_ICInitStruture);
//选择通道,选择TIM3的通道1.
TIM_ICInitStruture.TIM_Channel=TIM_Channel_1;
//配置输入捕获的滤波器,范围是0X0~0XF。越大滤波效果越好。
TIM_ICInitStruture.TIM_ICFilter=0XF;
/*边沿检测、极性选择。我们选择上升沿触发。
我们说过,这里的上升沿并不代表上升沿有效,因为编码器接口始终都是上升沿、下降沿都有效的。
这里的上升沿参数代表的是高低电平极性不反转。其实这里的极性参数等会我们配置编码器接口的
时候也有,属于重复配置了,这里这个其实也可以删掉。*/
TIM_ICInitStruture.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInit(TIM3,&TIM_ICInitStruture);//这样通道1就配置好了
//我们接着配置通道2,和通道1的逻辑一样。
TIM_ICInitStruture.TIM_Channel=TIM_Channel_2;
TIM_ICInitStruture.TIM_ICFilter=0XF;
TIM_ICInitStruture.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInit(TIM3,&TIM_ICInitStruture);
//配置编码器接口
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
//使能定时器
TIM_Cmd(TIM3,ENABLE);
}
//返回TIM3计数器的值
uint16_t Encoder_Get()
{
return TIM_GetCounter(TIM3);
}
本套件使用的编码器是有这个段落感的,每转一格,它输出的波形实际上是这样的:
,A、B相各出现一个下降沿和上升沿,所以计次总共加了4次,当然如果你是电机的编码器,那就不会有这个段落感了。
上述代码我们代入到实物中,会发现旋转编码器正转,CNT的值正常增加,但反转,会出现65535,这时我们就需要用到之前所说的补码小技巧,把uint16_t的类型强转成int16_t,这样就把65535强转成-1了。(STM32是16位系统,所以-1的补码正好是65535)
表现在代码上就是:
//返回TIM3计数器的值
int16_t Encoder_Get()
{
return TIM_GetCounter(TIM3);
}
把返回值强转成了int16_t类型的有符号数。
接下来我们可以再来研究一下极性的问题,如果这个方向和你想要的不一致的话,可以修改一下极性。
在硬件层面上,我们可以直接把A、B相的引脚换一下位置。
在软件层面上,我们可以把任意一个极性反转一下,方向就会反过来。如果两个极性都反转,那极性还是会保持不变。
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Falling);
编码器测速代码
如果我们想用这个编码器来测速的话,就可以在固定的闸门时间,读一次CNT,然后把CNT清零。
//读取CNT,清零CNT。
int16_t Encoder_Get()
{
int16_t Temp;
Temp = TIM_GetCounter(TIM3);
TIM_SetCounter(TIM3,0);
return Temp;
}