搜索
bottom↓
回复: 38

我现在想用AVR单片机读取两个旋转编码器,要求是AB相输入的,频率不高4K左右,要考虑速

[复制链接]

出0入8汤圆

发表于 2009-4-20 09:25:20 | 显示全部楼层 |阅读模式
谢谢!!

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入8汤圆

 楼主| 发表于 2009-4-20 11:06:00 | 显示全部楼层
顶一顶!!

出0入0汤圆

发表于 2009-4-20 11:13:57 | 显示全部楼层
void EncoderDetect(uchar *p, uchar pinsta)
{
/*************************************************************
   _____      ____      ____           ____      ____
A      |____|    |____|    |____I____|    |____|    |____
                                 I
   _______      ____      ____   I   ____      ____
B        |____|    |____|    |__I__|    |____|    |______
                                 I
            前进                           后退
        -------->                         <---------
*************************************************************/
    uchar cnt;
    uchar i = *p;

    cnt = i & 0x0f;
    i = ((i >> 4) & 0x03);
    pinsta = pinsta & 0x03;
   
    cnt++;
    {
        if (cnt == 1) {
            if(pinsta != 3) {goto EncoderDetect_LAB0;}
        }else if (cnt == 2) {
            if(pinsta == 3) {cnt--; goto EncoderDetect_LAB2;}
            if(pinsta == 0) {goto EncoderDetect_LAB0;}
            i = pinsta;
        }else if (cnt == 3) {
            if(pinsta == 0) {
                if(i == 2) {i |= 0x04; goto EncoderDetect_LAB1;}
                else if(i == 1) {goto EncoderDetect_LAB1;}
                goto EncoderDetect_LAB0;
            }

            if(pinsta != 3) {cnt--; goto EncoderDetect_LAB2;}
            goto EncoderDetect_LAB0;
EncoderDetect_LAB1:
            i = i | 0x08;
        }else {
EncoderDetect_LAB0:
            cnt = 0;
        }
    }
EncoderDetect_LAB2:
    *p = (i << 4) | cnt;
}

出0入8汤圆

 楼主| 发表于 2009-4-20 11:30:25 | 显示全部楼层
谢谢!!慢慢研究一下!!!

出0入0汤圆

发表于 2009-4-20 11:51:22 | 显示全部楼层
2位为1表示后退(i = i | 0x04;) !
3位为1表示前进(i = i | 0x08;) !

放在主程序检测就行!
*p表示旋转编码器缓冲!
pinsta低两位表示AB状态!

出0入0汤圆

发表于 2009-4-20 11:57:20 | 显示全部楼层
当然查询不能太慢!

出0入0汤圆

发表于 2009-4-20 12:05:57 | 显示全部楼层
采用中断方式完全能满足

出0入4汤圆

发表于 2009-4-20 12:09:39 | 显示全部楼层
还是用个CPLD采集 然后 AVR读取 这样可靠一点 单片接负担小点

出0入296汤圆

发表于 2009-4-20 12:30:27 | 显示全部楼层
楼上的都太复杂了……
直接用两个外中断+两个普通端口:
比如INT0+Pxn1  INT1+Pxn2

外中断触发从上升沿和下降沿中任选一个:然后,判断Pxn的电平,高电平计数器增加;低电平计数器减少;

如果想两倍频:那么外中断的触发选择双边沿触发:然后判断Pxn的电平和INTn电平相同的,计数器增加;不相同的计数器减小……

……

用AVR可以轻松应付,不过记得在外中断中开欠套,而且,最好系统跑16M以上频率……

出0入0汤圆

发表于 2009-4-20 13:03:37 | 显示全部楼层
资源少的时候,如中断少的查询还是比较好!
我用89s52用查询做三个旋转编码器还可以!

出0入0汤圆

发表于 2009-4-20 13:11:16 | 显示全部楼层
最好先用电路把信号处理一下,然后送到单片机,那样比较好点。。。。。

出0入8汤圆

 楼主| 发表于 2009-4-20 14:57:53 | 显示全部楼层
收获了,谢谢各位!!
1、如果硬件处理的话,是不是在其I/O口加上一个103的电容就可以??
2、我也正在看“聪明孩子”你的书,你的书写得很好,看你的书好象看小说,不闷!!
按的书上的做法是,进入外部中断后,判断普通I/O口的电平来确定加数还是减数!!如何提高抗干扰,我的
想法在进入中断后,多次判断I/O的电平来确定是否有效,但是这样就降低速度怕会提脉冲!!你有什么好建议
谢谢!!

出0入8汤圆

 楼主| 发表于 2009-4-20 20:52:38 | 显示全部楼层
“聪明孩子”,在吗??

出200入0汤圆

发表于 2009-4-20 21:57:11 | 显示全部楼层
前几天利用Mega128做了光栅尺的计数器
A+ B+  A- B-   接到单片机的外部中断(上升沿触发中断)  
另外B+接到单片机的普通IO口
在A+对应的中断程序里判断B+对应的电平状态来判断光栅尺的方向

经过测试发现对于计数没有问题 不会丢失
但是好像对于方向的判断有点问题 我发现光栅尺朝一个方向运动的时候  检测到B+的电平不稳定  一会高一会低
呵呵  现在手头没程序 只能这么说说~~

出200入0汤圆

发表于 2009-4-20 22:02:25 | 显示全部楼层
另外还发现单片机有发热的状态~~~
不过应该属于正常的范围之内~

出200入0汤圆

发表于 2009-4-22 20:47:41 | 显示全部楼层
呵呵 没人接棒 接着来说说了啊~~

出0入0汤圆

发表于 2009-4-22 22:09:58 | 显示全部楼层
用LM3S带正交编码功能的可以非常容易做到,我们以前也有用AVR做的,读两个码盘的数据,占用大量CPU时间,影响CPU干其他事情,还容易出现丢码。
后来尝试使用LM3S,发现正交编码功能非常好用,不丢码也几乎不占用CPU时间。

出0入0汤圆

发表于 2009-4-22 22:10:38 | 显示全部楼层
1.加个74HC14 为什么呢? 因为假如做到4倍频,后面还要加个74HC86,所以是去扰+整形用(RC还是要的).然后再用4个INTX,4个普通GPIO.中断方式.非中断方式,就单独用个核,整个绝对式的也是不错的方式.--指4倍频.
2.如此这般,2个编码器.4倍频的实现就相当简单包括软件上.用M64/128做,不要可惜成本.或者中断扩展,再爬出几个GPIO来,呵呵.
3.最最容易的直接用STM32做,这个片子是ST为工控专门下的蛋.直接支持.(AVR没有什么优势.片上外设太少了).
4.俺的方法超爽.俺点到此,想通了,不用谢俺,谢谢你自己.对楼主加个103,建议有空时一定去看看邱关源的书,俺和他同宗.

出0入296汤圆

发表于 2009-4-22 22:15:38 | 显示全部楼层
to 【12楼】 fangmcu 方谭
    抗干扰的问题……如果这个系统存在干扰,建议你不要使用中断方式……查询方式最好……
    不过说实话……一般用到编码器的场合,都应该使用屏蔽线,并保证信号良好……如果你想降低干扰,可以考虑
在编码器的AB线上增加上拉电阻……或者通过普通光耦(非高速光耦合)隔离的方式来滤掉较高频率的毛刺……
    不知道你的应用场合如何,丢脉冲是很正常的,但是可以通过Z信号来校正。我应用的场合干扰算是比较夸张的,
都是继电器打来打去……一般不敢用长的普通导线……线的长度也在20cm以内。降低干扰固然重要,但是对于编码器
来说必要的校正才是王道。

    能不能叫我“傻孩子”……

出0入296汤圆

发表于 2009-4-22 22:17:34 | 显示全部楼层
to【17楼】 Qhjh
    两个通道用一个M88就可以了……为什么要用M64……4倍频不需要任何额外硬件……只要使用引脚电平变化中断配合INT0和INT1就可以实现……

出0入84汤圆

发表于 2009-4-22 22:24:58 | 显示全部楼层
用硬件先处理下,如果不处理肯定会丢脉冲的,如果是远距离的接成两路485的,硬件处理可参照以下方法,正向的时候一路输出脉冲另一路输出高电平,反向的时候反过来,这样只要做正向反向计数既可,对照编码器的最高速度调整电路参数,这样可保证在有电工作器件不丢脉冲,当然停电后就不得而知了,这种处理在闸控上最少用了20年了

出0入0汤圆

发表于 2009-4-22 22:44:12 | 显示全部楼层
傻孩子的方法正解

远距离可用非门增强

出0入0汤圆

发表于 2009-4-22 22:45:53 | 显示全部楼层
1.现在做的产品上AVR已经不用了,谢谢指点.假如M88有多个中断的话,的确是个好事情.
2.加个86,软件容易搞,每个边沿都能统一到上(/或统一到下)沿触发.AVR的电平变化中断,用在这个方面,让人耳目一新,好方法.

出0入8汤圆

 楼主| 发表于 2009-4-22 23:28:14 | 显示全部楼层
谢谢“傻孩子”!!能否说一说,用Z相校正的思路!!

出0入0汤圆

发表于 2009-4-23 00:10:06 | 显示全部楼层
为什么要限定avr呢,现在32位arm哪个没有ab相接口。你们考虑问题可能还偏简单,看看伺服锁住时候的编码器信号看看,抖得要命。频率绝对大于4K。到时死都不知道怎么死。

【16楼】 Alexkey 提得就是很好的简易。能硬件做肯定选硬件。方法归方法,但是你会发现做的很累。。。。

出0入4汤圆

发表于 2009-4-23 08:39:04 | 显示全部楼层
台湾的伺服电机的光电编码器用的是CPLD实现的,电子最快的时候3000转

3000/60*1000*2=100k
伺服驱动器还要实现四倍频

楼主所说的4k 那应该是正常运行的时候,如果在抖动的情况下估计不止4k 瞬间的频率可能很高。就有可能会丢脉冲


还有我觉得中断可能还是查询来的快。中断进进出出要开销时钟的。

但是用了查询之后,最好其他事情不要做了。

出0入8汤圆

 楼主| 发表于 2009-4-25 09:24:19 | 显示全部楼层
谢谢"tclandmei 小罗",我不是太看得明白你的程序,能否说一说思路!!

出0入0汤圆

发表于 2009-4-25 16:59:28 | 显示全部楼层
太久没有看和用这个函数了!
有点忘!回去看看明天再说说!

哈哈!都是没有作好注释的祸!

出0入0汤圆

发表于 2009-4-25 17:34:37 | 显示全部楼层
/*
*   先说一下思路:
*
*   typedef struct {   
*        ucahr cnt; // cnt == 1~3表示AB的三个状态
*        uchar pinstabk; // 记录上次AB
*        uchar encoderout; // 解码输出
*   }EncoderBuff;
*   p 指向的是上面的数据类型。我为了省RAM所以写可能有点不好理解,用一个字节表示了
*   
*/
void EncoderDetect(uchar *p, uchar pinsta)
{
/*************************************************************
   ___1__      ____      ____           ____      ____
A       |____|    |____|    |____I____|    |____|    |____
                                 I
   ___1____      ____      ____   I   ____      ____
B         |____|    |____|    |__I__|    |____|    |______
                                 I
            前进                           后退
        -------->                         <---------
*************************************************************/
    uchar cnt;
    uchar i = *p;

    cnt = i & 0x0f;
    i = ((i >> 4) & 0x03);
    pinsta = pinsta & 0x03;
   
    cnt++;
    {
        if (cnt == 1) { // cnt == 1表示要检测到AB == 11作为起始状态才进行后续
            if(pinsta != 3) { // 表示状态没有变,cnt = 0,下次继续检测cnt == 1的状态
                goto EncoderDetect_LAB0;
            }
        }else if (cnt == 2) { // cnt == 2表示AB == 10 ,AB == 01, AB == 00
            if(pinsta == 3) { // 起始状态AB == 11没有变化
                cnt--;
                goto EncoderDetect_LAB2;
            }

            if(pinsta == 0) { // AB == 00, 丢弃本帧
                goto EncoderDetect_LAB0;
            }
            i = pinsta; // 记录AB == 10 ,AB == 01,
        }else if (cnt == 3) { // 已经记录了AB == 10 ,AB == 01,
            if(pinsta == 0) { // 当AB == 00,则一帧 11 -> (10 或 01) -> 00 被检测
                /* 与上一次cnt == 2比较AB,如果相同表示一帧完整解码输出,不同丢弃本帧*/
                if(i == 2) {
                     i |= 0x04; // 输出减
                     goto EncoderDetect_LAB1;
                    }else if(i == 1) {
                         goto EncoderDetect_LAB1;
                }
                goto EncoderDetect_LAB0;
            }

            if(pinsta != 3) { // 如果AB没有变为00,则继续等待检测
                cnt--;
                goto EncoderDetect_LAB2;
            }
            goto EncoderDetect_LAB0; // AB == 11 ,丢弃本帧
EncoderDetect_LAB1:
            i = i | 0x08; // 输出加
        }else {
EncoderDetect_LAB0:
            cnt = 0;
        }
    }
EncoderDetect_LAB2:
    *p = (i << 4) | cnt;
}

出0入0汤圆

发表于 2009-7-13 09:14:18 | 显示全部楼层
继续学习

出0入0汤圆

发表于 2009-8-14 07:06:35 | 显示全部楼层

出0入0汤圆

发表于 2011-6-15 19:58:20 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-15 22:02:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-1-6 16:26:15 | 显示全部楼层
谢谢,正好用的着

出0入0汤圆

发表于 2016-10-27 15:27:06 | 显示全部楼层
Gorgon_Meducer 发表于 2009-4-20 12:30
楼上的都太复杂了……
直接用两个外中断+两个普通端口:
比如INT0+Pxn1  INT1+Pxn2

大侠,如果外中断一直被触发,那么主程序里面的程序(就是非中断的程序)怎么执行呢?谢谢!

出0入296汤圆

发表于 2016-11-3 18:35:39 | 显示全部楼层
baikenor 发表于 2016-10-27 15:27
大侠,如果外中断一直被触发,那么主程序里面的程序(就是非中断的程序)怎么执行呢?谢谢! ...

如果一直触发,那么就要看看这种一直触发是否合理了。脱离应用考虑极端情况是意义不大的。
你是否可以描述下具体的应用场景呢?

出0入0汤圆

发表于 2016-11-7 16:31:03 | 显示全部楼层
Gorgon_Meducer 发表于 2016-11-3 18:35
如果一直触发,那么就要看看这种一直触发是否合理了。脱离应用考虑极端情况是意义不大的。
你是否可以描 ...

受宠若惊!  大侠竟然回复了!  我看到大侠的方案是把脉冲接到中断引脚上,如果一直有脉冲,MCU还有时间处理其他的工作吗?谢谢!

出0入296汤圆

发表于 2016-12-2 15:49:09 | 显示全部楼层
baikenor 发表于 2016-11-7 16:31
受宠若惊!  大侠竟然回复了!  我看到大侠的方案是把脉冲接到中断引脚上,如果一直有脉冲,MCU还有时间处 ...

这里就是一个典型的“凭感觉得出结论的例子”——嵌入式开发是可以定量分析的,不能凭感觉。
就这个例子来说,你只说一只有脉冲,这个谁都没有办法回答你的问题——脉冲频率是多少?处理器主频是多少,处理器的指令周期和主频是什么关系(早期的51,指令周期和主频是 12分之一的关系)。有了这些信息,我们才有可能定性的评估你这个问题。如果你只单纯从人类的感官来思考——作为人类,也许1K已经很快了,也许10K已经很快了,但是对于一个跑12M的CPU来说,可能仍然是慢动作。所以针对你的问题,具体看了。

出0入0汤圆

发表于 2016-12-4 06:18:06 | 显示全部楼层
Gorgon_Meducer 发表于 2016-12-2 15:49
这里就是一个典型的“凭感觉得出结论的例子”——嵌入式开发是可以定量分析的,不能凭感觉。
就这个例子 ...

大侠,如果是10khz频率,单片机是在12MHZ下运行的MEGA16,并且MEGA16还有每50ms通过串口以9600波特率发送20个字节的任务,具体的时间消耗应该怎样计算呢,一般单片机程序消耗时间应该怎样计算呢?请大侠给个思路,谢谢!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-16 13:49

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表