免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 8537 | 回复: 4
打印 上一主题 下一主题

哪位大哥做过旋转编码开关程序帮忙看一下! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-08-16 16:43 |只看该作者 |倒序浏览
哪位大哥做过旋转编码开关程序帮忙看一下!
我最近在做旋转编码开关驱动程序,碰到一点问题,请高手帮忙看一下:
是基于2410 linux2.6内核的
旋转编码开关运动周期的时序为
顺时针运动:     A B     逆时针运动:     A B
                              1 1                                    1 1
                              0 1                                    1 0
                              0 0                                    0 0
                              1 0                                    0 1

我把当前的A,B输出值保存起来,与下一个A,B输出值做比较,得出运动方向(如果A,B输出11后输出01,则为顺时针;如果输出11后马上输出10,则为逆时针),

我采用的是双边缘中断方式,其中A接到INT16(GPIOG,接到INT8(GPIOG0),以下是我的驱动程序中的中断处理函数

static unsigned int inc[] = {0,0,0,0};
static unsigned int dec[] = {0,0,0,0};
//static int a=0;
unsigned int right=0, left=0,irq_num=0;
static  irqreturn_t  buttons2_irq(int irq, void *dev_id, struct pt_regs *reg)
{
unsigned int gpg_con2,gpg_dat2,gpg_up2;
unsigned long flags;
disable_irq(irq);
irq_num = irq_num + 1;
//local_irq_save(flags);
unsigned int k1 = 0,k2 = 0;
gpg_con2=readl(gpbase+0x60); //取出G端口控制字寄存器值
  gpg_dat2=readl(gpbase+0x64); // 取出G端口数据寄存器值
  gpg_up2=readl(gpbase+0x6;  // 取出G端口上拉寄存器值
  writel(gpg_con2 & 0xfffcfffc,gpbase+0x60);//G端口中G0、G8管脚设为输入模式
  writel(gpg_up2 | 0x0101,gpbase+0x6;
k1 = s3c2410_gpio_getpin(S3C2410_GPG;
k2 = s3c2410_gpio_getpin(S3C2410_GPG0);
writel(gpg_con2 & 0xfffefffe,gpbase+0x60);//G端口中G0、G8管脚设为中断模式
  set_irq_type(INC_IRQ,IRQT_BOTHEDGE);
  set_irq_type(DEC_IRQ,IRQT_BOTHEDGE);
  //printk("%x,%x\n",k1,k2);
  inc[3] = k1;
  dec[3] = k2;
  if((inc[0]==0x100) && (dec[0]==1)){              //1
   if((inc[1]==0) && (dec[1]==1)){
    if((inc[2]==0) && (dec[2]==0)){
     if((inc[3]==0x100) && (dec[3]==0)){
      right = 1;
      left = 0;
     }
    }
   }
  }
if((inc[0]==0x100) && (dec[0]==1)){              //2
   if((inc[1]==0x100) && (dec[1]==0)){
    if((inc[2]==0) && (dec[2]==0)){
     if((inc[3]==0) && (dec[3]==1)){
      right = 0;
      left = 1;
     }
    }
   }
  }
if((inc[0]==0) && (dec[0]==1)){              //3
   if((inc[1]==0) && (dec[1]==0)){
    if((inc[2]==0x100) && (dec[2]==0)){
     if((inc[3]==0x100) && (dec[3]==1)){
      right = 1;
      left = 0;
     }
    }
   }
  }
  if((inc[0]==0x100) && (dec[0]==0)){              //4
   if((inc[1]==0) && (dec[1]==0)){
    if((inc[2]==0) && (dec[2]==1)){
     if((inc[3]==0x100) && (dec[3]==1)){
      right = 0;
      left = 1;
     }
    }
   }
  }
  if((inc[0]==0) && (dec[0]==0)){             //5
  if((inc[1]==0x100) && (dec[1]==0)){
    if((inc[2]==0x100) && (dec[2]==1)){
     if((inc[3]==0) && (dec[3]==1)){
      right = 1;
      left = 0;
     }
    }
   }
  }

  if((inc[0]==0) && (dec[0]==0)){              //6
  if((inc[1]==0) && (dec[1]==1)){
    if((inc[2]==0x100) && (dec[2]==1)){
     if((inc[3]==0x100) && (dec[3]==0)){
      right = 0;
      left = 1;
    }
    }
   }
  }
  if((inc[0]==0x100) && (dec[0]==0)){             //7
   if((inc[1]==0x100) && (dec[1]==1)){
    if((inc[2]==0) && (dec[2]==1)){
     if((inc[3]==0) && (dec[3]==0)){
      right = 1;
      left = 0;
     }
    }
    }
  }
  if((inc[0]==0) && (dec[0]==1)){              //8
  if((inc[1]==0x100) && (dec[1]==1)){
    if((inc[2]==0x100) && (dec[2]==0)){
     if((inc[3]==0) && (dec[3]==0)){
      right = 0;
      left = 1;
     }
    }
   }
  }
  inc[0] = inc[1];
dec[0] = dec[1];
inc[1] = inc[2];
dec[1] = dec[2];
inc[2] = inc[3];
dec[2] = dec[3];  
  if(irq_num==1){  
if(right==1)
  key_value = 0x14;//int=20,正向递增
else if(left==1)
  key_value = 0x15;//int=21,逆向递减
ready = 1;
  wake_up_interruptible(&buttons_wait);
}
else
  irq_num = 0;   
  enable_irq(irq);
//local_irq_restore(flags);
return IRQ_HANDLED;
}
我是对4种状态一起比较的
我按上面处理方法能正常输出,也不会出现误码,只是在转换方向时,不能立即变向,而是在两次中断后在换过来,
当我只取其中两位分别比较时,能立即转换方向,但会出现误码(即出现反向的输出值)
请高手帮忙指点一下,或提供一下这方面的经验,在此感激不尽!谢谢!

论坛徽章:
0
2 [报告]
发表于 2007-08-17 01:23 |只看该作者
PIC的芯片好多都具有自动解这种正交编码的能力,
如果转速比较快的话,是否可以考虑不用系统cpu做这件事,外扩一个微处理器
或者加一个Index校正(PIC就是这样做的)。

论坛徽章:
0
3 [报告]
发表于 2007-08-17 09:11 |只看该作者
谢谢!
不过,我现在不大可能另增加PIC,我再想想办法!

论坛徽章:
0
4 [报告]
发表于 2015-04-12 21:51 |只看该作者
这位大哥,我也刚遇到你这样的问题!!你解决了没有?

论坛徽章:
0
5 [报告]
发表于 2015-04-13 14:48 |只看该作者
这种叫正交编码器(QEI),用STM32的TIMER做(它有QEI模式)或者用FPGA自己做合适。软件中断计数这玩法实在不怎么靠谱的。
我们公司生成光栅尺的,也是这种接口,有同事为省成本做过这种测试,结果当然是走不通,只要你手一抖动,速度就会快得中断忙不过来。
除非你有机构带着保证不会速度不稳,要求的速度也不高,否则不太可能用软件中断来做。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP