机械触点式编码开关,依托 A 相和 B 信任号的相位差来判别旋转方向,脉冲数计数,输出的抱负波形如下图:
实际运用时,其输出的脉冲边缘或许会包括许多毛刺,假如简略的运用上升沿或许下降沿触发,在边缘处会或许发生许多误触发,运用延时等手法虽能缓解,但从办法到成果都有蒙混过关之嫌,不能令人满意。下图是我用示波器随意抓了一个编码开关的下降沿:
为了能够牢靠计数,有必要避开上升沿和下降沿邻近的毛刺,在编码开关输出脉冲信号的脉冲中段取值,如下图所示:
1、A 相和 B 信任号别离送入具有上升/下降沿触发才能的IO,敞开上升沿/下降沿触发中止;
2、在 A 信任号的上升沿/下降沿触发中止中判别 B 相的状况,如上图所示的 T0 时间,得到 B 相当时的值为 0;
3、在 B 信任号的上升沿/下降沿触发中止中判别 A 相的状况,如上图所示的 T1 时间,得到 A 相当时的值为 1;
4、树立一个保存 A 相 和 B 相状况的数组,至少可保存 3 组状况值,若得到的状况值和数组中保存的上一个状况值持平,阐明该次触发为毛刺,则不更新状况数组,例如 T1 时间由 B 信任号触发的中止程序中,判别 A 信任号为 1 状况,与 T0 时间中的 A:0; B:0 状况不同,则更新数组;若 T1 时间后 B 相的上升沿发生毛刺进入中止程序,则由于读取到的 A 相值依然为 1,由于和上一个状况相同,不更新状况数组;
5、如此运用 A 相的边缘触发中止读取 B 相的值,B 相的边缘触发读取 A 相的值,就能够确保取样点坐落没信任号的中心时间;
6、在每次状况数组有更新时判别编码开关的旋转方向,如上图蓝色框内的数值组合呈现时,能够判别编码器 +1,反之,如下图紫色框内的数值组合呈现时,可判别编码器值 -1;
7、当编码器呈现半途改动方向的状况时,其输出的脉冲如下图所示:
能够看到,T1、T2、T3时间编码器发生 +1 的计数脉冲,T5、T6 由于收集到的 A 相和 B 相状况值与 T3 状况没有改动,故不更新状况数组也不做任何处理,到 T7 时间今后开端更新,则 T3、T7、T8 组合发生 -1 的状况组合。整个过程中都不会发生丢计数的状况,另一种编码器改动旋转方向的状况如下:
相似上面的剖析,也不会发生丢计数的状况。下面给出STM32外部触发程序作为参阅:
/* Encoder.c */
signed char Phase_A, Phase_B; //按bit位来贮存A/B相的状况,bit7作为缓存,bit6为最新状况 //值,然后依次是bit5、bit4,需求更新时,运用右移操作,之 //所以运用有符号数,是为了右移时保存bit7的值
void EXTI0_IRQHandler(void)
{
EXTI->PR &= EXTI_PR_PR0; //Clear interrup pending
if(COMP->CSR & COMP_CSR_COMP2OUT) //若编码器直连续入IO,此处改为判别IO状况即可,我使 //用的是比较器输出的值来驱动IO发生外部触发,故为此
{
Phase_B |= 0x80; //Phase_B = 1xxx xxxx
}
else
{
Phase_B &= 0x7F; //Phase_B = 0xxx xxxx
}
if(((Phase_B << 1)^Phase_B) & 0x80) //判别缓存中的bit7位和bit6位是否持平,若不等,更新缓存
{
Phase_B >>= 1;
Phase_A >>= 1;
if( ((Phase_A & 0x70) == 0x30) && ((Phase_B & 0x70) == 0x60) ) //A:0 1 1, B:1 1 0 序列
{
FlashData_Copy.encoder_count += 1;
}
if( ((Phase_A & 0x70) == 0x60) && ((Phase_B & 0x70) == 0x30) ) //A:1 1 0, B:0 1 1 序列
{
FlashData_Copy.encoder_count -= 1;
}
}
}
void EXTI2_TSC_IRQHandler(void)
{
EXTI->PR &= EXTI_PR_PR2; //Clear interrupt pending
if(COMP->CSR & COMP_CSR_COMP1OUT)
{
Phase_A |= 0x80; //Phase_A = 1xxx xxxx
}
else
{
Phase_A &= 0x7F; //Phase_A = 0xxx xxxx
}
if(((Phase_A << 1)^Phase_A) & 0x80)
{
Phase_A >>= 1;
Phase_B >>= 1;
if( ((Phase_A & 0x70) == 0x30) && ((Phase_B & 0x70) == 0x60) )
{
FlashData_Copy.encoder_count += 1;
}
if( ((Phase_A & 0x70) == 0x60) && ((Phase_B & 0x70) == 0x30) )
{
FlashData_Copy.encoder_count -= 1;
}
}
}
/******************************************************************************
EXTI0 and EXTI2 interrupt setup
******************************************************************************/
void setupEXTI0_2(void)
{
/* EXTI0 config */
EXTI->IMR |= EXTI_IMR_MR0;
EXTI->RTSR |= EXTI_RTSR_TR0; //Rising trigger
EXTI->FTSR |= EXTI_FTSR_TR0; //Falling trigger
/* Enable the Selected IRQ Channels ————————————–*/
NVIC->ISER[EXTI0_IRQn >> 0x05] |=
(uint32_t)0x01 << (EXTI0_IRQn & (uint8_t)0x1F);
/* EXTI2 config */
EXTI->IMR |= EXTI_IMR_MR2;
EXTI->RTSR |= EXTI_RTSR_TR2;
EXTI->FTSR |= EXTI_FTSR_TR2;
/* Enable the Selected IRQ Channels ————————————–*/
NV%&&&&&%->ISER[EXTI2_TSC_IRQn >> 0x05] |=
(uint32_t)0x01 << (EXTI2_TSC_IRQn & (uint8_t)0x1F);
}
该计划外围电路简略,无需%&&&&&%滤波,因采样点为脉冲中部,故作业牢靠,在编码器的特定方位做上记号用手随意改动方向和速度做测验,最终总能在编码开关回到原方位时归零,缺陷是需求IO具有上升/下降沿的双向边缘触发才能,以及运用了中止程序占用了部分资源。