1、 通过输出波形图可知每个运动周期的时序为 顺时针运动 逆时针运动 A B 1 1 0 1 0 0 1 0 A B 1 1 1 0 0 0 0 1 静止状态为11 或00, A异或B的结果为0(注1) 单片机可利用定时器中断来检测A和B的状态,中断时间在5~20ms之间均可。 当检测到A^B = 0时,表示为静止状态,记下A和B的状态。 当检测到A^B
2、 1时,表示有转动,读取AB的状态,如果AB是从11到01或者是从00到10则为正转,反之如果AB是从11到10或者是从00到01则为反转。 此方法比较简单可靠,可以检测转动一格又可以检测快速转动。 注1: 异或运算 异或的运算方法是一个二进制运算,C语言中用A^B表示A异或B: 1^1=0 0^0=0 1^0=1 0^1=1 两者相等为0,不等为1. 也许是屎上最简单的旋转编码器程序, 占用一个外中断 #define ROTATE_A PIND.2 #define ROTATE_B PIND.3 uchar CW=0; uchar CCW=0;
3、 // External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { if(ROTATE_A!=ROTATE_B) { CW++; } else CCW++; } void main(void) { if ((CW|CCW)!=0) { DATA=DATA+CW-CCW; } CW=0;
4、 CCW=0; delay_ms(50); } ////////////////////////////////////////// 占用一个外中断,电平变化触发,CW是顺时针转过的脉冲,CCW是逆时针 每50ms处理一下数值,如果想要出错,起码脉冲时间要比50ms/256短才行,手指是没可能达到这速度 实际应用中感觉很爽 //****************************************************************************** // 旋转编码器脉冲计数程序,在805
5、1上通过外部中断0实现 // 特别说明:适应于旋转编码器脉冲频率较低的场合(对于12MHz晶体,大致可以支持 4KHz // 以下的旋转编码器脉冲频率),若旋转编码器脉冲频率更高,建议采用计数器 // T0和T1分别实现正反向计数,此时一般需要附加少量外部电路的配合 // 以下代码仅供参考,由此产生的任何后果,本人不承担任何责任 //****************************************************************************** #include "reg51.h" long
6、counter=0; //旋转编码器的脉冲计数值,左转为正,右转为负 void main() { IT0 = 1; //外部中断0为边沿触发 EX0 = 1; //使能外部中断0 EA = 1; //使能中断
7、 while(1) { // 在这里写代码实现你想做的事,比如计数值的进一步处理等等等等 } } //****************************************************************************** // 延时函数delay(unsigned char dly) // 延时值与晶体频率有关,可以自己调整变量x的值以取得合适的单位延时值 //*****************************************************************
8、 void delay(unsigned char dly) { unsigned int x; while(dly--) { x = 1000; while(x--); } } //****************************************************************************** // 外部中断0的中断处理函数void ISR0() // 注意:旋转编码器的A接P3.2,B接P1.7(跟你图上一样不变) //********************
9、 void ISR0() interrupt 0 { if((P1&0x80) == 0x80) { delay(10); //消抖动,延时一会,确认P1.7仍然为高,如果频率比较高,延时要缩短 if((P1&0x80) == 0x80) counter++; } else { delay(10); //消抖动,延时一会,确认P1.7仍然为低,如果频率比较高,延时要缩短
10、 if((P1&0x80) == 0x00) counter--; } } 最近用到旋转编码器,在网上找了一大堆资料,发现这篇好文章。收藏到自己的空间待用。 [ME850扩展应用]旋转编码器计数程序(飞梭旋钮功能)-数码管显示 /******************************************************************* * * * ME850单片机开发实验仪演示
11、程序 - 旋转编码器计数程序 * * * * 3位数码管显示 * * * * MCU: AT89S52 晶振:11.0592MHz
12、 * * * 版本:V1.1 (2011/07/14) * * 作者:tangyuan * * 网站: / * * * * 邮箱:893@ * *
13、 * *【版权】东莞市林积为实业投资有限公司 * *【声明】此程序仅用于学习与参考,引用请注明版权和作者信息! * * * ******************************************************************** *
14、 * * 功能简述: (飞梭旋钮功能) * * 当旋钮顺时针旋转时,计数值增加。达到最大值255后,不再响应。 * * 当逆钮顺时针旋转时,计数值减小。达到最小值0后,不再响应。 * * 当按下旋钮时,将计数值清零(归位)。 * *
15、 *
*******************************************************************/
#include
16、90,0xff }; char code reserve[3]_at_ 0x3b; //保留0x3b开始的3个字节 unsigned char counter = 0; //编码器脉冲计数 unsigned char n,shift; /********************************************************** ms延时子函数 **********************************************************/ void delayms(unsigned int ms) { un
17、signed char k; while (ms--) { for (k = 0; k < 114; k++) ; } } /********************************************************** 扫描编码器子函数 在编码器引脚A为低电平期间: 编码器引脚B从0到1为正转,编码器引脚B从1到0为反转。 **********************************************************/ void scan_encoder(void) { stat
18、ic bit Curr_encoder_b; //定义一个变量来储存当前B信号 static bit Last_encoder_b; //定义一个变量来储存上次B脚信号 static bit updata= 0; if( PINA && PINB) //编码器无转动退出 { updata = 0; return; } Last_encoder_b = PINB; //记录B信号 while(!PINA) //等待A由低变高
19、{ Curr_encoder_b = PINB; //记录等待期间的B信号(指当前B信号) updata = 1; } if(updata) { updata = 0 ; if( (Last_encoder_b == 0)&&(Curr_encoder_b== 1) ) //B从0到1为正转 { if(counter == 255) return; counter++; //正转计数加 } else if( (Last
20、encoder_b == 1)&&(Curr_encoder_b == 0) ) //B从1到0为反转 { if(counter == 0) return; counter--; //反转计数减 } } } /********************************************************** 主函数 **********************************************************/ void main(void)
21、 { P0 = 0xff; P1 = 0xff; P2 = 0xff; T2CON = 0x00; //设置T2CON寄存器 TH2 = 0xfc; //1ms定时 TL2 = 0x66; ET2 = 1; //启用Timer2中断 EA = 1; //总中断允许 TR2 = 1; //启动定时器2 counter = 0
22、 //计数单元清零 while(1) { scan_encoder(); if(! PIND) //当按下旋钮时 { counter = 0; //计数单元清零(归位) delayms(10); } } } /********************************************************* Timer2中断函数 ******************************
23、/ void timer2() interrupt 5 { TR2 = 0; TF2 = 0; //手工清中断标志 TH2 = 0xfc; //1ms定时常数 TL2 = 0x66; if(n >= 3) //3位数码管显示 { n = 0; shift = 0xfe; //送位码初值
24、 P2 = 0xff; //关闭显示 } else { display[0] = counter%10; //个位数据 display[1] = (counter%100)/10; //十位数据 display[2] = counter/100; //百位数据 if(display[2] == 0) { display[2] = 0x0a; //百位为0,不显示 if(disp
25、lay[1] == 0) display[1] =0x0a; //十位为0,不显示 } P0 = LEDData[display[n++]]; //送段码 P2 = shift; //送位码 shift = (shift<<1)|0x01; //调整位码 } TR2 = 1; } /*********************************************************/ ;*****
26、 ;* * ;* ME850单片机开发实验仪演示程序 - 旋转编码器计数程序 * ;* * ;* 3位数码管显示
27、 * ;* * * 版本:V1.1 (2011/07/14) * * 作者:tangyuan * * 网站: / * * * * 邮箱:893@
28、 * * * *【版权】东莞市林积为实业投资有限公司 * *【声明】此程序仅用于学习与参考,引用请注明版权和作者信息! * ;* * ;******************************************************************** ;*
29、 * ;* 功能简述: (飞梭旋钮功能) * ;* 当旋钮顺时针旋转时,计数值增加。达到最大值255后,不再响应。 * ;* 当逆钮顺时针旋转时,计数值减小。达到最小值0后,不再响应。 * ;* 当按下旋钮时,将计数值清零(归位)。 * ;*
30、 * ;******************************************************************** -------------------------------------------------------------------------------- 以下为回复后可浏览的内容: $ INCLUDE(TIMER2.INC) PINA BIT P1.0 PINB BIT P1.1 P
31、IND BIT P1.2 LAST_B BIT 20H.0 CURR_B BIT 20H.1 UPDATA BIT 20H.2 DISPLAY EQU 40H COUNT EQU 45H ;********************************************************** ORG 0000H AJMP MAIN ORG 002BH AJMP TIMER
32、2 ORG 0050H ;********************************************************** ; 主程序 ;********************************************************** MAIN: MOV SP,#60H ;设置堆栈指针 MOV P0,#0FFH ;端口初始化 MOV P2,#0FFH MOV P1,#0FFH MOV COU
33、NT,#00H ;清计数单元 MOV R0,#DISPLAY ;获得显示单元首地址 MOV R1,#0FEH ;位码初值 MOV T2CON,#00H ;设置T2CON寄存器 MOV TH2,#0FCH ;1ms定时常数 MOV TL2,#66H SETB ET2 ;允许Timer2中断 SETB EA ;允许总中断
34、 SETB TR2 LOOP: ACALL ENCODER_SCAN JB PIND,LOOP ;判断轴向开关是否按下 MOV COUNT,#00H ;清计数单元(归位) AJMP LOOP RET ;********************************************************** ; 编码器扫描子程序 ; 在编码器引脚A为低电平期间: ; 编码器引脚B从0变到1为正转,编码器引脚B从1变到0为反转。
35、 ;********************************************************** ENCODER_SCAN: MOV P1,#0FFH NOP NOP MOV A,P1 ANL A,#03H CJNE A,#03H,SCAN1 AJMP SCAN_END ;旋钮没有旋转退出 SCAN1: JB PINB,SCAN1A ;记录B脚电平 CLR LA
36、ST_B AJMP SCAN2 SCAN1A: SETB LAST_B SCAN2: JB PINA,SCAN3 SETB UPDATA ;当旋钮旋转时,A脚有低电平产生 JB PINB,SCAN2A ;在A为低电平期间,循环记录B脚电平 CLR CURR_B AJMP SCAN2 SCAN2A: SETB CURR_B AJMP SCAN2 SCAN3:
37、 JNB UPDATA,SCAN_END ;旋钮没有旋转(没有新数据产生)退出 JNB CURR_B,SCAN5 ; JB LAST_B,SCAN_END MOV A,COUNT CJNE A,#0FFH,SCAN4 ;判断是否达到最大值 AJMP SCAN_END SCAN4: INC COUNT ;顺时针旋转,计数值加1 AJMP SCAN_END SCAN5: JNB LAST
38、B,SCAN_END MOV A,COUNT CJNE A,#00H,SCAN6 ;判断是否达到最小值 AJMP SCAN_END SCAN6: DEC COUNT ;逆时针旋转计数值减1 SCAN_END: CLR UPDATA ;清更新数据标志 RET ;********************************************************** ; Timer2 中断服务子程序 ;*
39、 TIMER2: CLR TR2 PUSH ACC PUSH B CLR TF2 ;清中断标志 MOV TH2,#0F8H ;2ms定时常数 MOV TL2,#0CCH MOV A,R1 JB ACC.3,T2_1 ;判3位数码管是否显示完? M
40、OV R0,#DISPLAY ;获得显示单元首地址 MOV R1,#0FEH ;位码初值 MOV P2,#0FFH ;关闭显示 AJMP T2_END T2_1: MOV A,COUNT ;转换计数值数据 MOV B,#100 DIV AB MOV DISPLAY+2,A ;百位数据 XCH A,B ;数据交换
41、MOV B,#10 DIV AB MOV DISPLAY+1,A ;十位数据 MOV DISPLAY,B ;个位数据 MOV A,DISPLAY+2 ;百位数据 CJNE A,#00H,T2_2 MOV DISPLAY+2,#0AH ;百位数据为0,不显示 MOV A,DISPLAY+1 ;十位数据 CJNE A,#00H,T2_2 MOV DISPLAY+1,#
42、0AH ;十位数据为0,不显示 T2_2: MOV A,@R0 ;取显示数据 MOV DPTR,#TABLE ;获得表头 MOVC A,@A+DPTR ;查表获得段码显示数据 MOV P0,A ;送段码 MOV P2,R1 ;送位码 MOV A,R1 ;准备下一位显示的位码 RL A MOV R1,A
43、 INC R0 ;取下一个显示单元地址 T2_END: POP B POP ACC SETB TR2 RETI ;********************************************************** TABLE: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H DB 0FFH ; '熄灭' ;********************************************************** END ;结束 ;**********************************************************






