哪位大哥做过旋转编码开关程序帮忙看一下!
哪位大哥做过旋转编码开关程序帮忙看一下!
我最近在做旋转编码开关驱动程序,碰到一点问题,请高手帮忙看一下:
是基于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种状态一起比较的
我按上面处理方法能正常输出,也不会出现误码,只是在转换方向时,不能立即变向,而是在两次中断后在换过来,
当我只取其中两位分别比较时,能立即转换方向,但会出现误码(即出现反向的输出值)
请高手帮忙指点一下,或提供一下这方面的经验,在此感激不尽!谢谢!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
PIC的芯片好多都具有自动解这种正交编码的能力,
如果转速比较快的话,是否可以考虑不用系统cpu做这件事,外扩一个微处理器
或者加一个Index校正(PIC就是这样做的)。
谢谢!
不过,我现在不大可能另增加PIC,我再想想办法!
这位大哥,我也刚遇到你这样的问题!!你解决了没有?
这种叫正交编码器(QEI),用STM32的TIMER做(它有QEI模式)或者用FPGA自己做合适。软件中断计数这玩法实在不怎么靠谱的。
我们公司生成光栅尺的,也是这种接口,有同事为省成本做过这种测试,结果当然是走不通,只要你手一抖动,速度就会快得中断忙不过来。
除非你有机构带着保证不会速度不稳,要求的速度也不高,否则不太可能用软件中断来做。