fangmcu 发表于 2009-4-20 09:25:20

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

谢谢!!

fangmcu 发表于 2009-4-20 11:06:00

顶一顶!!

tclandmei 发表于 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;
}

fangmcu 发表于 2009-4-20 11:30:25

谢谢!!慢慢研究一下!!!

tclandmei 发表于 2009-4-20 11:51:22

2位为1表示后退(i = i | 0x04;) !
3位为1表示前进(i = i | 0x08;) !

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

tclandmei 发表于 2009-4-20 11:57:20

当然查询不能太慢!

cqfeiyu 发表于 2009-4-20 12:05:57

采用中断方式完全能满足

ilan2003 发表于 2009-4-20 12:09:39

还是用个CPLD采集 然后 AVR读取 这样可靠一点 单片接负担小点

Gorgon_Meducer 发表于 2009-4-20 12:30:27

楼上的都太复杂了……
直接用两个外中断+两个普通端口:
比如INT0+Pxn1INT1+Pxn2

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

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

……

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

tclandmei 发表于 2009-4-20 13:03:37

资源少的时候,如中断少的查询还是比较好!
我用89s52用查询做三个旋转编码器还可以!

jiaxinhui 发表于 2009-4-20 13:11:16

最好先用电路把信号处理一下,然后送到单片机,那样比较好点。。。。。

fangmcu 发表于 2009-4-20 14:57:53

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

fangmcu 发表于 2009-4-20 20:52:38

“聪明孩子”,在吗??

wahaha 发表于 2009-4-20 21:57:11

前几天利用Mega128做了光栅尺的计数器
A+ B+A- B-   接到单片机的外部中断(上升沿触发中断)
另外B+接到单片机的普通IO口
在A+对应的中断程序里判断B+对应的电平状态来判断光栅尺的方向

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

wahaha 发表于 2009-4-20 22:02:25

另外还发现单片机有发热的状态~~~
不过应该属于正常的范围之内~

wahaha 发表于 2009-4-22 20:47:41

呵呵 没人接棒 接着来说说了啊~~

Alexkey 发表于 2009-4-22 22:09:58

用LM3S带正交编码功能的可以非常容易做到,我们以前也有用AVR做的,读两个码盘的数据,占用大量CPU时间,影响CPU干其他事情,还容易出现丢码。
后来尝试使用LM3S,发现正交编码功能非常好用,不丢码也几乎不占用CPU时间。

Qhjh 发表于 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,建议有空时一定去看看邱关源的书,俺和他同宗.

Gorgon_Meducer 发表于 2009-4-22 22:15:38

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

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

Gorgon_Meducer 发表于 2009-4-22 22:17:34

to【17楼】 Qhjh
    两个通道用一个M88就可以了……为什么要用M64……4倍频不需要任何额外硬件……只要使用引脚电平变化中断配合INT0和INT1就可以实现……

czzhouyun 发表于 2009-4-22 22:24:58

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

robinyuan 发表于 2009-4-22 22:44:12

傻孩子的方法正解

远距离可用非门增强

Qhjh 发表于 2009-4-22 22:45:53

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

fangmcu 发表于 2009-4-22 23:28:14

谢谢“傻孩子”!!能否说一说,用Z相校正的思路!!

heky 发表于 2009-4-23 00:10:06

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

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

ilan2003 发表于 2009-4-23 08:39:04

台湾的伺服电机的光电编码器用的是CPLD实现的,电子最快的时候3000转

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

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


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

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

fangmcu 发表于 2009-4-25 09:24:19

谢谢"tclandmei 小罗",我不是太看得明白你的程序,能否说一说思路!!

tclandmei 发表于 2009-4-25 16:59:28

太久没有看和用这个函数了!
有点忘!回去看看明天再说说!

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

tclandmei 发表于 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;
}

vv3g 发表于 2009-7-13 09:14:18

继续学习

xuelang1984 发表于 2009-8-14 07:06:35

xxcciov 发表于 2011-6-15 19:58:20

mark

yaya001 发表于 2011-6-15 22:02:31

mark

ohhoheihei 发表于 2013-1-6 16:26:15

谢谢,正好用的着

baikenor 发表于 2016-10-27 15:27:06

Gorgon_Meducer 发表于 2009-4-20 12:30
楼上的都太复杂了……
直接用两个外中断+两个普通端口:
比如INT0+Pxn1INT1+Pxn2


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

Gorgon_Meducer 发表于 2016-11-3 18:35:39

baikenor 发表于 2016-10-27 15:27
大侠,如果外中断一直被触发,那么主程序里面的程序(就是非中断的程序)怎么执行呢?谢谢! ...

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

baikenor 发表于 2016-11-7 16:31:03

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

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

Gorgon_Meducer 发表于 2016-12-2 15:49:09

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

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

baikenor 发表于 2016-12-4 06:18:06

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

大侠,如果是10khz频率,单片机是在12MHZ下运行的MEGA16,并且MEGA16还有每50ms通过串口以9600波特率发送20个字节的任务,具体的时间消耗应该怎样计算呢,一般单片机程序消耗时间应该怎样计算呢?请大侠给个思路,谢谢!
页: [1]
查看完整版本: 我现在想用AVR单片机读取两个旋转编码器,要求是AB相输入的,频率不高4K左右,要考虑速