TIM编码器接口
之前我们处理旋转编码器,是转一下中断一次,挺消耗资源的。
我们可以利用TIM的编码器功能,隔一段时间取一下旋转器值使得cnt++或–,以此判断旋转位置以及计算速度,相比中断节约资源。相当于外接了一个有方向的外部时钟。
编码器可以接收正交编码器信号控制cnt自增自减。
通过判断其中一相上升/下降沿时,另一相是高or低电平判断转动方向。
编码器接口判断是正反转,控制cnt++或–。arr设置为65535,这样cnt=0时一自减就变为65535,转为有符号数就是-1.
常用最后一个,精度高。
这里面的内容就是对应AB相的判断。比如图中FP1上升 FP2高电平,若1为A相2为B相,即A在上升时B在高电平,对应反转,因此向下计数。
如果一个信号跳变,另一个信号状态和上次跳变一样说明是毛刺。计数值来回摆动过滤噪声。
代码:基于定时器的可测速编码器
大多数还是基于IC的代码。新函数:TIM_EncoderInterfaceConfig,配置编码器接口。
#include "stm32f10x.h"
void Encoder_Init(){
//rcc, gpio, time base, ic(只配置滤波器和极性), TIM_Cmd 启动
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//滤波器采样,频率越低,采样点数越多,滤波效果越好。不过延迟也越大。采样频率就是内部时钟和这个分频参数共同作用的结果
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
//比如我们想定1s中断一次,CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1),也就是72M / (PSC + 1) / (ARR + 1) = 1
//所以两者赋值可以是10000-1和7200-1,只要两者都在65535以内就行,赋值不唯一
TIM_TimeBaseInitStructure.TIM_Period=65536-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//预分频器值,不分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器值,高级计数器才用
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
//PA6 7对应定时器3,oc channel1 channel2.
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//PA6对应定时器3 ch1
//TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//下面一行配置的极性会覆盖上面的配置,所以这里不用写
TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波消除毛刺,越大效果越好,看需求
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//PA7对应定时器3 ch2
//TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波消除毛刺,越大效果越好,看需求
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
TIM_Cmd(TIM3, ENABLE);
}
uint16_t Encoder_Get(){
return TIM_GetCounter(TIM3);
}
因为转动一格,AB各出现一个下降和一个上升沿,因此±4.
如果想测速,可以在get函数里获取后手动清零,且在main中加一个延时获取,比如1000ms获取一次。
while(1){
OLED_ShowNum(4,1,Encoder_Get(),5);
Delay_ms(1000);
}
不过在主函数中这样写延时会影响其他部分程序的运行,因此最好是写一个中断函数。
void TIM2_IRQHandler(void){
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
cnt=Encoder_Get();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}