矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
楼主: changjianguo

非常稳定的旋转编码器解码程序(C51源代码)

  [复制链接]
     
发表于 2019-2-25 19:57:21 | 显示全部楼层
无情地抄袭一下
回复 支持 反对

使用道具 举报

     
发表于 2019-2-27 23:54:08 | 显示全部楼层
没玩过这个,有空试试。谢楼主分享!
回复 支持 反对

使用道具 举报

     
发表于 2019-3-8 09:00:29 | 显示全部楼层
谢谢楼主分享  收藏了
回复 支持 反对

使用道具 举报

     
发表于 2019-3-15 03:50:46 | 显示全部楼层
旋转编码器是改什么用的,常在工控中看见
回复 支持 反对

使用道具 举报

     
发表于 2019-8-17 16:06:21 | 显示全部楼层
谢谢楼主分享  收藏了  有空时试一下
回复 支持 反对

使用道具 举报

     
发表于 2019-8-19 17:24:30 | 显示全部楼层
   楼主这个思路挺好啊,高手就是高手,思路和菜鸟完全是两回事。。本菜以前一直是检测IO状态,甚至还用过(while(io变成高电平),如果编码器卡在那动不了,程序也就卡住了)从没想过要把检测的状态另外定义个值表示出来。脑袋转不过弯来。
  没找到编码器,也没焊板子,自己用了两个按键人工模拟编码器仿真了一下楼主程序。发现有个问题,如果编码器转到一半又转回来,这个程序怎么触发?
我稍微改了一下,但是暂时没焊实物验证,只是手工模拟编码器仿真了一下。感觉稍微有点改进,如果编码器不是按设定的套路转动,那么就无效。
先贴上程序,望楼主指点。
  1. #include "reg52.h"
  2. #include "stdio.h"

  3. typedef  unsigned char        u8;
  4. typedef  unsigned int        u16;
  5. typedef  unsigned long        u32;

  6. sbit rs = P3^5;                                     
  7. sbit rw = P3^6;     
  8. sbit e  = P3^7;  
  9.                                                                           
  10. sbit bmqa=P1^0;                                                                  //编码器A引脚               
  11. sbit bmqb=P1^1;                                                                  //编码器B引脚

  12. u8 diyici,dierci,disanci;                                        //第一次值,第二次值,第三次值
  13. u8 buzhou;                                                                         //步骤。用于检测三次不同的值
  14. char chufa;                                                                        //触发
  15. int zijia;                                                                        //消抖计时

  16. #define shichang 5                                                        //消抖设定时间,感觉编码器函数放在定时器里会稳定很多

  17. /*本人英文实在太烂,实在是不喜欢写个程序洋不洋土不土的。看此程序请用拼音看。
  18.         实在看不懂,请看注释;再看不懂,本菜也没办法*/

  19. void yanshi(u16 hm)                                                           //延时函数
  20. {
  21.         for(;hm>0;hm--)                                                           //这里不需要精准,只要仿真的时候LCD能显示即可。
  22.         {                                                                                //实际如果这样延时,LCD可能不显示
  23.                 ;
  24.         }
  25. }

  26. void xiedizhi(u8 dizhi)                                                   //写LCD地址,时序请百度1602时序
  27. {
  28.         rs=0;
  29.         rw=0;
  30.         yanshi(1);
  31.         P2=dizhi;
  32.         yanshi(1);
  33.         e=1;
  34.         yanshi(1);
  35.         e=0;
  36. }

  37. void xieshuju(u8 dizhi)                                                 //写数据
  38. {
  39.         rs=1;
  40.         rw=0;
  41.         yanshi(1);
  42.         P2=dizhi;
  43.         yanshi(1);
  44.         e=1;
  45.         yanshi(1);
  46.         e=0;
  47. }

  48. void xianshi(u8 *shuju)                                                   //显示连续字符
  49. {       
  50.         while(*shuju)
  51.         xieshuju(*shuju++);               
  52. }

  53. void chushihua1602(void)                                         //初始化1602,
  54. {
  55.         yanshi(40);
  56.         xiedizhi(0x38);   
  57.         yanshi(20);
  58.         xiedizhi(0x38);
  59.         yanshi(20);
  60.         xiedizhi(0x38);
  61.         yanshi(20);
  62.         xiedizhi(0x0c);
  63.         yanshi(20);
  64.         xiedizhi(0x01);  
  65.         yanshi(20);
  66.         xiedizhi(0x06);  
  67.         yanshi(20);
  68. }                                                               

  69. void bmq(void)
  70. {
  71.         u8 a;
  72.     if(bmqa&&bmqb)                                                          //如果编码器A引脚和B引脚都为高电平
  73.         buzhou=0;                                                                     //清零步骤,防止转到一半又转回来也能触发编码器
  74.         else
  75.         {
  76.                 zijia++;                                                           //消抖计时,单片机慢的话,可以不需要消抖
  77.                 if(zijia>shichang)                                           //尽量把次函数放在定时器,可以精确消抖时间
  78.                 {
  79.                         zijia=0;                                                //清零消抖
  80.                         a=(bmqa?1:0)+(bmqb?2:0);                   //把计算出的结果复制给a
  81.                         if(buzhou==0)                                           //如果步骤为0
  82.                         diyici=a,buzhou=1;                                   //那么把A的值复制给第一次检测IO的数值。步骤为第二步
  83.                         else if(buzhou==1)                                //如果步骤为1
  84.                         {
  85.                                  if(a!=diyici)                                   //如果检测到编码器转动
  86.                                 {
  87.                                         dierci=a;                                  //把编码器计算出的值复制给第二次
  88.                                         buzhou=2;                                   //步骤到了第二步
  89.                                 }       
  90.                         }
  91.                         else if(buzhou==2)                                //同上,如果编码器转动了
  92.                         {
  93.                                  if(a!=dierci)                                   //如果a不等于第二次
  94.                                 {
  95.                                         disanci=a;                                   //那么赋值给第三次。
  96.                                         if(diyici==1&&dierci==0&&disanci==2)
  97.                                         chufa=1;                                //如果三次结果同时满足上述条件,触发1号键
  98.                                         if(diyici==2&&dierci==0&&disanci==1)
  99.                                         chufa=2;                                   //同上,触发2号键
  100.                                         buzhou=0;                                   //清零步骤
  101.                                 }       
  102.                         }
  103.                 }                       
  104.         }
  105. }

  106. void main(void)
  107. {
  108.         u32 a=12345678;
  109.         u8 shuju[11];
  110.         chushihua1602();
  111.         while(1)
  112.         {
  113.                 bmq();                                               
  114.                 if(chufa==1)                                                //如果触发1号键
  115.                 chufa=0,                                                           //清零触发,避免连续触发
  116.                 a++;                                                                   //A自加
  117.                 if(chufa==2)                                                   //同上
  118.                 chufa=0,
  119.                 a--;
  120.                 sprintf(shuju,"%ld",a);                                   //把数字转换成字符串
  121.                 xiedizhi(0x80);                                                //在这个位置
  122.                 xianshi(shuju);                                                   //显示这个数
  123.         }
  124. }
复制代码

QQ截图20190819172346.png
回复 支持 反对

使用道具 举报

     
发表于 2019-8-19 17:26:56 | 显示全部楼层
本帖最后由 isoimg2130 于 2019-8-19 17:29 编辑

   这个,复制上来注释就乱了,实际上注释的时候没这么乱的。。。 QQ截图20190819172601.png
嗯,复制上去的注释还打错了几个字。
回复 支持 反对

使用道具 举报

     
发表于 2019-8-19 17:34:49 | 显示全部楼层
本帖最后由 isoimg2130 于 2019-8-19 17:39 编辑

这是proteus8.0仿真文件和KEIL程序。
仿真的时候,按编码器时序,把鼠标指针放在要按的按键上,但是不点击鼠标,按空格,然后按键按下去之后就不会复位,然后另一个按键操作和此相同,待两个按键都按下了,再按时序把两个按键依次再按一次,让按键起来(就是恢复高电平)。如果不按时序来按键是不会触发的 QQ截图20190819173631.png

编码器测试程序和仿真.rar

40.36 KB, 下载次数: 320

回复 支持 反对

使用道具 举报

     
发表于 2019-8-19 18:07:40 | 显示全部楼层
  当然了,也可以设置小范围转动只触发1次,大范围转动触发转动了的次数,比如触发了5个脉冲,只触发1次,5次以上,触发5次。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2019-8-20 09:22:17 | 显示全部楼层
isoimg2130 发表于 2019-8-19 17:24
楼主这个思路挺好啊,高手就是高手,思路和菜鸟完全是两回事。。本菜以前一直是检测IO状态,甚至还用过 ...

欢迎交流,原程序只有2种有效状态(正转和反转),其它状态(停转或乱转)都作为无效状态,也就是不能正常解码的,直接返回0
回复 支持 反对

使用道具 举报

     
发表于 2019-8-20 09:25:15 | 显示全部楼层
工控的路过,编码器在工业控制中最常见的,一般都是PLC或者伺服中,普通单片机用这个太麻烦了
回复 支持 反对

使用道具 举报

     
发表于 2019-8-20 09:39:03 | 显示全部楼层
changjianguo 发表于 2019-8-20 09:22
欢迎交流,原程序只有2种有效状态(正转和反转),其它状态(停转或乱转)都作为无效状态,也就是不能正常解 ...

  知道啊,那如果转到一半再转回来呢。。
回复 支持 反对

使用道具 举报

     
发表于 2019-8-20 10:39:13 | 显示全部楼层
电憨憨 发表于 2019-8-20 09:25
工控的路过,编码器在工业控制中最常见的,一般都是PLC或者伺服中,普通单片机用这个太麻烦了

          啊(二声)? 普通单片机也不麻烦啊,当然了,前提是程序得写好。。
回复 支持 反对

使用道具 举报

     
发表于 2019-8-20 12:59:06 | 显示全部楼层
isoimg2130 发表于 2019-8-19 17:24
楼主这个思路挺好啊,高手就是高手,思路和菜鸟完全是两回事。。本菜以前一直是检测IO状态,甚至还用过 ...

这个编码器能用,名称MOTOR-ENCODER
正转.jpg
反转.jpg
回复 支持 反对

使用道具 举报

     
发表于 2019-8-20 14:54:15 | 显示全部楼层
gxg0000 发表于 2019-8-20 12:59
这个编码器能用,名称MOTOR-ENCODER

也可以,发现不是转一下的。中间要暂停,不然不知道转了多少次。。不知道怎么设置才能让电动机不要慢速启动。只能抓取刚开始的波形,不然等他转了不知道多少次再抓取的话,又验证不了程序是否正确。。仿真完,我看下找个板子弄上编码器实物测试下。。。
仿真图如下: QQ截图20190820141152.png QQ截图20190820141344.png 上两张是正反转波形 将就看下就好。
下面的是刚启动波形和启动一段时间后的正常波形
   QQ截图20190820144745.png QQ截图20190820144824.png QQ截图20190820144855.png
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-3-29 09:07

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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