找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3990|回复: 14
打印 上一主题 下一主题
收起左侧

ec11编码器谁有好用的单片机代码?现在抖动严重,乱跳 中断方式也步进丢失

  [复制链接]
跳转到指定楼层
楼主
ID:34268 发表于 2022-5-7 18:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
ec11编码器谁有好用的代码共享一下,现在的代码抖动严重,乱跳。用过中断方式也不好用,一样会出现步进丢失。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏7 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:94031 发表于 2022-5-7 19:13 | 只看该作者
要在硬件上下功夫。
回复

使用道具 举报

板凳
ID:149451 发表于 2022-5-7 19:27 | 只看该作者
看看下面这个程序,我把它改在控制LED流水方向上,OK的。注意EC11几个端子的电容是防抖动。
// Header:  编码开关代码   
// File Name: Encoder   
// Author:  李波   
// Date: 2009-04-19  20161129在开发板上完美运行:通过编码器EC11控制流水灯流动
/*========================================  
本代码为编码开关代码,编码开关也就是数字音响中的  
360度旋转的数字音量以及显示器上用的(单键飞梭开  
关)等类似鼠标滚轮的手动计数输入设备。  
我使用的编码开关为5个引脚的,其中2个引脚为按下  
转轮开关(也就相当于鼠标中键)一个接地,另一个P3.4。另外3个引脚用来  
检测旋转方向以及旋转步数的检测端。引脚分别为a,b,c  
b接地;a,c分别接到P3.3和P3.2口并分别接两个10K上拉  
电阻,并且a,c需要分别对地接一个104的电容,否则  
因为编码开关的触点抖动会引起轻微误动作。本程序不  
使用定时器,不占用中断,不使用延时代码,并对每个  
细分步数进行判断,避免一切误动作,性能超级稳定。  
我使用的编码器是APLS的EC11可以参照附件的时序图  
编码器控制流水灯最能说明问题,下面是以一段流水  
灯来演示。  
(单片机为STC89C52)=================*/   
#include <REGX52.H>   
#include <intrins.h>   
#define uint unsigned int   
#define uchar unsigned char   
#define NULL 0   

uchar x,WheelOld;   
uchar Led=0xfe;//LED流水灯初始化   

sbit SJ=P1^4;       //LED的使能端  YY开发板特有
sbit WEI=P2^1;      //74HC573的LE端 U4 LED的位选端 YY开发板特有,熄灭数码管
   
/*定义一下端口为编码器开关输入端=========*/   
sbit PINA=P3^2;    //定义编码器连接的IO   
sbit PINB=P3^3;    //定义编码器连接的IO   
   
/*过程返回==========*/   
uchar WheelLeft()      
{      
     //左转一步的操作   
        Led=_crol_(Led,1);         
    return(NULL);      
}     

uchar WheelRight()      
{      
     //右转一步的操作   
     Led=_cror_(Led,1);   
     return(NULL);      
}     
   
/*编码器过程====================*/   
uchar EncoderProcess()   
{      
     uchar keytmp,keytmp1,keytmp2,WheelNow;   
   
     PINA=1; //PINA至高电平   
     PINB=1;//PINB至高电平   
     if(PINA==1) //如果PINA为高电平   
         {   
         keytmp1=0x01;   
         }   
     else keytmp1=0;     
     if(PINB==1) //如果PINB为高电平   
         {   
         keytmp2=0x02;   
         }   
     else keytmp2=0;   
     WheelNow=keytmp1+keytmp2; //根据两个IO组合成16进制数为0x00|0x01|0x02|0x03   
     keytmp=WheelNow;   
     keytmp^=WheelOld;  //判断新数据同旧数据   
     if(keytmp==0) return(NULL); //如果新数据和原来的数据一样 就直接退出   
     if(WheelOld==0 && WheelNow==0x01)   
         {   
         x=WheelNow;   
         }   
   
     if(WheelOld==0 && x==0x01 && WheelNow==0x03)   
         {   
         WheelOld=WheelNow;   
         x=0;   
         return(WheelLeft()); //左旋转00 01 03   
         }   
   
     if(WheelOld==0x03 && WheelNow==0x02)   
         {   
         x=WheelNow;   
         }   
   
     if(WheelOld==0x03 && x==0x02 && WheelNow==0x00)   
         {   
         WheelOld=WheelNow;   
         x=0;   
         return(WheelLeft()); //左旋转03 02 00   
         }   
   
     if(WheelOld==0 && WheelNow==0x02)   
         {   
         x=WheelNow;   
         }   
   
     if(WheelOld==0 && x==0x02 && WheelNow==0x03)   
         {   
         WheelOld=WheelNow;   
         x=0;           
         return(WheelRight());  //右旋转00 02 03   
         }   
   
     if(WheelOld==0x03 && WheelNow==0x01)   
         {   
         x=WheelNow;   
         }   
   
     if(WheelOld==0x03 && x==0x01 && WheelNow==0x00)   
         {   
         WheelOld=WheelNow;   
         x=0;      
         return(WheelRight());  //右旋转03 01 10   
         }   
   
}   

void main()   
{      
        SJ=0;        //开LED总使能 YY开发板特有   
    WEI=1;
        P0=0xff;
        WEI=0;   
    while (1)   
    {   
            EncoderProcess();   
            P0=Led; //流水灯连接的IO   
    }   
}
回复

使用道具 举报

地板
ID:34268 发表于 2022-5-7 20:19 | 只看该作者
我天代码这么长。
回复

使用道具 举报

5#
ID:624769 发表于 2022-5-7 20:56 | 只看该作者


  1. <p>sbit INT0 = P3^2;  //EC11 PinA
  2. sbit INT1 = P3^3;  //EC11 PinB
  3. unsigned char KeyValue;</p><p>
  4. </p><p>void main()
  5. {
  6. INT0 = 1;
  7. INT1 = 1;
  8. IE0 = 0;
  9. IE1 = 0;
  10. IT0 = 1;
  11. IT1 = 1;
  12. EX0 = 1;
  13. EX1 = 1;
  14. EA = 1;
  15. while(1);</p><p>}</p><p>
  16. void EC11_Reset()   //消抖
  17. {
  18. unsigned char i;
  19. while((IE0)||(IE1)||(!INT0)||(!INT1)) //等待 INT0, INT1 无抖动高电平
  20. {
  21.   IE0 = 0;
  22.   IE1 = 0;
  23.   i = 200; //根据需要定义
  24.   while(--i);
  25. }
  26. }</p><p>void EX_INT_0() interrupt 0
  27. {
  28. while(INT1);  //等待 INT1 低电平
  29. EC11_Reset();  //等待 EC11 回初始状态
  30. KeyValue++;
  31. }</p><p>void EX_INT_1() interrupt 2
  32. {
  33. while(INT0);  //等待 INT0 低电平
  34. EC11_Reset();  //等待 EC11 回初始状态
  35. KeyValue--;
  36. }</p>
复制代码
优点:开关未旋转时,不占用系统资源。
缺点:旋转时比较占用系统资源。
建议:如经常旋转,并且系统比较繁忙,可以加定时器,编码器触发中断后,先关闭外部中断,通过定时器来等待编码器复位后,重开外部中断。


回复

使用道具 举报

6#
ID:213173 发表于 2022-5-7 20:59 | 只看该作者
  1. //测试条件:TX-1C开发板
  2. //杜邦线直接连接ABC端,未接消抖电容
  3. //正常快慢手速未见误码
  4. #include "reg51.h"

  5. typedef unsigned char uchar;
  6. typedef unsigned int  uint;

  7. sbit EC11_A=P3^2;
  8. sbit EC11_C=P3^3;
  9. sbit EC11_B=P3^4;

  10. sbit dula=P2^6;                                        //段
  11. sbit wela=P2^7;                                        //位
  12. //        共阴数码管标准字库       
  13. unsigned char code table[32]={                               
  14. //         0    1    2    3    4    5    6    7    8    9   10A  11B  12C  13D  14E  15F
  15.         0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
  16. //  16黑  17- 18H   19J         20K  21L  22N        23o  24P  25U  26t 27G   28Q  29r  30M  31y
  17.         0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e};
  18. unsigned char  data dis_buf[4];                        //显示缓存
  19. unsigned char count=50;
  20. unsigned char traitA,traitB;
  21. void display()
  22. {
  23.         static unsigned char  i;
  24.         P0=0x00;dula=1;dula=0;
  25.         P0=~(0x01<<i);wela=1;wela=0;
  26.         P0=dis_buf[i];dula=1;dula=0;
  27.         i=++i%4;
  28. }

  29. void main()
  30. {
  31.         EC11_C=0;
  32.         while (1)
  33.         {
  34.                 dis_buf[0]=table[17];
  35.                 dis_buf[1]=table[count/100%10];
  36.                 dis_buf[2]=table[count/10%10];
  37.                 dis_buf[3]=table[count%10];
  38.                 display();
  39.                 //顺时针旋转,每圈进阶20
  40.                 if(EC11_B && !EC11_A && traitA==0)          //第一特征码,如不符合则立即进行反转判断
  41.                 {
  42.                         traitA=1;
  43.                 }
  44.                 else if(!EC11_B && !EC11_A && traitA==1)//第二特征码
  45.                 {
  46.                         traitA=2;
  47.                 }
  48.                 else if(!EC11_B && EC11_A && traitA==2)//第三特征码
  49.                 {
  50.                         if(count>0)count--;
  51.                         traitA=3;
  52.                 }
  53.                 else if(EC11_B && EC11_A)//第四特征码
  54.                 {
  55.                         traitA=0;//清0
  56.                 }
  57.                 //逆时针旋转
  58.                 if(!EC11_B && EC11_A && traitB==0)          //第一特征码,如不符合则立即进行正转判断
  59.                 {
  60.                         traitB=1;
  61.                 }
  62.                 else if(!EC11_B && !EC11_A && traitB==1)//第二特征码
  63.                 {
  64.                         traitB=2;
  65.                 }
  66.                 else if(EC11_B && !EC11_A && traitB==2)//第三特征码
  67.                 {
  68.                         if(count<250)count++;
  69.                         traitB=3;
  70.                 }
  71.                 else if(EC11_B && EC11_A)//第四特征码
  72.                 {
  73.                         traitB=0;//清0
  74.                 }
  75.         }
  76. }

复制代码
回复

使用道具 举报

7#
ID:161164 发表于 2022-5-7 23:20 | 只看该作者
szqkfsskk 发表于 2022-5-7 20:19
我天代码这么长。


只有六行,夠短了吧
  1.             if(!PinA && PinA_O && PinB) {

  2.                  Now++;

  3.              }PinA_O = PinA;               

  4.              if(!PinB && PinB_O && PinA) {

  5.                  Now--;

  6.              }PinB_O = PinB;        
复制代码




详情请看我的贴子

回复

使用道具 举报

8#
ID:390416 发表于 2022-5-7 23:52 | 只看该作者
void ROTARY_ROTARY_Scan_Drive(void)
{
        static xdata u8 count=0,Rotary_Flag=0;
        if(count>30)
        {
                count=0;
                if((ROTARY_B==0)&&(Rotary_Flag==0))                        //如果按键B按下,且flag是0       
                {
                        Rotary_Flag=1;
                        Rotary_Read_Data_Rotary++;                                //按键值增加1
                }
                if((ROTARY_A==0)&&(Rotary_Flag==0))                        //如果按键A按下,且flag是0       
                {
                        Rotary_Flag=1;
                        Rotary_Read_Data_Rotary--;                                //按键值减少1
                }
                if((ROTARY_B!=0)&&(ROTARY_A!=0))                        //按键必须释放,下次按键才有效
                {
                        Rotary_Flag=0;
                }
        }
        count++;
}

主函数直接循环扫描这个函数就行了,人人学会单片机!对付人手还是可以的,如果是光电编码器 不适合此代码。
回复

使用道具 举报

9#
ID:401564 发表于 2022-5-8 09:21 | 只看该作者
lkc8210 发表于 2022-5-7 23:20
只有六行,夠短了吧

经过烧录验证,并不行
不用转动,摇一下EC11的摇杆,NOW就会改变
转一半,再不转,NOW也会改变
你帖子我看了,波形不需要分析,只看实际结果
回复

使用道具 举报

10#
ID:401564 发表于 2022-5-8 09:24 | 只看该作者
如果单片机不着急处理太多的东西,可以用定时器1mS扫描一次AB两个IO来判断转动
不用加电容,不用加去抖动
回复

使用道具 举报

11#
ID:161164 发表于 2022-5-8 10:12 | 只看该作者
Y_G_G 发表于 2022-5-8 09:21
经过烧录验证,并不行
不用转动,摇一下EC11的摇杆,NOW就会改变
转一半,再不转,NOW也会改变

如果不分析波形,只看实际结果
有没有可能…
你的实际和我的实际有点不一样?

if(ScanCount++ > 50)//这里有调大一点吗?
回复

使用道具 举报

12#
ID:401564 发表于 2022-5-8 11:12 | 只看该作者
lkc8210 发表于 2022-5-8 10:12
如果不分析波形,只看实际结果
有没有可能…
你的实际和我的实际有点不一样?

没有调大,我只是复制验证一下而已
并不是每次都会变动,单纯的找BUG一样去试的话,会有问题
如果只是正常使用,我转了就不再调回来,那效果还是可以的
回复

使用道具 举报

13#
ID:417804 发表于 2022-7-1 21:23 | 只看该作者

ytyt 放谢谢,很好用
回复

使用道具 举报

14#
ID:1034178 发表于 2023-12-7 21:11 来自手机 | 只看该作者
论证才有进步
回复

使用道具 举报

15#
ID:909736 发表于 2024-8-1 06:34 来自手机 | 只看该作者
lkc8210 发表于 2022-5-7 23:20
只有六行,夠短了吧



以前看见过这个代码,后来就找不到了,谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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