AN #115 - Quadrature Decoder/Counter and Display |
|
Quadrature Decoder/Counter and Display
Application note submitted by Ger
Langezaal.

Here is some additional comment from Ger:
For the encoder I used the one from an old "mouse".
There are two of them in each mouse.
The resolution of both axes is 0.05 mm and the display lloks like this:
[ X -106.45 mm ] for example
For each ax I used an AT90S2313-10 with display(16 x 1).
The problem of the "missing pulse" during a change of the direction
within a pulsewidth,
I solved with software. Encoder phase-A generates an interrupt for both edges.
INT0 and INT1 are connected because the 2313 does not have a toggle interrupt
like the 4433.
In the ISR only the phase-B and phase-A need to be compared with each other.
If A = B then increment counter otherwise decrement counter.
The counter value converting to a value in mm is dependend of the used encode
and mechanical construction.
For the signal conditioning between the encoder and AVR I used
a 74HC14.
Download the source code. It is
also shown below:
'-------------------------------------------------------------------------------
' Filename : QuadrDec_1.0.bas
' Purpose :
Quadrature Decoder/Counter and Display
' Author : Ger
langezaal
' Date : 5 April
2002
' Compiler : BASCOM-AVR Rev. 1.11.6.5
'
'-------------------------------------------------------------------------------
'
' Algorithm:
' Interrupt on both edges of phase A
' Test phase B in ISR
' When phase B <> phase A then decrement counter
' When phase B = phase A then increment counter
' Convert counter value to displacment units
' Format value in string and display
'
'-------------------------------------------------------------------------------
'
' Setup for AT90S2313-10
'
' INT0 edge is set to rising edge
' INT1 edge is set to falling edge
' Encoder phase A to INT0 and INT1 (PD2 and PD3)
' Encoder phase B to PD4
' Pushbutton between Portd.5 and GND (display zero)
' LCD at PortB
'
' Example for PROXXON KT150 XY table:
' Displacement/rev = 2 mm
' Encoder resolution = 20 pulses/rev
' Interrupt on both pulse edges = 40 interrupts/rev
' Dial resolution: 2 mm / 40 = 0.05 mm
' The optical encoder came from a used mouse (two
available)
'
'-------------------------------------------------------------------------------
'
' Options/Compiler/Chip:
' HW Stack 48
' Soft Stack 8
' Framesize 16
'
'-------------------------------------------------------------------------------
'
$regfile = "2313def.dat"
$crystal = 10000000 '10 MHz
Dim X_axis As String * 8 'LCD format
string
Dim Axis_raw As Integer 'optical pulse counter
Dim Axis_mm As Integer 'counter value converted to mm
' 'range:
-327.65 to +327.65 mm
Const Enc_res = 20 * 2 'encoder resolution * 2
Const Conv_mm = 200 / Enc_res 'dial resolution
= 0.05 mm
Config Portb = Output
Config Portd = Input
Portd = 255 'enable Portd pullup's
Config Lcdbus = 4
Config Lcd = 16 * 1
Config Lcdpin = Pin , Db4 = Pb.4 , Db5 = Pb.5 , Db6 = Pb.6 , Db7 = Pb.7 , E = Pb.3 , Rs = Pb.2
Cls
Cursor Off
Phase_a Alias Pind.2 'INT0 also connected to Pind.3 = INT1
Phase_b Alias Pind.4
Axis_rst Alias Pind.5 'reset counter if low
'---[ Set Interrupt logic
]-----------------------------------------------------
Mcucr = &B00001011 'set interrupt edges
On Int0 Phase_a_edge 'ISR on rising edge
On Int1 Phase_a_edge 'ISR on falling edge
Enable Int0
Enable Int1
Enable Interrupts
'---[ Initialization
]----------------------------------------------------------
Lcd "X-Axis Rev.1.0"
Waitms 1000
Cls
Axis_raw = 0
'---[ Main program loop
]-------------------------------------------------------
Do
If Axis_rst = 0 Then Axis_raw = 0 'reset counter if low
Axis_mm = Axis_raw * Conv_mm 'convert to mm
X_axis = Str(axis_mm) '
X_axis = Format(x_axis , " +0.00") 'format without
leading zero's
' X_axis =
Format(x_axis , "+000.00") 'format with leading zero's
Locate 1 , 1
Lcd "X " ; X_axis ; " mm" 'display
Waitms 200
Loop
'-------------------------------------------------------------------------------
End
'---[ Interrupt Service Routine
]-----------------------------------------------
Phase_a_edge: 'Interrupt on rising and falling edge
If Phase_b <> Phase_a Then 'test phase B
Decr Axis_raw 'CCW
Else
Incr Axis_raw 'CW
End If
Return
'-------------------------------------------------------------------------------
|