Hi!
I'm working on a project were I need a quadrature decoder to calculate pulses
from an encoder. This should be implemented in a 16C77. I have some idea on20how to implement this but I'm not really intrested to invent the wheel again.20Has
anybody done something like this.
When pin A goes up, pin B state the direction;
If pin B is up, direction is forward, otherwise is backward,
or reversed, but easy as it is.
Wagner.
< Patric Anvegard wrote:
>
> Hi!
> I'm working on a project were I need a quadrature decoder to calculate pulses
> from an encoder. This should be implemented in a 16C77. I have some idea on how to implement this but I'm not really intrested to invent the wheel again. Has
> anybody done something like this.
>
> Patric AnvegŒrd
Wagner Lipnharski wrote:
>
> When pin A goes up, pin B state the direction;
> If pin B is up, direction is forward, otherwise is backward,
> or reversed, but easy as it is.
>
> Wagner.
>
but don' try doing it this way in a industrial enviroment, because of
noise you will get a more random count.
( I had the problem once ) I suggest a state-machine wich
tracks the states of both chanels to filter valid changes of
both channels.
A B
0 0
0 1
1 1
1 0
0 0 -> on count valid in one direction
or:
0 0
1 0
1 1
0 1
0 0 -> on count vaild to the other direction
Hi!
I'm working on a project were I need a quadrature decoder to calculate
pulses
from an encoder. This should be implemented in a 16C77. I have some idea on
how to implement this but I'm not really intrested to invent the wheel
again. Has
anybody done something like this.
Patric AnvegŒrd
----------
The most secure implementation that I have seen is to asynchronously read
the inputs
and use the old (previous) and new readings to determine position value.
The
read rate must be just slightly faster that the maximum change rate on the
inputs.
Reading more often improves the noise immunity.
a new b new A old B old
0 0 0 0 do nothing
0 0 0 1 increment
0 0 1 0 decrement
0 0 1 1 error condition (noise)
0 1 0 0 decrement
0 1 0 1 do nothing
0 1 1 0 error condition (noise )
0 1 1 1 decrement
1 0 0 0 decrement
1 0 0 1 error condition (noise )
1 0 1 0 do nothing
1 0 1 1 increment
1 1 0 0 error condition (noise)
1 1 0 1 decrement
1 1 1 0 increment
1 1 1 1 do nothing
The over sampling makes this relatively noise immune and
old Vs new readings can be implemented in software with
a table or an exclusive or. One of the PC mice I did used table lookup and
processed both axis at once.
Some numbers that are useful for mice design is the fastest measure
hand movement we measured was 43 inches per second
I'm working on a project were I need a quadrature decoder to calculate
pulses
from an encoder.
Patric AnvegŒrd
----------
The most secure implementation that I have seen is to asynchronously
read the inputs and use the old (previous) and new readings to determine
position value.The read rate must be just slightly faster that the maximum
change rate on the inputs.
Reading more often improves the noise immunity.
a new b new A old B old
0 0 0 0 do nothing
0 0 0 1 increment
0 0 1 0 decrement
0 0 1 1 error condition (noise)
0 1 0 0 decrement
0 1 0 1 do nothing
0 1 1 0 error condition (noise )
0 1 1 1 decrement
1 0 0 0 decrement
1 0 0 1 error condition (noise )
1 0 1 0 do nothing
1 0 1 1 increment
1 1 0 0 error condition (noise)
1 1 0 1 decrement
1 1 1 0 increment
1 1 1 1 do nothing
The over sampling makes this relatively noise immune.
Further to the previous post. The following MPC code fragment
will do quadrature decoding. Just keep calling quad whenever your
application has nothing better to do or from the the timer interrupt or
both. It solves both the no motion and error cases.
Hi Stefan, yes, the noisy environment requires more care.
I have heard a lot about noise here and noise there, looks like there is
noise everywhere. hehe :), I understand that, now tell me, a four wire
shielded cable, grounded at the processor side, with the minimum
possible impedance forced on both sides, with some decoupling small
caps, can eliminate a big amount of emi and noises. In some environments
it is necessary some filtering at the AC incoming to the power supply. I
already done that in several situations and *never* got severe noisy
problems, even in metallurgic environments for several different kind of
sensors, with cables longer than 20 ft. The only impossible environment
is the metallurgic electric metal melting chamber... man, if you heard
about EMI that is where it was born... mainly when the electrodes are
pouring thousands of amps over the scrap melting metal and they inject
pure oxygen in the middle of it... do you know that they avoid to use
electronic wrist watches around there? hehe.
Why don't you tell us in which situation, and how the sensor was
connected, cable, filtering, when you got those noise problems?
A lot of people can learn about it if we share our experiences, right?
>
> Hi Wagner,
>
> Wagner Lipnharski wrote:
> >
> > When pin A goes up, pin B state the direction;
> > If pin B is up, direction is forward, otherwise is backward,
> > or reversed, but easy as it is.
> >
> > Wagner.
> >
>
> but don' try doing it this way in a industrial enviroment, because of
> noise you will get a more random count.
>
> ( I had the problem once ) I suggest a state-machine wich
> tracks the states of both chanels to filter valid changes of
> both channels.
>
> A B
> 0 0
> 0 1
> 1 1
> 1 0
> 0 0 -> on count valid in one direction
>
> or:
>
> 0 0
> 1 0
> 1 1
> 0 1
> 0 0 -> on count vaild to the other direction
>
> kind regards,
>
> Stefan Sczekalla-Waldschmidt
> sswspam_OUToikossw.de
HP makes an IC that will do it for you, maybe motorola also. You can do it
yourself with 2 flip flops if your processor has an input counter, I've also
done it with an 4 bit up down counter. The counter starts at 8 and counts up
to 15 or down to 0, at either extreme it stops counting. The counter is reset
whenever its polled by the processor.
>
> ----------
> The most secure implementation that I have seen is to asynchronously
> read the inputs and use the old (previous) and new readings to determine
> position value.The read rate must be just slightly faster that the maximum
> change rate on the inputs.
>
> Reading more often improves the noise immunity.
>
> a new b new A old B old
> 0 0 0 0 do nothing
> 0 0 0 1 increment
> 0 0 1 0 decrement
> 0 0 1 1 error condition (noise)
> 0 1 0 0 decrement
> 0 1 0 1 do nothing
> 0 1 1 0 error condition (noise )
> 0 1 1 1 decrement
> 1 0 0 0 decrement
> 1 0 0 1 error condition (noise )
> 1 0 1 0 do nothing
> 1 0 1 1 increment
> 1 1 0 0 error condition (noise)
> 1 1 0 1 decrement
> 1 1 1 0 increment
> 1 1 1 1 do nothing
>
> The over sampling makes this relatively noise immune.
>
Are you sure about the Table ???
There are five times decrement and only three times increment to see.
But the general idea is very similar the way I did exception -
by loosing some of the resolution I did the state-machine in
this way, that only after running through the whole sequence
00:01:11:10:00 OR 00:10:11:01:00 a up or down count was done.
I've posted this little routine several times before in the list, and got no
comments. I've used it to read a hand-operated encoder (volume in a piped
music application) with no problem. Yes, this is not a very noisy
environment...
Here it goes:
Assume the actual state of the encoder is in 'encod' bits 0 and 1.
; Encoder read
clrf auxint
movf auxint,W ; encod <- (actual state) xor (previous one)
xorwf encod,F ; (only bits 0 and 1 affected)
;
rrf auxint,F ; XOR results, reordered, get
rlf encod,F ; into encod, in bits 0 and 1.
rrf auxint,F ; This bits are the motion indicators
rlf encod,F
;
btfsc encod,2 ; 'X' motion...
incf posenc,F
btfsc encod,3 ; ...or 'Y'
decf posenc,F
That's all. You have the "position" of the encoder in posenc. I need only 8
bits, but this is your choice. It is very easy to get 16 or more bits.
If you want some kind of soft filtering, previous "motion detection" of the
encoder are in 'encod', bits 4-5 and 6-7, in the same 2-3 fashion (you have
the last 3 readings). This bits mean:
3 2
--- ---
0 0 -> No motion
0 1 -> X motion
1 0 -> Y motion
1 1 -> Error
The last state indicates there is an error. It may be some kind of noise, or
it can be too lazy readings of the encoder... you have to read it more
often.
This routine uses 'encod', 'posenc' and 'aux', and lasts 11
instuction-cycles EVERY TIME. I placed it in a timer-interrupted routine,
where other tasks are taken.
Thats all. Hope my english is not too bad, and hope this helps.
>When pin A goes up, pin B state the direction;
>If pin B is up, direction is forward, otherwise is backward,
>or reversed, but easy as it is.
>
>Wagner.
>
>< Patric Anvegard wrote:
>>
>> Hi!
>> I'm working on a project were I need a quadrature decoder to calculate
pulses
>> from an encoder. This should be implemented in a 16C77. I have some idea
on how to implement this but I'm not really intrested to invent the wheel
again. Has
>> anybody done something like this.
>>
>> Patric AnvegŒrd
>
The one and only problem you have to account for is that the resting
position of the decoder is VERY close the the leading edge of one of the
pulses.. ie if you bump the decoder slightly or it begins to wear, it would
be all too possible to generate direction-indication pulses in one direction
without even touching the knob..
Believe me, I know :) I did a durability test with one by chucking it into a
reversible drill! After all was said and done, it was sloppy and generating
errors.. So, anyway, to get around this, I had the processor read one input,
then look at the other for direction, THEN wait for them BOTH to be high
before generating an output pulse, because only with that sequence of events
can you be sure the person actually wanted the pulse output. If it gets
direction data and it takes more than .5 sec for A*B=1, it times out and
ignores the direction data as an error...
This is the only sure way of doing it.
Thanks for the good advises to solve my problem with the quadrature decoding.
I'll try some of the routines I got from Walter Banks and Alvaro and see how they work...
The solution that I had some thoughts about before I sent this message to the
list
was that this problem could be solved by having one of the channels(A) connected
to the Capture input and the other one to an "ordinary" input.
The Capture module is initialized to interrupt on rising edge. When I get an0interrupt I
put the processor in "state 1" if the B-channel is 1 or in "state 0" if the B-channel is 0
and when changes the CCP module to interrupt on falling edge.
When I get the next interrupt I read the B channel and detects the direction.20If the
previous state was 0 I should now get a 1 on the B-channel or if the previous state was 0 I should now get a 0. If I get two 0 states (or two 1 states) I ignore0it (this could
accure if I get noise on the A channel or if the direction has changed on the encoder.
Does anyone have an argument why this should'nt work or should I put some effort to try this solution too.
Thanks for the good advises to solve my problem with the quadrature decoding.
I'll try some of the routines I got from Walter Banks and Alvaro and see how they work...
The solution that I had some thoughts about before I sent this message to the
list
was that this problem could be solved by having one of the channels(A) connected
to the Capture input and the other one to an "ordinary" input.
The Capture module is initialized to interrupt on rising edge. When I get an0interrupt I
put the processor in "state 1" if the B-channel is 1 or in "state 0" if the B-channel is 0
and when changes the CCP module to interrupt on falling edge.
When I get the next interrupt I read the B channel and detects the direction.20If the
previous state was 0 I should now get a 1 on the B-channel or if the previous state was 0 I should now get a 0. If I get two 0 states (or two 1 states) I ignore0it (this could
accure if I get noise on the A channel or if the direction has changed on the encoder.
Does anyone have an argument why this should'nt work or should I put some effort to try this solution too.
Thanks for the good advises to solve my problem with the quadrature decoding.
I'll try some of the routines I got from Walter Banks and Alvaro and see how they work...
The solution that I had some thoughts about before I sent this message to the
list
was that this problem could be solved by having one of the channels(A) connected
to the Capture input and the other one to an "ordinary" input.
The Capture module is initialized to interrupt on rising edge. When I get an0interrupt I
put the processor in "state 1" if the B-channel is 1 or in "state 0" if the B-channel is 0
and when changes the CCP module to interrupt on falling edge.
When I get the next interrupt I read the B channel and detects the direction.20If the
previous state was 0 I should now get a 1 on the B-channel or if the previous state was 0 I should now get a 0. If I get two 0 states (or two 1 states) I ignore0it (this could
accure if I get noise on the A channel or if the direction has changed on the encoder.
Does anyone have an argument why this should'nt work or should I put some effort to try this solution too.
Thanks for the good advises to solve my problem with the quadrature decoding.
I'll try some of the routines I got from Walter Banks and Alvaro and see how they work...
The solution that I had some thoughts about before I sent this message to the
list
was that this problem could be solved by having one of the channels(A) connected
to the Capture input and the other one to an "ordinary" input.
The Capture module is initialized to interrupt on rising edge. When I get an0interrupt I
put the processor in "state 1" if the B-channel is 1 or in "state 0" if the B-channel is 0
and when changes the CCP module to interrupt on falling edge.
When I get the next interrupt I read the B channel and detects the direction.20If the
previous state was 0 I should now get a 1 on the B-channel or if the previous state was 0 I should now get a 0. If I get two 0 states (or two 1 states) I ignore0it (this could
accure if I get noise on the A channel or if the direction has changed on the encoder.
Does anyone have an argument why this should'nt work or should I put some effort to try this solution too.
Thanks for the good advises to solve my problem with the quadrature decoding.
I'll try some of the routines I got from Walter Banks and Alvaro and see how they work...
The solution that I had some thoughts about before I sent this message to the
list
was that this problem could be solved by having one of the channels(A) connected
to the Capture input and the other one to an "ordinary" input.
The Capture module is initialized to interrupt on rising edge. When I get an0interrupt I
put the processor in "state 1" if the B-channel is 1 or in "state 0" if the B-channel is 0
and when changes the CCP module to interrupt on falling edge.
When I get the next interrupt I read the B channel and detects the direction.20If the
previous state was 0 I should now get a 1 on the B-channel or if the previous state was 0 I should now get a 0. If I get two 0 states (or two 1 states) I ignore0it (this could
accure if I get noise on the A channel or if the direction has changed on the encoder.
Does anyone have an argument why this should'nt work or should I put some effort to try this solution too.
Thanks for the good advises to solve my problem with the quadrature decoding.
I'll try some of the routines I got from Walter Banks and Alvaro and see how they work...
The solution that I had some thoughts about before I sent this message to the
list
was that this problem could be solved by having one of the channels(A) connected
to the Capture input and the other one to an "ordinary" input.
The Capture module is initialized to interrupt on rising edge. When I get an0interrupt I
put the processor in "state 1" if the B-channel is 1 or in "state 0" if the B-channel is 0
and when changes the CCP module to interrupt on falling edge.
When I get the next interrupt I read the B channel and detects the direction.20If the
previous state was 0 I should now get a 1 on the B-channel or if the previous state was 0 I should now get a 0. If I get two 0 states (or two 1 states) I ignore0it (this could
accure if I get noise on the A channel or if the direction has changed on the encoder.
Does anyone have an argument why this should'nt work or should I put some effort to try this solution too.
The decoder I used (Bournes) had a specified contact bounce time of 5 ms.
That was a good reason not to connect it a an interupt pin! Seriously I did
think about thihs method and was warned against it by someone else on the
list becuase of this. I guess if you are using a super optical encoder with
no bounce it would be ok.
A point I missed making in my earlier comments on
quadrature decoding is that electrical noise is generally not
a serious problem. The leads to the sensors are generally
short and generally quite low inpedence.
Mechanical noise is for the most part self correcting in
the code that I posted. Even the apparent jitter of the
edge of a transistion is completely self correcting with
the apparent short term error of one count and no
system accumulated error.
The decoder I used (Bournes) had a specified contact bounce time of 5 ms.
That was a good reason not to connect it a an interupt pin! Seriously I
did
think about thihs method and was warned against it by someone else on the
list becuase of this. I guess if you are using a super optical encoder
with
no bounce it would be ok.
|The one and only problem you have to account for is that the resting
|position of the decoder is VERY close the the leading edge of one of the
|pulses.. ie if you bump the decoder slightly or it begins to wear, it would
|be all too possible to generate direction-indication pulses in one direction
|without even touching the knob..
What about regarding the four states of the encoder as (in CW order),
1X, X0, 0X, and X1? Or, to put it another way...
State 0:
Wait for first input lo.
If second input lo, inc count and goto state 1. Else dec and state 3.
State 1:
Wait for second input hi.
If first input lo, inc count and goto state 2. Else dec and state 0.
State 2:
Wait for first input hi.
If second input hi, inc count and goto state 3. Else dec and state 1.
State 3:
Wait for second input lo.
If first input hi, inc count and goto state 0. Else dec and state 2.
Note that since this algorithm will always be waiting for an edge on the
input which *DIDN'T* change last, it won't have jitter problems the way
the more "normal" algorithm doesn. Further, if the chip being used has
suitably-programmable interrupts, the decoding can be interrupt-driven
without excessive numbers of interrupts.
I can't really see why this problem should accure.......
Or maybe I did'nt explain too well what I mean.
Lets call the two channels "Count" and "Direction"
The "Count" is always interrupted on change with the
capture-input. It the last interrupt was on falling edge
the next must be on rising edge. The "direction" is neverconnected to an interrupt. So if I'm very close to the "Direction"
leading edge I would not get any interrupt (ever). If I'm very close to the "Count" leading edge the following would appear:
1. I get an interrupt (on rising edge on "Counter").
2. I read the "Direction"-input and detects if it's high or low.
3. I get an interrupt (on falling edge on "Counter")
4. I read the "Direction"-input and detects that i has not changed
since 2 and then I don't count up or down.
To get a faulty count the resting position has to be very close
to both the "Direction" and the "Count" leading edge.....
|The one and only problem you have to account for is that the resting
|position of the decoder is VERY close the the leading edge of one of the
|pulses.. ie if you bump the decoder slightly or it begins to wear, it would
|be all too possible to generate direction-indication pulses in one direction
|without even touching the knob..
What about regarding the four states of the encoder as (in CW order),
1X, X0, 0X, and X1? Or, to put it another way...
State 0:
Wait for first input lo.
If second input lo, inc count and goto state 1. Else dec and state 3.
State 1:
Wait for second input hi.
If first input lo, inc count and goto state 2. Else dec and state 0.
State 2:
Wait for first input hi.
If second input hi, inc count and goto state 3. Else dec and state 1.
State 3:
Wait for second input lo.
If first input hi, inc count and goto state 0. Else dec and state 2.
Note that since this algorithm will always be waiting for an edge on the
input which *DIDN'T* change last, it won't have jitter problems the way
the more "normal" algorithm doesn. Further, if the chip being used has
suitably-programmable interrupts, the decoding can be interrupt-driven
without excessive numbers of interrupts.
Yes, you're quite right. You have clarified that you are looking at
*both* edges of the "clock" (interrupt) phase. The problem comes when
this is not understood and someone attempts to simplify it by using only
*one* edge.
The whole system (*any* quadrature encoder) depends on the ability of
the firmware to respond to a transition on one phase (and that includes
bounces) before any transition occurs on the other.
Also, any encoder in which the bounce of one phase can ever extend to
the subsequent transition on the other would be essentially useless in
consequence.
"Mechanical" encoders (contacts) are thus limited to non-critical uses
such as manual adjustment knobs. All my mice with PCB encoder discs are
now in the "curiousity" box (I can't bring myself to throw anything
out...).
The chief limitation of "count" and "direction" encoding is that it
halves the resolution, i.e., you can only respond to transitions on the
"count" phase. Better is to XOR the two inputs and feed that to the
IRQ input (which still must detect both transitions).
I like John Payson's suggestion which is a two-phase debounce.
--
Cheers,
Paul B.
Use synchronous detection software to eliminate noise sensitivity. I've
done this to eliminate motor noise pickup from a homemade shaft encoder. It
completely solved the problem. Mine was an incremental encoder (did not
sense direction) but two photodetectors and synchrounous detectors will be
required for quadrature detection. I can't give you my code, since it
belongs to my employer, but I'll tell you a little about how a synchronous
detector works.
Preset two registers to the middle of their range (128, probably). Write
your software to pulse the photodetector LEDs at different times, reading
the detectors such that you increment the appropriate counter when the
emitter associated with that counter is on, and decrement the counter when
the associated emitter is off. Any noise or non-synchronous signals will be
virtually cancelled out. Set your trigger threshold to half the total
number of counts for each photodetector for max noise immunity. You don't
need a lot of counts for excellent noise immunity. Experiment. More counts
slows you down. Don't set your count number so high that it is possible to
overflow or underflow the registers. You don't necessarily need a square
wave at the emitters as long as you take the same number of samples while
the LED is on as when it's off. Then, use the quadrature detection ideas of
other respondants to realize a noise free quadrature decoder.
I hopes this helps. It worked beautifully for me.
At 12:10 PM 4/20/99 +0000, you wrote:
>Hi everybody!
>
>Thanks for the good advises to solve my problem with the quadrature decoding.
>I'll try some of the routines I got from Walter Banks and Alvaro and see
how they work...
>
>The solution that I had some thoughts about before I sent this message to
the list
>was that this problem could be solved by having one of the channels(A)
connected
>to the Capture input and the other one to an "ordinary" input.
>The Capture module is initialized to interrupt on rising edge. When I get
an interrupt I
>put the processor in "state 1" if the B-channel is 1 or in "state 0" if
the B-channel is 0
>and when changes the CCP module to interrupt on falling edge.
>When I get the next interrupt I read the B channel and detects the
direction. If the
> previous state was 0 I should now get a 1 on the B-channel or if the
previous state was 0 I should now get a 0. If I get two 0 states (or two 1
states) I ignore it (this could
> accure if I get noise on the A channel or if the direction has changed on
the encoder.
>
>Does anyone have an argument why this should'nt work or should I put some
effort to try this solution too.
>
>Patric AnvegŒrd
>
>