用过旋转编码器的进来指导下,这样做能减少误判吗?

[复制链接]
楼主: Jack602
手机看帖
扫描二维码
随时随地手机跟帖
zy19860818| | 2010-11-13 08:51 | 显示全部楼层
鼠标中混轮上的也是一种啊
200804121359316743.jpg
照片 002.jpg
照片 001.jpg

使用特权

评论回复
mmax| | 2010-11-13 08:54 | 显示全部楼层
如果楼主怕精度不够,就用两相四倍频。

A上升沿、下降沿,B的上升沿,B的下降沿都记一次数。(每个沿的时候都要判断另一个信号电平来判断方向)

比你只用上升沿多一倍的分辨率。

使用特权

评论回复
eydj2008| | 2010-11-13 09:08 | 显示全部楼层
本帖最后由 eydj2008 于 2010-11-13 11:21 编辑

yewuyi 分析得 很好 很好理解  能行得通
我来总结一下:
1.可以检测其中一线 我们假设为A线 可以检测上升 或是下降沿中断 中断设置为最高优先级(占用最多不过10个指令周期 已经应用)  这里以上升沿为例
a.检测到A线上升沿触发了中断,那么再检测B线的电平为高(反转)或者为低(正转) 来判断是正还是反转 (以上图为例) 这样就可以在一个齿之间 判断是正转还是反转了,精度与齿数相同。
b.也有结构(每个齿不同)和编码器做得不够好的情况,比如:A线的上升沿 刚好又是B线的 上升沿或是下降沿 这样无论你怎么是检测B线 要么都为高,要么都为低.这种是要避免的情况(一般这样情况很少,可以改善编码器与编码盘见c)
c.编码器与编码盘 最佳的做法是 编码盘  编码盘齿间距==二个光电检测中心距离/3*2  或是/5*2 /7*2 。。。 刚好正交  就可以解决这个问题
且编码盘的凹凸齿距 相等
d.我看了老外的程序 并没有加滤波(用中断不好滤波,),当然加上更好(肪冲宽度远小于齿距的,放弃不计数,是干扰) 会多占几个时钟周期来滤波。
e.个人感觉用定时查询方式不是很理想,因为它只能检测电平。而电平有四种情况
正转    A        0        1        1        0
            B        0        0        1        1
                                       
反转   A        0        0        1        1
          B        0        1        1        0
这样占用CPU时间过多 定时查询的时候,会出现四种情况 还得判断出来。
附 300R/MIN  100齿  每个齿的时间是2ms 定时周期至少得高出这个5倍以上 <400us

使用特权

评论回复
自然的天逸| | 2010-11-13 11:22 | 显示全部楼层
/*贴上代码*/



#include   <intrins.h>                                                      /*包含库函数*/
#include"SH79F166.H"
#include"RotaryEncoder.H"
#define KeyH P4                                                             /*按键扫描水平和垂直输入端口*/
#define KeyV P3
#define KeyVPin P3CR                                                        /*垂直输入输入输出*/
INT16U        KeyData=0;   
INT8U  KeyTime=0;                                                           /*按键记时去抖*/                                                                                       
bit     RrR=1;
bit     LlL=1;
sbit    Rpin=P0^4;                                                         /*输入端口右*/
sbit    Lpin=P0^5;                                                         /*输入端口左*/

/**************************************************************************
**函数名:InitCpu
**函数功能:初始化单片机
**参数:    无
**返回:    无
***************************************************************************/
void InitRE(void)
{
    CLKCON=0x00;
    P4CR = 0X00;                                                            /*输入模式*/
    P4PCR |= 0X0F;                                                          /*P40-P41 输入模式开上拉*/
    P3CR |= 0X0F;                                                           /*输出模式*/
    P3&=~0X0F;                                                              /*P30-P34 输出模式至地*/
    T2CON|=0X00;
    T2MOD=0x00;                                                             /*定时器模式16位计速模式*/
    RCAP2H=(65536-T2IME)/256;                                               /*定时时间*/
    RCAP2L=(65536-T2IME)%256;
        ET2=1;                                                                  /*开定时器2中断*/                                                                                                                               
        EA=1;                                                                   /*开中断*/
    TR2=1;
}
/**************************************************************************
**函数名:main
**函数功能:主函数
**参数:    无
**返回:    无
***************************************************************************/
void main(void)
{   INT8U i;
    InitRE();
    for(;;)
    {
        RSTSTAT=0X00;
        i=RotaryEncoder();
                if(i>0)
                {
                   _nop_();
                   _nop_();
                   _nop_();
                   _nop_();
                }
                _nop_();
                _nop_();
                i=KeySan();
                if(i)
            {
                _nop_();
                _nop_();
                    _nop_();
                }
                _nop_();
                _nop_();
       
    }   
}
/**************************************************************************
**函数名:ISR_Timer2
**函数功能:定时器2中断
**参数:    无
**返回:    无
***************************************************************************/
void ISR_Timer2(void) interrupt 5
{
        INT16U        CoderCounter=10000;                                                                    /*编码器计*/
            static        INT8U         Codings_BiaoZi=0;
        TF2=0;                                                              /*清中断标志*/                               
                   if (1 == Codings_BiaoZi )                                                                /*有转动*/
                   {               
                                     if((Rpin!=RrR))                                                    /*右转*/
                                     {                                       
                                             CoderCounter++;
                                         Codings_BiaoZi=2;                                    
                                         RrR=Rpin;
                                     }
                                     else
                                     {
                                              CoderCounter--;                                        /*左转*/
                                         Codings_BiaoZi=2;
                                         LlL=Lpin;       
                                    }
                 }
                else if ( Codings_BiaoZi == 3)                                      /*第二个脉冲来波形转换完毕*/
                {
                        if((Lpin==LlL)&&(Rpin==RrR))                                                /*都为高才释放标志*/
                        {
                                Codings_BiaoZi=0;
                        }
                }
                else if ((Codings_BiaoZi == 0)||(Codings_BiaoZi == 2))
                   {
                         if((LlL != Lpin)||(RrR != Rpin))                                                /*A相和B相任何有一方高电平说明有转动*/
                        {
                                    if(Codings_BiaoZi == 0)Codings_BiaoZi=1;
                                    else
                                    {
                                        Codings_BiaoZi = 3;
                                        RrR=Rpin;
                                            LlL=Lpin;
                                    }        
                        }
                   }      
                  
           if(CoderCounter!=10000)                                                                    /*读出定时器2的值*/
           {                if(CoderCounter>10000)
                           {
                               KeyData=CoderRight;                                         /*右转*/
                           }
                           else
                           {
                                KeyData=CoderLeft;                                         /*左转*/
                       }
                       CoderCounter=10000;            
           }       
   KeyTime++;
}
/**************************************************************************
**函数名:RotaryEncoder
**函数功能:旋转编码器扫描返回
**参数:    无
**返回:    左转CoderLeft 右转CoderRight  0 编码器没有转动
***************************************************************************/
INT8U RotaryEncoder(void)
{   INT8U i=0;
    if(KeyData>0)                                                           /*编码器有转动*/
    {
        i=KeyData;
         KeyData=0;
    }
        return i;        
}

使用特权

评论回复
eydj2008| | 2010-11-13 11:29 | 显示全部楼层
本帖最后由 eydj2008 于 2010-11-13 13:28 编辑

楼上的程序  太复杂  不用抗干扰只用简单几条指令就可以
void INIT_IRQ(void)  //检测A双边沿触发中断
{

if (A=1)
{
    if (b=1)
     i++; //编码计数
   else  
     i--;
}
else
{
     if (b=0)
     i++; //编码计数
   else  
     i--;

}

}

使用特权

评论回复
yewuyi| | 2010-11-13 12:18 | 显示全部楼层
15# Jack602



armmage的方法是有问题,主要是他没有做倍频检查,检测频率应该高于A相、B相频率值的4倍即能有效防止正反转产生的偏差。

如果A/B频率不高时,以A/B频率的4倍速定时查询A相电平值,如果检测到A相电平发生变化,则可按照类似我在12楼提到的方法进行正反转判断,具体看LZ顶楼的波形图即可明白该如何做了。

使用特权

评论回复
自然的天逸| | 2010-11-13 14:33 | 显示全部楼层
我的程序好用的

使用特权

评论回复
5880527| | 2010-11-13 16:15 | 显示全部楼层
还好,我遇到的都只考虑一个方向旋转

使用特权

评论回复
Jack602|  楼主 | 2010-11-13 21:22 | 显示全部楼层
18# 自然的天逸

用定时器吗? 可以分享几句代码不?

使用特权

评论回复
Jack602|  楼主 | 2010-11-13 21:23 | 显示全部楼层
20# isoar
未命名.JPG

使用特权

评论回复
Jack602|  楼主 | 2010-11-13 21:24 | 显示全部楼层
用不用中断也无所谓,
但是关键是 正负要相抵,而且不能丢脉冲。
这次的状态必须和上次的状态相关,
这样再怎么抖动也不会产生误差。
QuakeGod 发表于 2010-11-13 00:44


我现在正负相抵,不知道什么意思? 程序怎么实现?

使用特权

评论回复
yewuyi| | 2010-11-13 21:33 | 显示全部楼层
没有倍频检测的话,正反转的情况下肯定会有丢脉冲现象,我以前在侃单片机版专门开过一个帖子讨论过,需要的人不放搜老帖子,一看就明白应该怎么做了,而且当时我好像还提供了PIC的示范代码。

使用特权

评论回复
Jack602|  楼主 | 2010-11-14 16:06 | 显示全部楼层
25# eydj2008

问题是51没双边沿触发中断...

使用特权

评论回复
Jack602|  楼主 | 2010-11-14 16:13 | 显示全部楼层
没有倍频检测的话,正反转的情况下肯定会有丢脉冲现象,我以前在侃单片机版专门开过一个帖子讨论过,需要的人不放搜老帖子,一看就明白应该怎么做了,而且当时我好像还提供了PIC的示范代码。 ...
yewuyi 发表于 2010-11-13 21:33


谢谢这位大哥...看看..

使用特权

评论回复
coody| | 2010-11-14 16:40 | 显示全部楼层
25楼,有的51有双边沿中断,比如STC的部分MCU

使用特权

评论回复
月下狂想曲| | 2010-11-14 17:45 | 显示全部楼层
我也在学习这个东西,我用中断,可以检测,但有时会误码,

使用特权

评论回复
Jack602|  楼主 | 2010-11-14 22:07 | 显示全部楼层
感谢LS几位兄弟耐心解答,尤其感谢yewuyi大哥,虽然我还是菜鸟,但第一次感到21IC社区确实是个好地方,让我有更大的学习动力,

我现在用定时2ms查询,如有旋转就记住这一次的状态..与下一次做比较,明天试试看,不知道这样行不行,还请前辈兄弟再指教..如果可以了,奉上代码,让后来人有个很好的参考!便于理解

使用特权

评论回复
月下狂想曲| | 2010-11-16 12:52 | 显示全部楼层
感谢LS几位兄弟耐心解答,尤其感谢yewuyi大哥,虽然我还是菜鸟,但第一次感到21IC社区确实是个好地方,让我有更大的学习动力,

我现在用定时2ms查询,如有旋转就记住这一次的状态..与下一次做比较,明天试试看,不 ...
Jack602 发表于 2010-11-14 22:07


这个方法也可以,我试过,但高速转动时会误码,所以,小弟还是认为中断好一点,快速转与慢速转都可以产生中断

使用特权

评论回复
darling890321| | 2010-11-16 12:52 | 显示全部楼层
哈哈

使用特权

评论回复
Jack602|  楼主 | 2010-11-19 12:08 | 显示全部楼层
本帖最后由 Jack602 于 2011-2-13 20:07 编辑
这个方法也可以,我试过,但高速转动时会误码,所以,小弟还是认为中断好一点,快速转与慢速转都可以产生中断
月下狂想曲 发表于 2010-11-16 12:52


还好..基本不会误码,奉上代码..

bAdd = 0;
bSub = 0;
   if (bVRA != P12)
    {
    bVRA = P12;
    bAdd = 1;                          
   }
   if (bVRB != P13)
     {   
        bVRB = P13;
        bSub = 1;                           
     }
    if ((bAdd) &&(bVRA==0)&& (P12 ^ P13))
     temp++;
   if ((bSub) &&(bVRB==0)&& (P12 ^ P13))
      temp--;      
   EA=1;

其中bvra  和bvrb是状态值,BADD右转,BSUB为左转,本人用过可以..再次感谢大家热心回复,那个感动..

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则