找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9029|回复: 13
收起左侧

51单片机旋转编码器模块测试代码

  [复制链接]
ID:658665 发表于 2020-5-5 15:28 | 显示全部楼层 |阅读模式
模块图片 旋转编码器.jpg
测试平台:STC89C516单片机 晶振:12MHz
其他单片机(STC12单片机)或晶振,请在程序的LCD1602.crotary_encoder.c文件中修改延时函数


连线如图(连线的接口在程序的port.h文件里)

旋转编码器连线.jpg


测试代码功能:
将程序下载到开发板,LCD显示0FF,显示数字000.
按下旋转编码器的按键,OFF变为ON,转动旋转编码器就可以在LCD1602中看到数字变化.
再次按下旋转按键,ON变为OFF,此时转动旋转编码器不可以在LCD1602中看到数字变化.

结尾:
    测试程序的注释也比较详细,自我感觉这个程序对较慢的转速和正常的转速的兼容性都比较好,只有极少数情况出现丢步,已经实现较好的实现了旋转编码器的功能了.

本帖测试程序参考过以下帖子
http://www.51hei.com/bbs/dpj-93972-1.html

单片机源程序如下:
  1. #include <intrins.h>
  2. #include "public.h"
  3. #include "rotary_encoder.h"
  4. #include "LCD1602.h"
  5. #include "port.h"

  6. void rotary_encoder_delay50us()//12.000MHz
  7. {
  8.         u8 i;
  9.         _nop_();
  10.         i=22;
  11.         while(--i);
  12. }

  13. void rotary_encoder_delay10ms()        //12.000MHz
  14. {
  15.         u8 i,j;

  16.         i=20;
  17.         j=113;
  18.         do
  19.         {
  20.                 while (--j);
  21.         }while (--i);
  22. }

  23. //旋转编码器初始化
  24. void rotary_encoder_init()
  25. {
  26.         ROTARY_ENCODER_CLK=1;
  27.         ROTARY_ENCODER_DT=1;
  28.         ROTARY_ENCODER_SW=1;
  29.        
  30.         IT0=1;
  31.         EX0=1;
  32.         EA=1;
  33.        
  34.         LCD1602_print_char(0,0,'O');
  35.         LCD1602_print_char(0,1,'F');
  36.         LCD1602_print_char(0,2,'F');
  37.        
  38.         LCD1602_print_char(1,0,'0'+0);
  39.         LCD1602_print_char(1,1,'0'+0);
  40.         LCD1602_print_char(1,2,'0'+0);
  41. }

  42. //扫描旋转编码器,返回值为1代表正转,返回值为0代表反转,返回值为0xFF代表未旋转或旋转错误
  43. u8 scan_rotary_encoder()
  44. {
  45.         u8 rotary_encoder_state;//旋转编码器状态
  46.         u16 forced_out;//强制退出
  47.        
  48.         //旋转编码器状态
  49.         //如果在刚开始ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT都为1,则状态为1
  50.         //如果在刚开始ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT都为0,则状态为0
  51.         if((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT)) rotary_encoder_state=1;
  52.         else if((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)) rotary_encoder_state=0;
  53.        
  54.         //ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT为同一电平时检测
  55.         if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
  56.         {
  57.                 //用最多150ms时间来等待ROTARY_ENCODER_CLK电平或ROTARY_ENCODER_DT电平变化(此时AB为11或00)
  58.                 forced_out=3000;
  59.                 while(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
  60.                 {
  61.                         --forced_out;
  62.                         rotary_encoder_delay50us();
  63.                         if(!forced_out) return 0xFF;//超时则强制退出,返回错误码
  64.                 }
  65.                
  66.                 //每次电平变化必定旋转了编码器,电平变化后要消抖
  67.                 rotary_encoder_delay10ms();
  68.                
  69.                 //当ROTARY_ENCODER_CLK为低电平,ROTARY_ENCODER_DT为高电平时
  70.                 if((!ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))
  71.                 {
  72.                         //用150ms时间来等待ROTARY_ENCODER_DT电平变化(此时AB为01)
  73.                         forced_out=3000;
  74.                         while((!ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))
  75.                         {
  76.                                 --forced_out;
  77.                                 rotary_encoder_delay50us();
  78.                                 if(!forced_out) return 0xFF;//超时则强制退出,返回错误码
  79.                         }
  80.                        
  81.                         //每次电平变化必定旋转了编码器,电平变化后要消抖
  82.                         rotary_encoder_delay10ms();
  83.                        
  84.                         //当ROTARY_ENCODER_CLK为低电平,而且ROTARY_ENCODER_DT也为低电平
  85.                         //或ROTARY_ENCODER_CLK为高电平,而且ROTARY_ENCODER_DT也为高电平(AB为11或00)
  86.                         //此时  AB从11到01到00  或  AB从00到01到11
  87.                         if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
  88.                         {
  89.                                 //如果旋转编码器的状态为1则返回1,代表正转一下
  90.                                 if(rotary_encoder_state) return 1;
  91.                                 //如果旋转编码器的状态为0则返回0,代表反转一下
  92.                                 else return 0;
  93.                         }
  94.                         //若AB不为11或不为00则返回旋转编码器错误码
  95.                         else return ROTARY_ENCODER_ERROR;
  96.                 }
  97.                 //当ROTARY_ENCODER_CLK为高电平,ROTARY_ENCODER_DT为低电平时
  98.                 else
  99.                 {
  100.                         //当ROTARY_ENCODER_CLK为高电平,ROTARY_ENCODER_DT为低电平时
  101.                         if((ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT))
  102.                         {
  103.                                 //用150ms时间来等待ROTARY_ENCODER_CLK电平变化(此时AB为10)
  104.                                 forced_out=3000;
  105.                                 while((ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT))
  106.                                 {
  107.                                         --forced_out;
  108.                                         rotary_encoder_delay50us();
  109.                                         if(!forced_out) return 0xFF;//超时则强制退出,返回错误码
  110.                                 }
  111.                                
  112.                                 //每次电平变化必定旋转了编码器,电平变化后要消抖
  113.                                 rotary_encoder_delay10ms();
  114.                                
  115.                                 //当ROTARY_ENCODER_CLK为低电平,而且ROTARY_ENCODER_DT也为低电平
  116.                                 //或ROTARY_ENCODER_CLK为高电平,而且ROTARY_ENCODER_DT也为高电平(AB为11或00)
  117.                                 //此时  AB从11到10到00  或  AB从00到10到11
  118.                                 if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
  119.                                 {
  120.                                         //如果旋转编码器的状态为0则返回1,代表正转一下
  121.                                         if(!rotary_encoder_state) return 1;
  122.                                         //如果旋转编码器的状态为1则返回0,代表反转一下
  123.                                         else return 0;
  124.                                 }
  125.                                 //若AB不为11或不为00则返回旋转编码器错误码
  126.                                 else return ROTARY_ENCODER_ERROR;
  127.                         }
  128.                 }
  129.         }
  130.         //未响应返回旋转编码器错误码
  131.         return 0xFF;
  132. }

  133. //旋转编码器中断
  134. void rotary_encoder_interrupt() interrupt 0
  135. {
  136.         static u8 dat=0;
  137.         u8 temp=0xFF;//临时变量先赋旋转编码器错误码的值
  138.         if(!ROTARY_ENCODER_SW)//检查按键是否按下
  139.         {
  140.                 rotary_encoder_delay10ms();//若按键按下,则消抖
  141.                 if(!ROTARY_ENCODER_SW)//再次检查按键是否按下
  142.                 {
  143.                         while(!ROTARY_ENCODER_SW);//按键按住则程序卡死在这里
  144.                         rotary_encoder_delay10ms();//松手消抖
  145.                        
  146.                         LCD1602_print_char(0,0,'O');
  147.                         LCD1602_print_char(0,1,'N');
  148.                         LCD1602_print_char(0,2,' ');
  149.                        
  150.                         while(ROTARY_ENCODER_SW)//现在扫描旋转编码器
  151.                         {       
  152.                                 //扫描旋转编码器,返回值为1代表正转,返回值为0代表反转,返回值为0xFF代表未旋转或旋转错误
  153.                                 temp=scan_rotary_encoder();
  154.                                
  155.                                 if(temp!=0xFF)//去除旋转编码器错误码
  156.                                 {
  157.                                         //利用 unsigned char 特性
  158.                                         //当temp为255时,再加1则溢出,变为0
  159.                                         //同理,当temp为0时,再减1则变为255
  160.                                         if(temp==0x01) ++dat;
  161.                                         if(temp==0x00) --dat;
  162.                                        
  163.                                         //LCD1602打印字符(行,列,字符)
  164.                                         LCD1602_print_char(1,0,'0'+(dat/100%10));
  165.                                         LCD1602_print_char(1,1,'0'+(dat/10%10));
  166.                                         LCD1602_print_char(1,2,'0'+(dat/1%10));
  167.                                 }
  168.                         }
  169.                         rotary_encoder_delay10ms();//按键按下,则消抖
  170.                        
  171.                         while(!ROTARY_ENCODER_SW);//按键按住则程序卡死在这里
  172.                         rotary_encoder_delay10ms();//松手消抖
  173.                        
  174.                         LCD1602_print_char(0,0,'O');
  175.                         LCD1602_print_char(0,1,'F');
  176.                         LCD1602_print_char(0,2,'F');
  177.                 }
  178.         }
  179. }
复制代码

链接:
游客,本帖隐藏的内容需要积分高于 1 才可浏览,您当前积分为 0

全部资料51hei下载地址:

旋转编码器测试代码.rar (1.44 MB, 下载次数: 125)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:658665 发表于 2020-7-21 21:32 | 显示全部楼层
我实在找不到编辑按钮在哪了,直接发吧

旋转编码器V1.1版
测试平台:STC89C516单片机        12MHz晶振
其他平台可能要在RotaryEncoder.c文件中修改延时函数
接口定义在port.h文件中

版本特性:

1.旋转编码器程序加入旋转编码器按键的单击双击以及长按
2.精简旋转编码器代码
旋转编码器V1.1.rar (35.09 KB, 下载次数: 46)
回复

使用道具 举报

ID:748377 发表于 2020-5-10 17:21 | 显示全部楼层
谢谢分享,我试了下在仿真里数值似乎没有变化啊
回复

使用道具 举报

ID:658665 发表于 2020-5-11 08:12 | 显示全部楼层
深海咸鱼 发表于 2020-5-10 17:21
谢谢分享,我试了下在仿真里数值似乎没有变化啊

这段代码我没有用仿真测试过,都是用实物测试的,下面的GIF是实物测试
b26cdbb381f849e2a540218d01265ba5 00_00_00-00_00_30.gif

回复

使用道具 举报

ID:799404 发表于 2020-7-9 11:43 | 显示全部楼层
这不是正交信号吗,怎么你编码器的丝印都是串行输出的
回复

使用道具 举报

ID:514317 发表于 2020-7-22 08:30 | 显示全部楼层
楼主用的中断方式   占用1个中断     代码中的11   00这两个状态很关键      配合01 10就能很准确的判断方向
回复

使用道具 举报

ID:56960 发表于 2020-7-22 09:28 | 显示全部楼层
我赞同楼上的意见,根据状态 判断出   旋转方向,是正转还是反转
回复

使用道具 举报

ID:833183 发表于 2020-10-26 16:44 | 显示全部楼层
楼主e6b2cwz6c编码器用过吗?这种三相的脉冲输出应该怎么做
回复

使用道具 举报

ID:605142 发表于 2021-2-27 15:15 | 显示全部楼层
GGG.gif
用103做了一个,用按钮模拟是对的,我没有编码器,用坏鼠标里的滚轮接上,竟然乱跑,一会加一会减,难道是滚轮坏了
回复

使用道具 举报

ID:605142 发表于 2021-2-27 15:28 | 显示全部楼层
51hei图片20210227152550.png
拆开后是这个样子了,看来要打磨一下
回复

使用道具 举报

ID:275826 发表于 2021-3-2 09:10 | 显示全部楼层
太复杂了,看了头通,可以优化吧
回复

使用道具 举报

ID:743823 发表于 2021-6-12 08:14 | 显示全部楼层
楼主,你好,我需要增加2个LED灯,正转=LED1;反正=LED2;来测试编码器方向,如何增加,求大家指点下
回复

使用道具 举报

ID:789448 发表于 2021-12-25 15:28 | 显示全部楼层
好东西!给无私奉献点个赞!
回复

使用道具 举报

ID:69115 发表于 2021-12-26 00:41 | 显示全部楼层
这个旋转编码器程序程序,写的太复杂了.应该几行C代码就可以实现.
当A相在刚导通的瞬间,同时检测B相是否也接通,若没有接通,说明A相先接通是正转
若B相已经接通,说明B相已经先接通了,是反转
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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