STM32正交编码器驱动电机
0赞1。编码器原理
什么是正交?如果两个信号相位相差90度,则这两个信号称为正交。由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向。
这里使用了TI12模式,例如当T1上升沿,T2在低电平时;T1下降沿,T2在高电平时,向上计数,这样的好处是当有毛刺产生的时候,会自动+1 -1过滤掉毛刺。
2。编码器的中断
由于编码器是基于定时器的,所以编码器的中断实际上就是定时器的中断。也就是说定时器是每隔一定时间加一个数(或减一个数 ),当数到达预设值时就产生中断,而编码器是每一个有效脉冲就加一个数(或减一个数 ),当数到达预设值时就产生中断。若预设值为1000则编码器与定时器中断不同的是,当编码器反转时值到达999产生一次中断,而当编码器正转到达0时同 样产生一次中断。在硬件上这两个中断是没法区分的,这也就造成了有种情况的误判。
3。STM32编码器没有考虑的情况
想象一下,如果编码器的预设值为1000,当某次我们使得编码器正转产生中断后,立即反转则又该怎么办呢?根据上面的说法,这时候会产生两次一样的中断。 如果在算法上没有处理的话,极有可能认为是行走了两次正向。但实际上并没有。所以这个时候必须结合方向来判断行走的情况(判断方向使用的是DIR寄存器 位)或者在产生中断后读一次count寄存器位(看看是999还是0,以此来判断当前的方向)。只有上一次为正且这一次同样为正,距离才是相加的。
4。STM32f1系列定时器16位的问题
我用STM32的定时器3工作于编码器方式,可以正常得到编码器位置,但由于现在只有16位计数,位数不够,我想扩展到32位,可以先用定时器内部连接,将定时器3 的溢出送到定时器2,用定时器2做高位,在正转的时候正常,但反向的时候出错。换了个思路,做个每10ms产生一次的中断,在中断中调用下面的代码,下述代码中MAX_COUNT是 比 10ms内可能出现的计数最大值还要大的值,ENCODER_TIM_PERIOD是定时器的period值,最好比MAX_COUNT大,然后定义一个32位的有符号变量,如currentCount,然后每隔10ms执行一次currentCount += Enc_GetCount();只需要去读取currentCount的值就可以得到位移信息了。
s16 Enc_GetCount(void)
{
static u16 lastCount = 0;
u16 curCount = ENCODER_TIM->CNT;
s32 dAngle = curCount - lastCount;
if(dAngle >= MAX_COUNT){
dAngle -= ENCODER_TIM_PERIOD;
}else if(dAngle < -MAX_COUNT){
dAngle += ENCODER_TIM_PERIOD;
}
lastCount = curCount;
return (s16)dAngle;
}
5。其它一些得到的信息
1.编码器有个转速上限,超过这个上限是不能正常工作的,这个是硬件的限制,原则上线数越多转速就越低,这点在选型时要注意,编码器的输出一般是开漏的,所以单片机的io一定要上拉输入状态.
2.定时器初始化好以后,任何时候CNT寄存器的值就是编码器的位置信息,正转他会加反转他会减这部分是不需要软件干预的,初始化时给的TIM_Period 值应该是码盘整圈的刻度值,在减溢出会自动修正为这个数.加超过此数值就回0.
3.如果要扩展成多圈计数需要溢出中断,程序上圈计数加减方向位就行了.
4.每个定时器的输入脚可以通过软件设定滤波
5.应用中如果没有绝对位置信号或者初始化完成后还没有收到绝对位置信号前的计数只能是相对计数.收到绝对位置信号后重新修改一次CNT的值就行了.码盘一般都有零位置信号,结合到定时器捕获输入就行.上电以后要往返运动一下找到这个位置.
6.即便有滤波计数值偶尔也会有出错误的情况,一圈多计一个或少计一个数都是很正常的特别是转速比较高的时候尤其明显,有个绝对位置信号做修正是很有必要的.绝对位置信号不需要一定在零位置点,收到这个信号就将CNT修正为一个固定的数值即可.
7.开启定时器的输入中断可以达到每个步计数都作处理的效果,但是高速运转的时候你可能处理不过来.