找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 13235|回复: 52
收起左侧

一定位一脉冲的EC11旋转编码器最简洁的单片机驱动代码

  [复制链接]
ID:161164 发表于 2021-7-2 19:11 | 显示全部楼层 |阅读模式
先上代碼為敬
  1.             if(!PinA && PinA_O && PinB) {
  2.                 Now++;
  3.             }PinA_O = PinA;               
  4.             if(!PinB && PinB_O && PinA) {
  5.                 Now--;
  6.             }PinB_O = PinB;        
复制代码
只有六行代碼就能用EC11對Now進行加減操作

为什么这样写呢?
上时序图
顺时针转:

顺时针转

顺时针转


逆时针转:
2021-07-02_172038s.png

我们看到,当顺时针转时
Pin A会早于Pin B 转低电平,反之亦然

代码解读:
!PinA && PinA_O && PinB//当Pin A 为低电平而之前为高电平(即下降沿)并且Pin B为高电平
这一句就捕捉到顺时针转时序图中箭指着的那一刹那的情况
于是Now加1

!PinB && PinB_O && PinA//当Pin B 为低电平而之前为高电平(即下降沿)并且Pin A为高电平
这一句就捕捉到逆时针转时序图中箭指着的那一刹那的情况
于是Now减1



如果编码器不加电容消抖
就用软件消抖

  1.         if(ScanCount++ > 50) {        //其数值按单片机速度加减
  2.             ScanCount = 0;
  3.             if(PinA && !PinA_O && PinB) {
  4.                 Now++;
  5.             }PinA_O = PinA;               
  6.             if(PinB && !PinB_O && PinA) {
  7.                 Now--;
  8.             }PinB_O = PinB;                        
  9.             Now>9? Now = 0:_nop_();
  10.             Now<0? Now = 9:_nop_();
  11.         }
复制代码
现附上小应用实例一则
基如STC15F104E的EC11软串口六位密码检查程序
如发现顺逆时针相反,对调PinA/PinB 定义脚即可
51hei.png

上图.c文件51hei下载: Encoder3_PW_Lock.zip (1.7 KB, 下载次数: 405)

评分

参与人数 2黑币 +95 收起 理由
MOVEORDIE + 5 赞一个!
admin + 90 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:569384 发表于 2021-7-3 09:46 | 显示全部楼层
假如顺时针扭了一点但没到位之前逆时针扭回去了呢?
回复

使用道具 举报

ID:161164 发表于 2021-7-3 12:37 来自手机 | 显示全部楼层
不考慮任何不正常操作
回复

使用道具 举报

ID:46750 发表于 2021-7-3 14:49 | 显示全部楼层
代码简洁易懂
回复

使用道具 举报

ID:47286 发表于 2021-7-3 17:04 | 显示全部楼层
haokey 发表于 2021-7-3 09:46
假如顺时针扭了一点但没到位之前逆时针扭回去了呢?

我觉得"ScanCount++"解决了你说的问题 就是说这之后得到的是一个确定值 要么转了要么没转 即便按你说的哆嗦一下 那也是下一次监测的事了

感觉这代码写的不错
回复

使用道具 举报

ID:161164 发表于 2021-7-3 23:41 | 显示全部楼层
dzbj 发表于 2021-7-3 17:04
我觉得"ScanCount++"解决了你说的问题 就是说这之后得到的是一个确定值 要么转了要么没转 即便按你说的哆 ...

然而,并不能
之前的回覆草率了

先上时序图

哆嗦X 和 哆嗦Y

哆嗦X 和 哆嗦Y



青色虚线之间是一次完整的脉冲
Now++是发生在第一条青色虚线之后少少的时间
但一定早于哆嗦X 和 哆嗦Y
而Now++或Now--的先要条件是: 之前高电平+现在低电平(下降沿发生)
无论哆嗦X 还是 哆嗦Y所产生的都是之前低电平+现在高电平(上升沿发生)
不满足Now++或Now--的先要条件

haokey兄所提出的问题,真正答案是:没事发生


而"ScanCount++"所做的事是加长扫描时间去消抖
再上时序图:

不干净的脉冲

不干净的脉冲


这是一个不干净的脉冲
如果没有"ScanCount++"

没有"ScanCount++"

没有"ScanCount++"


單片機會在黃色虚线那里判斷
結果在3,4,6判為成立

如果加上"ScanCount++"

加上"ScanCount++"

加上"ScanCount++"


就只会在2那里成立,避开了抖动

当然"ScanCount++ >"的数值要进行调节
如果数值太大如图

"ScanCount++ >"的数值太大

"ScanCount++ >"的数值太大


在2看到的就是B之前高电平+B现在低电平(B下降沿发生)+A高电平 = 逆时针转了!
                       
       
                                                        
回复

使用道具 举报

ID:569384 发表于 2021-7-7 11:25 | 显示全部楼层
lkc8210 发表于 2021-7-3 23:41
然而,并不能
之前的回覆草率了

能不能帮忙分析一下有没有其他不正常的情况?
回复

使用道具 举报

ID:569384 发表于 2021-7-7 12:20 | 显示全部楼层
lkc8210 发表于 2021-7-3 23:41
然而,并不能
之前的回覆草率了

探讨一下,假如我改成这样会怎样:
if(!PinA&&PinB)
{PinA_O= 1;}
if(!PinB&&PinA)
{PinB_O= 1;}
                               
                               
if(PinA_O&& PinA)
{
        PinA_O = 0;
        if(!PinB)
        {
                Now++;
        }
}
                               
if(PinB_O&& PinB)
{
        PinB_O= 0;
        if(!PinA)
        {
                Now--;
        }
}                                               
回复

使用道具 举报

ID:161164 发表于 2021-7-7 17:20 | 显示全部楼层
haokey 发表于 2021-7-7 12:20
探讨一下,假如我改成这样会怎样:
if(!PinA&&PinB)
{PinA_O= 1;}

这样改是为了什么?
回复

使用道具 举报

ID:308267 发表于 2021-8-25 19:52 | 显示全部楼层
小白请教:请问,IF最后面大括号外面的PinA_O = PinA是什么意思?
if(PinA && !PinA_O && PinB) {
                Now++;
            }PinA_O = PinA;

回复

使用道具 举报

ID:308267 发表于 2021-8-25 19:57 | 显示全部楼层
PinA_O是怎么定义为下降沿的啊?真心请教
回复

使用道具 举报

ID:989992 发表于 2022-1-27 11:10 | 显示全部楼层
代码简洁
回复

使用道具 举报

ID:67925 发表于 2022-1-28 06:16 来自手机 | 显示全部楼层
按中键时如果有移位,可能会误触发一次加减
回复

使用道具 举报

ID:161164 发表于 2022-1-28 13:54 | 显示全部楼层
yxlitol 发表于 2021-8-25 19:52
小白请教:请问,IF最后面大括号外面的PinA_O = PinA是什么意思?
if(PinA && !PinA_O && PinB) {
       ...

记录A脚电平
回复

使用道具 举报

ID:161164 发表于 2022-1-28 14:00 | 显示全部楼层
yxlitol 发表于 2021-8-25 19:57
PinA_O是怎么定义为下降沿的啊?真心请教

不是单单用PinA_O去看
要结合PinA
if(!PinA && PinA_O && PinB)的文字表达就是:
当"A脚现在是低电平" 与 "A脚前一次是高电平" 与 "B脚现在是高电平" 时成立

!PinA && PinA_O 这俩合起来才能判断是否下降沿
回复

使用道具 举报

ID:161164 发表于 2022-1-28 14:03 | 显示全部楼层
cdhigh 发表于 2022-1-28 06:16
按中键时如果有移位,可能会误触发一次加减

如果编码器太松就有可能
回复

使用道具 举报

ID:69115 发表于 2022-2-3 22:59 | 显示全部楼层
这个代码写的不错 简明有效 很实用
回复

使用道具 举报

ID:1004108 发表于 2022-2-5 01:12 | 显示全部楼层
代码简洁易懂
回复

使用道具 举报

ID:66287 发表于 2022-2-7 10:49 | 显示全部楼层
楼主代码及其精简,不错!
实际上,只检测A引脚的下降沿,由B引脚状态决定加减更高效。
经实验,无漏脉冲和多加多减现象。
void key()   //按键处理
{
      if((PinA_O== PinA)||(PinA ==1))  //不理会A引脚上升沿,低电平每个脉冲只做一次处理
         {
                 PinA_O= PinA;
                  return;
         }                                                         
       (PinB == 0) ? NUM-- : NUM++;   //根据引脚B的值,判断正反转
        PinA_O = PinA;                         //存储引脚A状态
}
采样A引脚下降沿时B引脚状态,同相减、异相加。
回复

使用道具 举报

ID:514317 发表于 2022-2-7 16:45 | 显示全部楼层
你这种处理方法我都试过了   用在EC11旋转编码器上勉强够用  也存在其他处理占用时间而掉脉冲的情况   但如果脉冲要达到1K的速度   就掉脉冲严重
EC11还是可以用下的   
回复

使用道具 举报

ID:161164 发表于 2022-2-7 17:20 | 显示全部楼层
bhjyqjs 发表于 2022-2-7 10:49
楼主代码及其精简,不错!
实际上,只检测A引脚的下降沿,由B引脚状态决定加减更高效。
经实验,无漏脉冲 ...

妙啊~
回复

使用道具 举报

ID:67925 发表于 2022-2-8 01:32 来自手机 | 显示全部楼层
lkc8210 发表于 2022-1-28 14:03
如果编码器太松就有可能

为什么我知道是因为我以前就是用类似的算法,后来全部换成更复杂的算法了。
看应用,如果误加减影响不大则可以用,否则需要更鲁棒性的算法
回复

使用道具 举报

ID:883031 发表于 2022-2-8 10:18 | 显示全部楼层
本帖最后由 cn_zhx 于 2022-2-8 14:43 编辑

其实,这里AB数据线产生的是格雷码,如果我们采集时采用判断AB两线的变化,即,A或B来下降沿时,作出4次判断,可以避免楼上所说的哆嗦,但是,要求采样频率要跟得上,可以采用加减速器的方法,
回复

使用道具 举报

ID:161164 发表于 2022-2-8 13:29 来自手机 | 显示全部楼层
cn_zhx 发表于 2022-2-8 10:18
其实,这里AB数据线产生的是格雷码,如果我们采集时采用判断AB两线的变化,即,A或B来下降沿时,作出4次判 ...

什么是加减速器的方法?
可以详细说说吗?
回复

使用道具 举报

ID:883031 发表于 2022-2-8 14:40 | 显示全部楼层
齿轮传动,小齿轮带大齿轮,用大齿轮带动编码器旋转,即可降低转速
回复

使用道具 举报

ID:119977 发表于 2022-2-16 14:19 | 显示全部楼层
个人做法硬件加104电容  一个接外部中断一个接普通IO    中断后读普通IO高低     正转高或低   反转低或高控制++ --      可靠高效无敌  一般人我不告诉他
回复

使用道具 举报

ID:509339 发表于 2022-2-17 14:27 | 显示全部楼层
hewayking 发表于 2022-2-16 14:19
个人做法硬件加104电容  一个接外部中断一个接普通IO    中断后读普通IO高低     正转高或低   反转低或高 ...

难打别人不都是这样吗?
回复

使用道具 举报

ID:887371 发表于 2022-6-14 15:48 | 显示全部楼层
hewayking 发表于 2022-2-16 14:19
个人做法硬件加104电容  一个接外部中断一个接普通IO    中断后读普通IO高低     正转高或低   反转低或高 ...

我也认为这种方法更好。
http://www.51hei.com/bbs/dpj-221520-1.html
这是用十速51mcu做的直流电机定位功能,非常可靠准确,用于EC11要加104电容。
一定要用软件消抖,要增加2个全局bit变量用于存储AB引脚之前的状态,但这样增加了不少mcu开销。
回复

使用道具 举报

ID:240452 发表于 2022-11-8 17:51 | 显示全部楼层
这个代码我在STC15W408AS上调试通过。 为什么在STC8H1K08上不行,就是没有操作EC11旋转编码器,电脑串口    不断收到数据。                                                                                                                                                                                          
回复

使用道具 举报

ID:240452 发表于 2022-11-8 20:55 | 显示全部楼层
//00准双向  01推挽输出  10高阻输入 11开漏输出高阻输入
P3M1 = B0000_0000;
P3M0 = B1010_0000;

增加这个后就可以了
回复

使用道具 举报

ID:240452 发表于 2022-11-8 20:55 | 显示全部楼层
stc8h默认是高阻
回复

使用道具 举报

ID:996773 发表于 2023-4-17 10:59 | 显示全部楼层
不用这么复杂,只要判断两个脚是11,然后延时毫秒多少。忘了,再判断是不是10,就说明

它旋转了,如果判断出来是01就是反方向旋转了,中断和定时器都不需要,主程序留在

等待的时候加一丢丢延时再执行就ok了
回复

使用道具 举报

ID:1085900 发表于 2023-6-26 22:21 | 显示全部楼层
hi等你 发表于 2023-4-17 10:59
不用这么复杂,只要判断两个脚是11,然后延时毫秒多少。忘了,再判断是不是10,就说明

它旋转了,如果判 ...

[em17
回复

使用道具 举报

ID:161164 发表于 2023-6-27 11:30 | 显示全部楼层
hi等你 发表于 2023-4-17 10:59
不用这么复杂,只要判断两个脚是11,然后延时毫秒多少。忘了,再判断是不是10,就说明

它旋转了,如果判 ...

看到"延时毫秒"和"中断和定时器都不需要"
就知道你还没弄懂
回复

使用道具 举报

ID:996773 发表于 2023-6-28 16:05 | 显示全部楼层
lkc8210 发表于 2023-6-27 11:30
看到"延时毫秒"和"中断和定时器都不需要"
就知道你还没弄懂

TA8127x6a64.jpg

我就是不用定时器和中断,这个资源用在更重要的地方,只需要判断10和11就行,反转判断01和11.

已经成品用了好久了,手感也很好
回复

使用道具 举报

ID:1085441 发表于 2023-6-30 21:18 | 显示全部楼层
EC11不需要用延时,放在中断程序中,占用资源很少,用的很稳定。
回复

使用道具 举报

ID:1085441 发表于 2023-6-30 21:21 | 显示全部楼层
微笑的小小 发表于 2022-11-8 17:51
这个代码我在STC15W408AS上调试通过。 为什么在STC8H1K08上不行,就是没有操作EC11旋转编码器,电脑串口     ...

STC15W的引脚默认是准双向口,STC8H的引脚默认是高阻,初始化的时候需要设置为准双向口。
回复

使用道具 举报

ID:1064915 发表于 2023-7-1 09:36 | 显示全部楼层
hi等你 发表于 2023-6-28 16:05
我就是不用定时器和中断,这个资源用在更重要的地方,只需要判断10和11就行,反转判断01和11.

已 ...

能否共享一下
回复

使用道具 举报

ID:398219 发表于 2023-9-22 15:41 | 显示全部楼层
谢谢楼主分享,我用的STC15W408AS。用楼主的例程,采用两个外部中断来检测脉冲。能正常检测到正转和反转。但是旋转编码器的旋转速度稍微快点,就容易丢脉冲(脉冲速度快了,连成一片了),导致单片机采不到或者误采到B相。求一下速度快点的解决办法。count1和count2是正转和反转的脉冲计数,以后用于计算角度使用。
void exint0() interrupt 0       //INT0中断入口
{       
        if(!P32 && PinA_O && P33)
        {
                count1++;
               
        }       
        PinA_O = P32;
}
//外部中断服务程序1
void exint1() interrupt 2       //INT1中断入口
{
        if(!P33 && PinB_O && P32)
        {
                count2++;
        }
        PinB_O = P33;
}
回复

使用道具 举报

ID:161164 发表于 2023-9-22 16:14 | 显示全部楼层
herui2128 发表于 2023-9-22 15:41
谢谢楼主分享,我用的STC15W408AS。用楼主的例程,采用两个外部中断来检测脉冲。能正常检测到正转和反转。 ...

用一个外中断即可
  1. uint Delay_XD = 0;
  2. bit Encoder_EN = 1;
  3. void exint0() interrupt 0       //INT0中断入口
  4. {
  5.         if(Encoder_EN)
  6.         {
  7.                 if(!P33)
  8.                 {
  9.                         count1++;
  10.                 }else{
  11.                         count2++;
  12.                 }
  13.                 Encoder_EN = 0;
  14.         }
  15. }
  16. void main()
  17. {
  18.         //your code
  19.         while(1)
  20.         {
  21.                 //your code
  22.                 if(!Encoder_EN)
  23.                 {
  24.                         if(P32)
  25.                         {
  26.                                 if(Delay_XD++>=1000)//按主循环周期调节
  27.                                 {
  28.                                         Delay_XD = 0;
  29.                                         Encoder_EN = 1;
  30.                                 }
  31.                         }else{
  32.                                 Delay_XD = 0;
  33.                         }
  34.                 }
  35.         }
  36. }
复制代码



回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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