前几天一直因为光电编码器检测犯愁,因本人是菜鸟,只会用51的汇编在论坛也请教了不少的高手,不过大部分人都说可以但检测速度不行等等,现在吧我的程序发上来和大家共同研究讨论,本例分辨率0.05MM(精度可可以改的更高,但我们要求精度没有那么高)
增量式旋转光电编码器 5V 2500线,线与输出方式。
因本程序最终是用在产品上,主处理器还要处理其他程序,顾采用2个51单片机完成。如果只是做实验用完全可以用一个D触发器比如4013等替代AT89C2051,不过没有倍频。
程序完成后的显示效果:
(原文件名:图像001.jpg)
(原文件名:图像002.jpg)
(原文件名:图像003.jpg)
(原文件名:图像004.jpg)
光电编码器输出正交信号方式如下图所示:
顺时针旋转A超前B相信号90°:
A: _|--|__|--|_
B: __|--|__|--|
逆时针旋转B相信号超前A相信号90°:
A:__|--|__|--|_
B:_|--|__|--|__
下面是AT89C2051检测并进行二倍频程序:
;采用外部中断方式
ORG 00H
LJMP MAIN
ORG 03H
LJMP INT0
ORG 13H
LJMP INT1
ORG 50H
MAIN: MOV SP,#40H
MOV P3,#0FFH
MOV IE,#10000101B ;设定外部中断
MOV TCON,#00000101B
SETB EA
MA1: MOV P1,#0FFH
MOV P3,#0FFH
SJMP MA1
;*******************
INT0: PUSH PSW
CLR EA
I0: JNB P1.0,FAN
CLR P3.4
SJMP INT0END
FAN: CLR P3.5
INT0END:
POP PSW
SETB EA
MOV P3,#0FFH
RETI
INT1: PUSH PSW
CLR EA
JNB P1.0,ZHENG
CLR P3.5
SJMP INT1END
ZHENG: CLR P3.4
INT1END:
POP PSW
SETB EA
MOV P3,#0FFH
RETI
处理后由P3.4\P3.5分别在顺时针和逆时针时输出脉冲信号,送入AT89C51的T0,T1进行计数
下面是计数及处理程序
AT89C51负责信号处理并在12864液晶显示模块上把实际值显示出来,分辨率0.05MM
液晶模块用的金鹏的OCMJ4X8C
RS EQU P0.0 ;选择I/O口定义,RS为指令/数据选择端
RW EQU P0.1
E EQU P0.2 ;选择I/O口定义,E为使能端
PSB EQU P0.3
RESET EQU P0.4
FIRST_COL EQU 36H ;定义字符/汉字显示起始行
FIRST_ROW EQU 37H ;定义字符/汉字显示起始列
WORD_WID EQU 38H ;定义字符/汉字显示长度
WORD_LIN EQU 39H ;定义字符/汉字显示行数
FIRST_ADD EQU 3AH ;定义字符/汉字显示起始位置
START_ADD EQU 3BH ;起始位置缓存单元
FIRST_LIN EQU 3CH ;起始行位置缓存单元
A0 EQU 30H
A1 EQU 31H ;
A2 EQU 32H
B0 EQU 33H
B1 EQU 34H
Z0 EQU 35H ;
Z5 BIT 20H.0 ;正反负数标志
ORG 00H
LJMP MAIN
ORG 0BH
LJMP TT0
ORG 1BH
LJMP TT1
ORG 50H
MAIN: MOV SP,#40h
SETB RESET
SETB PSB
CLR RW
MOV A0,#00H
MOV A1,#00H
MOV A2,#00H
MOV B0,#00H
MOV B1,#00H
CLR Z5
MOV TMOD,#66H ;定时器定时方式2,自动装载
MOV TH0,#0ECH ;计够20个脉冲产生次中断
MOV TL0,#0ECH ;设检测盘周长为250MM,1P脉冲为0.05MM
MOV TH1,#0ECH ;2P脉冲为0.1MM,20P为1MM,200P为10MM
MOV TL1,#0ECH
SETB TR0
SETB TR1
SETB ET1
SETB ET0
SETB EA
QIU1: LCALL INITIL ;调用系统初始化程序
MOV A, #0CH ;开显示,关游标
LCALL INPUT
LCALL DELAY01
MOV A, #01H ;DDRAM清零,DDRAM地址计数器到00H
LCALL INPUT
LCALL DELAY01
LCALL QIU2
QIU3: LCALL INITIL ;调用系统初始化程序
MOV A, #0CH ;开显示,关游标
LCALL INPUT
LCALL DELAY01
MOV A, #01H ;DDRAM清零,DDRAM地址计数器到00H
LCALL INPUT
LCALL DELAY01
MOV FIRST_ADD,#00H ;设定字符/汉字显示起始位置为第一个显示单元
MOV FIRST_LIN,#01H ;设定字符/汉字显示起始位置为第一行
MOV word_WID,#08H ;每行显示汉字个数
MOV word_LIN,#04H ;显示行数
MOV START_ADD,#00H ;清首个显示地址缓存单元
SETB TR0
LJMP QIU2
;-----------------**************
QIU: LJMP QIU1
;*******************************
TT0: PUSH PSW ;计够20P脉冲中断发生即1MM
PUSH A
MOV A,A2
JNZ T00
MOV A,A1
JNZ T00
MOV A,A0
JNZ T00
CLR Z5
T00: JB Z5,T02
MOV A,A0
ADD A,#01H
DA A
MOV A0,A
CJNE A,#00H,TT0END ;够100即100mm
;MOV A0,#00H
MOV A,A1
ADD A,#01H
DA A
MOV A1,A
CJNE A,#00H,TT0END ;够100即10000MM=10M
; MOV A1,#00H
MOV A,A2
ADD A,#01H
DA A
MOV A2,A
CJNE A,#03H,TT0END ;够3即30M
MOV A2,#00H
MOV A1,#00H
MOV A0,#00H
CLR Z5
SJMP TT0END
T02: MOV A,A0
ADD A,#99H ;-1程序
DA A
MOV A0,A
CJNE A,#99H,TT0END ;有借位产生执行下面程序
; MOV A0,A
MOV A,A1
ADD A,#99H
DA A
MOV A1,A
CJNE A,#99H,TT0END
; MOV A1,#00H
MOV A,A2
JNZ T03
ADD A,#99H
DA A
MOV A2,A
CJNE A,#99H,TT0END
MOV A2,#00H
MOV A1,#00H
MOV A0,#00H
T03: CLR Z5
TT0END:
POP A
POP PSW
RETI
;********************************
TT1: PUSH PSW
PUSH A
MOV A,A2
JNZ T10
MOV A,A1
JNZ T10
MOV A,A0
JNZ T10
SETB Z5
T10: JB Z5,T11
MOV A,A0
ADD A,#99H
DA A
MOV A0,A
CJNE A,#99H,TT1END
MOV A,A1
ADD A,#99H
DA A
MOV A1,A
CJNE A,#99H,TT1END
MOV A,A2
ADD A,#99H
DA A
MOV A2,A
CJNE A,#99H,TT1END
MOV A2,#00H
MOV A1,#00H
MOV A0,#00H
T110: SETB Z5
SJMP TT1END
T11: MOV A,A0
ADD A,#01H
DA A
MOV A0,A
CJNE A,#00H,TT1END ;够100即100mm
MOV A0,#00H
MOV A,A1
ADD A,#01H
DA A
MOV A1,A
CJNE A,#00H,TT1END ;够100即10000MM=10M
MOV A1,#00H
MOV A,A2
ADD A,#01H
DA A
MOV A2,A
CJNE A,#00H,TT1END ;够100即100M
MOV A2,#00H
SETB Z5
TT1END:
POP A
POP PSW
RETI
;**********************************************************
INITIL: LCALL DELAY ;延时
;首先选择基本指令集
MOV A, #30H ;30---基本指令操作
LCALL INPUT ;调写入子程序
LCALL DELAY01
MOV A, #01H ;指令#01H为:清除屏幕文字,把地址指针指向00H单元
LCALL INPUT ;调写入子程序
LCALL DELAY01
MOV A, #06H ;指定在资料写入或读取时,设定游标的移动方向及指定显示的移位
LCALL INPUT
LCALL DELAY01
RET
;-----------------
;汉字显示子程序
;---------------
QIU2: ;********1*********
MOV A,#80H
LCALL INPUT
MOV R1,#08H
MOV DPTR,#TA
WORD1: CLR A ;因为要连续输入机内码高位(区码)、低位(位码)
MOVC A, @A+DPTR ;所以要输入两次数据,如果是字符就是输入两个字符字符代码可以看说明书
LCALL DISPL ;DATA INPUT
INC DPTR ;显示地址会自动加一,如果连续写就不用再输入地址,空白可用某空白汉字或字符代替
CLR A
MOVC A, @A+DPTR
LCALL DISPL ;DATA INPUT
LCALL DELAY01
INC DPTR
DJNZ R1,WORD1
;**********2***********
MOV A,#90H
LCALL INPUT
MOV DPTR,#TB1
MOV R1,#08H
WORD2: CLR A ;因为要连续输入机内码高位(区码)、低位(位码)
MOVC A, @A+DPTR ;所以要输入两次数据,如果是字符就是输入两个字符字符代码可以看说明书
LCALL DISPL ;DATA INPUT
INC DPTR ;显示地址会自动加一,如果连续写就不用再输入地址,空白可用某空白汉字或字符代替
CLR A
MOVC A, @A+DPTR
LCALL DISPL ;DATA INPUT
LCALL DELAY01
INC DPTR
DJNZ R1,WORD2
;*********3************
MOV A,#88H
LCALL INPUT
MOV DPTR,#TB2
MOV R1,#08H
WORD3: CLR A ;因为要连续输入机内码高位(区码)、低位(位码)
MOVC A, @A+DPTR ;所以要输入两次数据,如果是字符就是输入两个字符字符代码可以看说明书
LCALL DISPL ;DATA INPUT
INC DPTR ;显示地址会自动加一,如果连续写就不用再输入地址,空白可用某空白汉字或字符代替
CLR A
MOVC A, @A+DPTR
LCALL DISPL ;DATA INPUT
LCALL DELAY01
INC DPTR
DJNZ R1,WORD3
;**********位移显示处理区************
HUANSUAN: CLR C
MOV A,TL0
MOV B,TL1
SUBB A,B
JNC SS0 ;有借位说明A是负数,即补码,要调整后使用
CPL A
INC A
SS0: MOV Z0,A
;************小数转换****************
CLR C
MOV A,Z0
MOV B,#5
MUL AB
MOV Z0,A
MOV A,Z0
MOV B,#100
DIV AB
MOV A,B
MOV B,#10
DIV AB
MOV B0,A
MOV B1,B
;********至此小数位转换完毕***********
JNB Z5 ,SS4
MOV A,#89H
LCALL INPUT
CLR A
MOV DPTR,#TA0
MOVC A,@A+DPTR
LCALL WE
CLR A
MOV DPTR,#TA1
MOVC A,@A+DPTR
LCALL WE
SJMP SS5
SS4: MOV A,#89H
LCALL INPUT
CLR A
MOV DPTR,#TA0
MOVC A,@A+DPTR
LCALL WE
MOV A,#20H
LCALL WE
SS5: MOV A,#8AH
LCALL INPUT
MOV DPTR,#TAB1
MOV A,A2
LCALL WD1
MOV A,A2
LCALL WD2
MOV A,A1 ;8B
LCALL WD1
MOV A,A1
LCALL WD2 ;8C
MOV A,A0
LCALL WD1
MOV A,A0
LCALL WD2
MOV A,#8EH
LCALL INPUT
MOV A,B0
LCALL WD2
MOV A,B1
LCALL WD2
;**********4*************
MOV A,#98H
LCALL INPUT
MOV DPTR,#TAB1
; MOV R1,#08H
WORD4: ;CLR A ;因为要连续输入机内码高位(区码)、低位(位码)
; MOVC A, @A+DPTR ;所以要输入两次数据,如果是字符就是输入两个字符字符代码可以看说明书
; LCALL DISPL ;DATA INPUT
; INC DPTR ;显示地址会自动加一,如果连续写就不用再输入地址,空白可用某空白汉字或字符代替
; CLR A
; MOVC A, @A+DPTR
; LCALL DISPL ;DATA INPUT
; LCALL DELAY01
; INC DPTR
; DJNZ R1,WORD4
MOV A,TL0
LCALL WD1
MOV A,TL0
LCALL WD2
MOV A,TL1
LCALL WD1
MOV A,TL1
LCALL WD2 ;2
MOV A,#20H
LCALL WE
MOV A,#20H
LCALL WE
MOV A,A2
LCALL WD1
MOV A,A2
LCALL WD2
MOV A,A1
LCALL WD1
MOV A,A1
LCALL WD2 ;2
MOV A,A0
LCALL WD1
MOV A,A0
LCALL WD2
MOV A,#20H
LCALL WE
MOV A,#20H
LCALL WE ;2
JB Z5,S0
MOV A,#00H
LCALL WD1
MOV A,#00H
LCALL WD2
LJMP QIU3
S0: MOV A,#11H
LCALL WD1
MOV A,#11H
LCALL WD2
LJMP QIU3
;*************************
WD1: ANL A,#0F0H
SWAP A
MOVC A,@A+DPTR
LCALL DISPL
LCALL DELAY01
RET
WD2: ANL A,#0FH
MOVC A,@A+DPTR
WE: LCALL DISPL
LCALL DELAY01
RET
WR: CLR A
MOVC A,@A+DPTR
LCALL DISPL
INC DPTR
CLR A
MOVC A,@A+DPTR
LCALL DISPL
CLR A
LCALL DELAY01
RET
READ: MOV P3, #0FBH ;读数据子程序
;p3--CONTRAL I/O
NOP ;p3=11111011B RS=1 R/W=1 READ DATA
SETB E ;E=E(I/O)
LCALL DELAY01
MOV A, P1 ;p1=DATA(I/O)
NOP
CLR E
RET
;--------------------------------------
CHK_BUSY: CLR RS ;读忙状态子程序
SETB RW
SETB E
HEHE1: JB P1.7,HEHE1
CLR E
RET
;--------------------------------------
;写数据子程序
;----------------------------
DISPL: LCALL CHK_BUSY ;p3--CONTRAL I/O
NOP ;p3=11111001B RS=1 WRITE DATA
SETB RS
CLR RW
SETB E ;E=E(I/O)
MOV P1, A ;p1=DATA(I/O)
LCALL DELAY01
NOP
CLR E
NOP
MOV P1,#0FFH
RET
;--------------------------------------
;写指令子程序
;----------------------------
INPUT: LCALL CHK_BUSY ;以确保上一指令/数据模块已经接收处理完
;p3--CONTRAL I/O
NOP ;p3=11111000B RS=0 WRITE INSTRUTION
CLR RS
CLR RW
SETB E ;E=E(I/O)
MOV P1, A ;p1=DATA(I/O)
LCALL DELAY01
NOP
CLR E
NOP
MOV P1,#0FFH
RET
;----------------------
;DELAY TIME
;---------------------
DELAY: MOV R5,#03H
C0: MOV R6, #0FFH
C1: MOV R7, #0FFH
C2: DJNZ R7, C2
DJNZ R6, C1
NOP
NOP
DJNZ R5, C0
RET
DELAY01: MOV R6, #6
D5: MOV R7, #08h
D6: DJNZ R7, D6
DJNZ R6, D5
RET
;------------------
DELAY02: MOV R6, #6
D52: MOV R7, #18h
D62: DJNZ R7, D62
DJNZ R6, D52
RET
;--------------------------------------
TA: DB '程序制作山东济南'
TB1: DB 'xiaomage_2000'
TB2: DB '长: . mm'
TB3: DB ' '
TA0: DB ':'
TA1: DB '-'
TAB1;pB "0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F";
TAB: DB '.'
END |