标题: 51单片机旋转编码器模块测试代码 [打印本页]
作者: pengxxx 时间: 2020-5-5 15:28
标题: 51单片机旋转编码器模块测试代码
模块图片
测试平台:STC89C516单片机 晶振:12MHz
其他单片机(如STC12单片机)或晶振,请在程序的LCD1602.c和rotary_encoder.c文件中修改延时函数
连线如图(连线的接口在程序的port.h文件里)
测试代码功能:
将程序下载到开发板,LCD显示0FF,显示数字000.
按下旋转编码器的按键,OFF变为ON,转动旋转编码器就可以在LCD1602中看到数字变化.
再次按下旋转按键,ON变为OFF,此时转动旋转编码器不可以在LCD1602中看到数字变化.
结尾:
测试程序的注释也比较详细,自我感觉这个程序对较慢的转速和正常的转速的兼容性都比较好,只有极少数情况出现丢步,已经实现较好的实现了旋转编码器的功能了.
本帖测试程序参考过以下帖子
http://www.51hei.com/bbs/dpj-93972-1.html
单片机源程序如下:
- #include <intrins.h>
- #include "public.h"
- #include "rotary_encoder.h"
- #include "LCD1602.h"
- #include "port.h"
- void rotary_encoder_delay50us()//12.000MHz
- {
- u8 i;
- _nop_();
- i=22;
- while(--i);
- }
- void rotary_encoder_delay10ms() //12.000MHz
- {
- u8 i,j;
- i=20;
- j=113;
- do
- {
- while (--j);
- }while (--i);
- }
- //旋转编码器初始化
- void rotary_encoder_init()
- {
- ROTARY_ENCODER_CLK=1;
- ROTARY_ENCODER_DT=1;
- ROTARY_ENCODER_SW=1;
-
- IT0=1;
- EX0=1;
- EA=1;
-
- LCD1602_print_char(0,0,'O');
- LCD1602_print_char(0,1,'F');
- LCD1602_print_char(0,2,'F');
-
- LCD1602_print_char(1,0,'0'+0);
- LCD1602_print_char(1,1,'0'+0);
- LCD1602_print_char(1,2,'0'+0);
- }
- //扫描旋转编码器,返回值为1代表正转,返回值为0代表反转,返回值为0xFF代表未旋转或旋转错误
- u8 scan_rotary_encoder()
- {
- u8 rotary_encoder_state;//旋转编码器状态
- u16 forced_out;//强制退出
-
- //旋转编码器状态
- //如果在刚开始ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT都为1,则状态为1
- //如果在刚开始ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT都为0,则状态为0
- if((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT)) rotary_encoder_state=1;
- else if((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)) rotary_encoder_state=0;
-
- //ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT为同一电平时检测
- if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
- {
- //用最多150ms时间来等待ROTARY_ENCODER_CLK电平或ROTARY_ENCODER_DT电平变化(此时AB为11或00)
- forced_out=3000;
- while(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
- {
- --forced_out;
- rotary_encoder_delay50us();
- if(!forced_out) return 0xFF;//超时则强制退出,返回错误码
- }
-
- //每次电平变化必定旋转了编码器,电平变化后要消抖
- rotary_encoder_delay10ms();
-
- //当ROTARY_ENCODER_CLK为低电平,ROTARY_ENCODER_DT为高电平时
- if((!ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))
- {
- //用150ms时间来等待ROTARY_ENCODER_DT电平变化(此时AB为01)
- forced_out=3000;
- while((!ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))
- {
- --forced_out;
- rotary_encoder_delay50us();
- if(!forced_out) return 0xFF;//超时则强制退出,返回错误码
- }
-
- //每次电平变化必定旋转了编码器,电平变化后要消抖
- rotary_encoder_delay10ms();
-
- //当ROTARY_ENCODER_CLK为低电平,而且ROTARY_ENCODER_DT也为低电平
- //或ROTARY_ENCODER_CLK为高电平,而且ROTARY_ENCODER_DT也为高电平(AB为11或00)
- //此时 AB从11到01到00 或 AB从00到01到11
- if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
- {
- //如果旋转编码器的状态为1则返回1,代表正转一下
- if(rotary_encoder_state) return 1;
- //如果旋转编码器的状态为0则返回0,代表反转一下
- else return 0;
- }
- //若AB不为11或不为00则返回旋转编码器错误码
- else return ROTARY_ENCODER_ERROR;
- }
- //当ROTARY_ENCODER_CLK为高电平,ROTARY_ENCODER_DT为低电平时
- else
- {
- //当ROTARY_ENCODER_CLK为高电平,ROTARY_ENCODER_DT为低电平时
- if((ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT))
- {
- //用150ms时间来等待ROTARY_ENCODER_CLK电平变化(此时AB为10)
- forced_out=3000;
- while((ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT))
- {
- --forced_out;
- rotary_encoder_delay50us();
- if(!forced_out) return 0xFF;//超时则强制退出,返回错误码
- }
-
- //每次电平变化必定旋转了编码器,电平变化后要消抖
- rotary_encoder_delay10ms();
-
- //当ROTARY_ENCODER_CLK为低电平,而且ROTARY_ENCODER_DT也为低电平
- //或ROTARY_ENCODER_CLK为高电平,而且ROTARY_ENCODER_DT也为高电平(AB为11或00)
- //此时 AB从11到10到00 或 AB从00到10到11
- if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
- {
- //如果旋转编码器的状态为0则返回1,代表正转一下
- if(!rotary_encoder_state) return 1;
- //如果旋转编码器的状态为1则返回0,代表反转一下
- else return 0;
- }
- //若AB不为11或不为00则返回旋转编码器错误码
- else return ROTARY_ENCODER_ERROR;
- }
- }
- }
- //未响应返回旋转编码器错误码
- return 0xFF;
- }
- //旋转编码器中断
- void rotary_encoder_interrupt() interrupt 0
- {
- static u8 dat=0;
- u8 temp=0xFF;//临时变量先赋旋转编码器错误码的值
- if(!ROTARY_ENCODER_SW)//检查按键是否按下
- {
- rotary_encoder_delay10ms();//若按键按下,则消抖
- if(!ROTARY_ENCODER_SW)//再次检查按键是否按下
- {
- while(!ROTARY_ENCODER_SW);//按键按住则程序卡死在这里
- rotary_encoder_delay10ms();//松手消抖
-
- LCD1602_print_char(0,0,'O');
- LCD1602_print_char(0,1,'N');
- LCD1602_print_char(0,2,' ');
-
- while(ROTARY_ENCODER_SW)//现在扫描旋转编码器
- {
- //扫描旋转编码器,返回值为1代表正转,返回值为0代表反转,返回值为0xFF代表未旋转或旋转错误
- temp=scan_rotary_encoder();
-
- if(temp!=0xFF)//去除旋转编码器错误码
- {
- //利用 unsigned char 特性
- //当temp为255时,再加1则溢出,变为0
- //同理,当temp为0时,再减1则变为255
- if(temp==0x01) ++dat;
- if(temp==0x00) --dat;
-
- //LCD1602打印字符(行,列,字符)
- LCD1602_print_char(1,0,'0'+(dat/100%10));
- LCD1602_print_char(1,1,'0'+(dat/10%10));
- LCD1602_print_char(1,2,'0'+(dat/1%10));
- }
- }
- rotary_encoder_delay10ms();//按键按下,则消抖
-
- while(!ROTARY_ENCODER_SW);//按键按住则程序卡死在这里
- rotary_encoder_delay10ms();//松手消抖
-
- LCD1602_print_char(0,0,'O');
- LCD1602_print_char(0,1,'F');
- LCD1602_print_char(0,2,'F');
- }
- }
- }
复制代码
链接:
全部资料51hei下载地址:
旋转编码器测试代码.rar
(1.44 MB, 下载次数: 138)
作者: 深海咸鱼 时间: 2020-5-10 17:21
谢谢分享,我试了下在仿真里数值似乎没有变化啊
作者: pengxxx 时间: 2020-5-11 08:12
这段代码我没有用仿真测试过,都是用实物测试的,下面的GIF是实物测试
作者: wjianing 时间: 2020-7-9 11:43
这不是正交信号吗,怎么你编码器的丝印都是串行输出的
作者: pengxxx 时间: 2020-7-21 21:32
我实在找不到编辑按钮在哪了,直接发吧
旋转编码器V1.1版
测试平台:STC89C516单片机 12MHz晶振
其他平台可能要在RotaryEncoder.c文件中修改延时函数
接口定义在port.h文件中
版本特性:
1.旋转编码器程序加入旋转编码器按键的单击双击以及长按
2.精简旋转编码器代码
旋转编码器V1.1.rar
(35.09 KB, 下载次数: 47)
链接:https://pan.baidu.com/s/1DDse2uiioNi6ByMBjVnB2Q
提取码:peng
作者: lzzasd 时间: 2020-7-22 08:30
楼主用的中断方式 占用1个中断 代码中的11 00这两个状态很关键 配合01 10就能很准确的判断方向
作者: 沧海一粒 时间: 2020-7-22 09:28
我赞同楼上的意见,根据状态 判断出 旋转方向,是正转还是反转
作者: scorpioxz 时间: 2020-10-26 16:44
楼主e6b2cwz6c编码器用过吗?这种三相的脉冲输出应该怎么做
作者: hefq 时间: 2021-2-27 15:15
用103做了一个,用按钮模拟是对的,我没有编码器,用坏鼠标里的滚轮接上,竟然乱跑,一会加一会减,难道是滚轮坏了
作者: hefq 时间: 2021-2-27 15:28
拆开后是这个样子了,看来要打磨一下
作者: tyrl800 时间: 2021-3-2 09:10
太复杂了,看了头通,可以优化吧
作者: 985524550 时间: 2021-6-12 08:14
楼主,你好,我需要增加2个LED灯,正转=LED1;反正=LED2;来测试编码器方向,如何增加,求大家指点下
作者: zhycong 时间: 2021-12-25 15:28
好东西!给无私奉献点个赞!
作者: xiexugang 时间: 2021-12-26 00:41
这个旋转编码器程序程序,写的太复杂了.应该几行C代码就可以实现.
当A相在刚导通的瞬间,同时检测B相是否也接通,若没有接通,说明A相先接通是正转
若B相已经接通,说明B相已经先接通了,是反转
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |