The purpose of this group is to foster exchange of information on the Texas Instruments MSP430 family of microcontrollers and related tools. Everyone welcome, all levels of familiarity/expertise.
Quadrature Encoder - Thiago Alberto - Aug 4 19:23:42 2009
Hi
I need to use a quadrature encoder (1000 ppr rotating at 400 rpm). I was
looking for codes and i didn't find anything.
Has anyone any ideas how i can use timers to monitoring channels A and B,
decide if it is CW or cCW and increment or decrement a position variable?
I thought about using the channels as the clock timer source but it will not
work 'cause i'd not know if it is turning CW or cCW. I thought using P1
interrupts.... And other things
Well I'm using a MSP430F1611 based system.
Any help would be welcome.
Thanks
Thiago Alberto
[Non-text portions of this message have been removed]
------------------------------------
______________________________
controlSUITE software. Comprehensive. Intuitive. Optimized.
Real-world software for real-time control. Details Here!

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )
Re: Quadrature Encoder - old_cow_yellow - Aug 4 19:48:55 2009
You could use two Capture Channels of one of the two Timers. Alternatively, you could use
two of the Port 1 or 2 pins as edge detectors.
Port 1 or 2 pins have to be set up to detect either rising or falling edge. Using Capture
Channels is a little easier because they can be set up to detect both edges at the same
time.
A quad B encoding is designed to show the direction. Detecting CW or CCW should be
easy.
--- In m...@yahoogroups.com, Thiago Alberto
wrote:
>
> Hi
> I need to use a quadrature encoder (1000 ppr rotating at 400 rpm). I was
> looking for codes and i didn't find anything.
>
> Has anyone any ideas how i can use timers to monitoring channels A and B,
> decide if it is CW or cCW and increment or decrement a position variable?
>
> I thought about using the channels as the clock timer source but it will not
> work 'cause i'd not know if it is turning CW or cCW. I thought using P1
> interrupts.... And other things
>
> Well I'm using a MSP430F1611 based system.
>
> Any help would be welcome.
>
> Thanks
>
> Thiago Alberto
> [Non-text portions of this message have been removed]
>
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Quadrature Encoder - Howard Hansen - Aug 4 20:19:48 2009
Label your two signals A and B. First look for a rising edge on A and
concurrently monitor the level of the B signal. If B is low when a
rising edge occurs on A the shaft is rotating in one direction. If B is
high when a rising edge occurs on A the shaft is rotating in the
opposite direction. Hence use A's rising edge as an input to an up
down counter and B's level to determine whether to increment or
decrement your counter.
This approach is based on the material on page 330 of "Digital Design by
Peter J. Ashenden.
Howard
Thiago Alberto wrote:
>
>
> Hi
> I need to use a quadrature encoder (1000 ppr rotating at 400 rpm). I was
> looking for codes and i didn't find anything.
>
> Has anyone any ideas how i can use timers to monitoring channels A and B,
> decide if it is CW or cCW and increment or decrement a position variable?
>
> I thought about using the channels as the clock timer source but it
> will not
> work 'cause i'd not know if it is turning CW or cCW. I thought using P1
> interrupts.... And other things
>
> Well I'm using a MSP430F1611 based system.
>
> Any help would be welcome.
>
> Thanks
>
> Thiago Alberto
>
> [Non-text portions of this message have been removed]
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )
Re: Quadrature Encoder - Stuart_Rubin - Aug 5 8:32:13 2009
I did just this kind of code a while back on a Freescale chip. The theory should be the
same.
See
http://en.wikipedia.org/wiki/Rotary_encoder and look for the section "Incremental rotary
encoder". The charts are helpful.
I would probably not fool with the timers for this. This is basically how I did it.
1. Setup an signed accumulator variable to count how many net "clicks" occurred. (Assume
a positive value means more clockwise clicks. Negative means more counter-clockwise.)
2. Enable interrupts on your A and B channels. Start them with arbitrary edge sensitivity
(e.g. both set to "rising edge").
3. When the interrupt occurs, invert the edge sensitivity on the line which caused the
interrupt. (i.e. if "A" had a rising edge interrupt, flip the sensitivity to "falling
edge".) Use the gray-code charts shown on the Wiki site to either add or subtract on
"click" from the accumulator.
4. Periodically (i.e. in your main loop, at time timer interval, etc.) read the
accumulator value to see how many clicks (magnitude) you've gone and in which direction
(sign). Then reset the accumulator back to 0.
What was cool was how I tested it. I "centered" the knob (which was connected to the
encoder) to the 12 o'clock position then reset the program. Then, I turned the knob as
fast as I could and read back the value (as a sanity check). Then, I very slowly turned
the knob back click-by-click to the 12 o'clock position. If the value was 0, then all the
clicks in both directions were read. (You might want to try this slowly, then speed up!
The worst that can happen is that you miss a click, and need another click to get back
into sync, but you'll never be off by more than one count!)
Let us know how it works out.
Stuart
--- In m...@yahoogroups.com, Thiago Alberto
wrote:
>
> Hi
> I need to use a quadrature encoder (1000 ppr rotating at 400 rpm). I was
> looking for codes and i didn't find anything.
>
> Has anyone any ideas how i can use timers to monitoring channels A and B,
> decide if it is CW or cCW and increment or decrement a position variable?
>
> I thought about using the channels as the clock timer source but it will not
> work 'cause i'd not know if it is turning CW or cCW. I thought using P1
> interrupts.... And other things
>
> Well I'm using a MSP430F1611 based system.
>
> Any help would be welcome.
>
> Thanks
>
> Thiago Alberto
> [Non-text portions of this message have been removed]
>
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Re: Quadrature Encoder - Thiago Alberto - Aug 5 9:30:13 2009
Thank you guys
I think i will monitoring just one channel (i.e. channel A on the rising
edge)... then when a P1 pin interrupt occurs i will see the other channel
(channel B is conected like a input pin) if B is high i'm moving CW then
cont ++ otherwise if B is low i'm moving cCW then cont--
With this code i will read 1000 ppr. I could read 2000 ppr if I monitor both
edges (rising and falling) but 1000 is good enough for me.
Maybe, after that if i could do my control i will try the 2000 ppr approach.
Thaks for all the help.
Thiago Alberto
[Non-text portions of this message have been removed]
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )
Re: Re: Quadrature Encoder - micr...@virginbroadband.com.au - Aug 5 9:47:29 2009
Indeed-a-li-doo !
Another nice thing about quadrature is its reasonable robustness. If
implemented properly, jitter doesn't cause errors.
A glitch forward, followed by a "backwards" pulse, will result in a nett
count of zero.
Not surprising on one hand, since it implements the principles of Gray
codes, like Stuart pointed out.
B rgds
Kris
On Wed, 05 Aug 2009 12:30:40 -0000, "Stuart_Rubin"
wrote:
> I did just this kind of code a while back on a Freescale chip. The
theory
> should be the same.
>
> See
> http://en.wikipedia.org/wiki/Rotary_encoder and look for the section
> "Incremental rotary encoder". The charts are helpful.
>
> I would probably not fool with the timers for this. This is basically
how
> I did it.
>
> 1. Setup an signed accumulator variable to count how many net "clicks"
> occurred. (Assume a positive value means more clockwise clicks.
Negative
> means more counter-clockwise.)
>
> 2. Enable interrupts on your A and B channels. Start them with arbitrary
> edge sensitivity (e.g. both set to "rising edge").
>
> 3. When the interrupt occurs, invert the edge sensitivity on the line
which
> caused the interrupt. (i.e. if "A" had a rising edge interrupt, flip the
> sensitivity to "falling edge".) Use the gray-code charts shown on the
> Wiki site to either add or subtract on "click" from the accumulator.
>
> 4. Periodically (i.e. in your main loop, at time timer interval, etc.)
> read the accumulator value to see how many clicks (magnitude) you've gone
> and in which direction (sign). Then reset the accumulator back to 0.
>
> What was cool was how I tested it. I "centered" the knob (which was
> connected to the encoder) to the 12 o'clock position then reset the
> program. Then, I turned the knob as fast as I could and read back the
> value (as a sanity check). Then, I very slowly turned the knob back
> click-by-click to the 12 o'clock position. If the value was 0, then all
> the clicks in both directions were read. (You might want to try this
> slowly, then speed up! The worst that can happen is that you miss a
> click, and need another click to get back into sync, but you'll never be
> off by more than one count!)
>
> Let us know how it works out.
>
> Stuart
>
> --- In m...@yahoogroups.com, Thiago Alberto wrote:
>>
>> Hi
>> I need to use a quadrature encoder (1000 ppr rotating at 400 rpm). I was
>> looking for codes and i didn't find anything.
>>
>> Has anyone any ideas how i can use timers to monitoring channels A and
B,
>> decide if it is CW or cCW and increment or decrement a position
variable?
>>
>> I thought about using the channels as the clock timer source but it will
>> not
>> work 'cause i'd not know if it is turning CW or cCW. I thought using P1
>> interrupts.... And other things
>>
>> Well I'm using a MSP430F1611 based system.
>>
>> Any help would be welcome.
>>
>> Thanks
>>
>> Thiago Alberto
>> [Non-text portions of this message have been removed]
>>
> ------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Quadrature Encoder - aschuh - Aug 5 10:04:25 2009
Another possibility if you have enough IOs free:
Use two IO Pins for each Channel, initialize one for rising an the other one for falling
edges.
This has the advantage that very fast switching on one channel (through vibrations etc...)
won't corrupt your position information. Because if you use one IO you have to reconfigure
your interrupt edges at some point in code, when an edge just occurs at this time this
interrupt might get lost! Of course this can be avoided by rechecking the IO state after
switching the interrupt edge.
As mentioned before the combination of rising/falling edges interrupts and the state of
the second channel will give you the direction information. Count up/down your position
variable accordingly.
--- In m...@yahoogroups.com,
wrote:
>
> Indeed-a-li-doo !
>
> Another nice thing about quadrature is its reasonable robustness. If
> implemented properly, jitter doesn't cause errors.
> A glitch forward, followed by a "backwards" pulse, will result in a nett
> count of zero.
> Not surprising on one hand, since it implements the principles of Gray
> codes, like Stuart pointed out.
>
> B rgds
> Kris
> On Wed, 05 Aug 2009 12:30:40 -0000, "Stuart_Rubin"
> wrote:
> > I did just this kind of code a while back on a Freescale chip. The
> theory
> > should be the same.
> >
> > See
> > http://en.wikipedia.org/wiki/Rotary_encoder and look for the section
> > "Incremental rotary encoder". The charts are helpful.
> >
> > I would probably not fool with the timers for this. This is basically
> how
> > I did it.
> >
> > 1. Setup an signed accumulator variable to count how many net "clicks"
> > occurred. (Assume a positive value means more clockwise clicks.
> Negative
> > means more counter-clockwise.)
> >
> > 2. Enable interrupts on your A and B channels. Start them with arbitrary
> > edge sensitivity (e.g. both set to "rising edge").
> >
> > 3. When the interrupt occurs, invert the edge sensitivity on the line
> which
> > caused the interrupt. (i.e. if "A" had a rising edge interrupt, flip the
> > sensitivity to "falling edge".) Use the gray-code charts shown on the
> > Wiki site to either add or subtract on "click" from the accumulator.
> >
> > 4. Periodically (i.e. in your main loop, at time timer interval, etc.)
> > read the accumulator value to see how many clicks (magnitude) you've gone
> > and in which direction (sign). Then reset the accumulator back to 0.
> >
> > What was cool was how I tested it. I "centered" the knob (which was
> > connected to the encoder) to the 12 o'clock position then reset the
> > program. Then, I turned the knob as fast as I could and read back the
> > value (as a sanity check). Then, I very slowly turned the knob back
> > click-by-click to the 12 o'clock position. If the value was 0, then all
> > the clicks in both directions were read. (You might want to try this
> > slowly, then speed up! The worst that can happen is that you miss a
> > click, and need another click to get back into sync, but you'll never be
> > off by more than one count!)
> >
> > Let us know how it works out.
> >
> > Stuart
> >
> > --- In m...@yahoogroups.com, Thiago Alberto wrote:
> >>
> >> Hi
> >> I need to use a quadrature encoder (1000 ppr rotating at 400 rpm). I was
> >> looking for codes and i didn't find anything.
> >>
> >> Has anyone any ideas how i can use timers to monitoring channels A and
> B,
> >> decide if it is CW or cCW and increment or decrement a position
> variable?
> >>
> >> I thought about using the channels as the clock timer source but it will
> >> not
> >> work 'cause i'd not know if it is turning CW or cCW. I thought using P1
> >> interrupts.... And other things
> >>
> >> Well I'm using a MSP430F1611 based system.
> >>
> >> Any help would be welcome.
> >>
> >> Thanks
> >>
> >> Thiago Alberto
> >>
> >>
> >> [Non-text portions of this message have been removed]
> >>
> >
> >
> >
> >
> > ------------------------------------
> >
> >
> >
> >

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Quadrature Encoder - Dan Bloomquist - Aug 5 11:28:04 2009
Thiago Alberto wrote:
> Hi
> I need to use a quadrature encoder (1000 ppr rotating at 400 rpm). I was
> looking for codes and i didn't find anything.
>
I did this some years ago, it worked fine then with a noisy encoder.
test_buf counts up/down on the input.
Best, Dan.
~~~
#define QUAD_VECTOR PORT1_VECTOR
#define QUAD_A BIT1
#define QUAD_B BIT2
#define QUAD_PORT P1IN
#define QUAD_IE P1IE
#define QUAD_IES P1IES
#define QUAD_IFG P1IFG
static unsigned int test_buf;
static int bit_test;
main(...)
#ifdef QUAD_ON
QUAD_IE|= QUAD_A | QUAD_B;
if( QUAD_PORT & QUAD_A )
sys_flags|= SYSF_QUAD_A;
if( QUAD_PORT & QUAD_B )
sys_flags|= SYSF_QUAD_B;
#endif
#pragma vector=QUAD_VECTOR
__interrupt void _quad_change( void )
{
if( QUAD_IE & QUAD_A )
{
if( QUAD_PORT & QUAD_B )
{
bit_test= 1;
QUAD_IES|= QUAD_B;
}
else
{
bit_test= -1;
QUAD_IES&= ~QUAD_B;
}
if( QUAD_IES & QUAD_A )
test_buf+= bit_test;
else
test_buf-= bit_test;
QUAD_IE&= ~QUAD_A;
QUAD_IE|= QUAD_B;
}
else //if( QUAD_IE & QUAD_B )
{
if( QUAD_PORT & QUAD_A )
{
bit_test= -1;
QUAD_IES|= QUAD_A;
}
else
{
bit_test= 1;
QUAD_IES&= ~QUAD_A;
}
if( QUAD_IES & QUAD_B )
test_buf+= bit_test;
else
test_buf-= bit_test;
QUAD_IE&= ~QUAD_B;
QUAD_IE|= QUAD_A;
}
QUAD_IFG&= ~( QUAD_A | QUAD_B );
}
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )
Re: Quadrature Encoder - tintronic - Aug 5 13:28:25 2009
I made a code for a rotary switch many years ago. I connected A and B to 2 P1 inputs each,
to generate an interrupt on each edge of each signal. The ISR consisted of a state machine
with 4 states: 00, 01, 11 and 10 corresponding to the state of the AB inputs. Depending on
the previous state and the current state, the pulses variable was incremented or
decremented. To make sure no pulses were missed, invalid transitions between 00 <-> 11 and
01 <-> 10 were reported as errors (you can't know the direction of rotation in case you
missed a transition, however, you could assume it is maintaining the direction of the
previous transition). No matter how fast I could turn the encoder with my hand (which was
far faster than it would ever rotate once installed), it never detected those invalid
transitions and always kept the correct position, proving the code was robust.
This has also the benefit (or drawback) that the resolution of your enconder is
cuadruplied (1000ppr = 2000 edges per rotation on each signal, 4000 total epr).
In your case, this would mean:
4epp x 1000ppr x 400rpm
-------------------- = 26,666.67 edges per second (int. freq.)
60 seconds/minute
Using a 8MHz crystal, you'd have about 300 cycles between interrupts to execute the ISR
and have time left for your other interrupts and/or main loop.
No matter how you implement the counting, you need to take care of how you read the
variable that stores the pulses. Make sure any read, write and read->modify->write
operation on it is atomic, that is, that the operation can not be interrupted.
Regards,
Michael K.
------------------------------------
______________________________
controlSUITE software. Comprehensive. Intuitive. Optimized.
Real-world software for real-time control. Details Here!

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Quadrature Encoder - old_cow_yellow - Aug 5 16:15:18 2009
--- In m...@yahoogroups.com, "tintronic"
wrote:
>
> I made a code for a rotary switch many years ago. I connected A and B to 2 P1 inputs
each, to generate an interrupt on each edge of each signal. The ISR consisted of a state
machine with 4 states: 00, 01, 11 and 10 corresponding to the state of the AB inputs.
Depending on the previous state and the current state, the pulses variable was incremented
or decremented. To make sure no pulses were missed, invalid transitions between 00 <-> 11
and 01 <-> 10 were reported as errors (you can't know the direction of rotation in case
you missed a transition, however, you could assume it is maintaining the direction of the
previous transition). No matter how fast I could turn the encoder with my hand (which was
far faster than it would ever rotate once installed), it never detected those invalid
transitions and always kept the correct position, proving the code was robust.
> This has also the benefit (or drawback) that the resolution of your enconder is
cuadruplied (1000ppr = 2000 edges per rotation on each signal, 4000 total epr).
>
> In your case, this would mean:
>
> 4epp x 1000ppr x 400rpm
> -------------------- = 26,666.67 edges per second (int. freq.)
> 60 seconds/minute
>
> Using a 8MHz crystal, you'd have about 300 cycles between interrupts to execute the ISR
and have time left for your other interrupts and/or main loop.
>
> No matter how you implement the counting, you need to take care of how you read the
variable that stores the pulses. Make sure any read, write and read->modify->write
operation on it is atomic, that is, that the operation can not be interrupted.
>
> Regards,
> Michael K.
>
Let me see if I can repeat what Michael said:
// Signals A & B form a 2-bit Gray code with 4 states
enum
{
Q0, // 00, A low & B low
Q1, // 01, A low & B high
Q2, // 11, A high & B high
Q3, // 10, A high & B low
} state;
// Changes of A & B are named as 4 kinds of events
enum
{
AL2H, // A low to high
AH2L, // A high to low
BL2H, // B low to high
BH2L, // B high to low
} event;
// We want to implement a binary counter
signed long int count;
// The state and counter are driven by events as follows
switch (event)
{
case AL2H: // A low to high
{
switch (state)
{
case Q0: //00
{state = Q3; count--; break;}
case Q1: //01
{state = Q2; count++; break;}
default: { errow(); }
}
break;
}
case AH2L: // A high to low
{
switch (state)
{
case Q2: //11
{state = Q1; count--; break;}
case Q3: //10
{state = Q0; count++; break;}
default: { errow(); }
}
break;
}
case BL2H: // B low to high
{
switch (state)
{
case Q0: //00
{state = Q1; count++; break;}
case Q3: //10
{state = Q2; count--; break;}
default: { errow(); }
}
break;
}
case BH2L: // B high to low
{
switch (state)
{
case Q1: //01
{state = Q0; count--; break;}
case Q2: //11
{state = Q3; count++; break;}
default: { errow(); }
}
break;
}
}
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Quadrature Encoder - David - Aug 5 17:03:57 2009
--- In m...@yahoogroups.com, "old_cow_yellow"
wrote:
>
> --- In m...@yahoogroups.com, "tintronic" wrote:
> >
> > I made a code for a rotary switch many years ago. I connected A and B to 2 P1 inputs
each, to generate an interrupt on each edge of each signal. The ISR consisted of a state
machine with 4 states: 00, 01, 11 and 10 corresponding to the state of the AB inputs.
Depending on the previous state and the current state, the pulses variable was incremented
or decremented. To make sure no pulses were missed, invalid transitions between 00 <-> 11
and 01 <-> 10 were reported as errors (you can't know the direction of rotation in case
you missed a transition, however, you could assume it is maintaining the direction of the
previous transition). No matter how fast I could turn the encoder with my hand (which was
far faster than it would ever rotate once installed), it never detected those invalid
transitions and always kept the correct position, proving the code was robust.
> > This has also the benefit (or drawback) that the resolution of your enconder is
cuadruplied (1000ppr = 2000 edges per rotation on each signal, 4000 total epr).
> >
> > In your case, this would mean:
> >
> > 4epp x 1000ppr x 400rpm
> > -------------------- = 26,666.67 edges per second (int. freq.)
> > 60 seconds/minute
> >
> > Using a 8MHz crystal, you'd have about 300 cycles between interrupts to execute the
ISR and have time left for your other interrupts and/or main loop.
> >
> > No matter how you implement the counting, you need to take care of how you read the
variable that stores the pulses. Make sure any read, write and read->modify->write
operation on it is atomic, that is, that the operation can not be interrupted.
> >
> > Regards,
> > Michael K.
> > Let me see if I can repeat what Michael said:
>
> // Signals A & B form a 2-bit Gray code with 4 states
> enum
> {
> Q0, // 00, A low & B low
> Q1, // 01, A low & B high
> Q2, // 11, A high & B high
> Q3, // 10, A high & B low
> } state;
>
> // Changes of A & B are named as 4 kinds of events
> enum
> {
> AL2H, // A low to high
> AH2L, // A high to low
> BL2H, // B low to high
> BH2L, // B high to low
> } event;
>
> // We want to implement a binary counter
> signed long int count;
>
> // The state and counter are driven by events as follows
> switch (event)
> {
>
> case AL2H: // A low to high
> {
> switch (state)
> {
> case Q0: //00
> {state = Q3; count--; break;}
> case Q1: //01
> {state = Q2; count++; break;}
> default: { errow(); }
> }
> break;
> }
>
> case AH2L: // A high to low
> {
> switch (state)
> {
> case Q2: //11
> {state = Q1; count--; break;}
> case Q3: //10
> {state = Q0; count++; break;}
> default: { errow(); }
> }
> break;
> }
>
> case BL2H: // B low to high
> {
> switch (state)
> {
> case Q0: //00
> {state = Q1; count++; break;}
> case Q3: //10
> {state = Q2; count--; break;}
> default: { errow(); }
> }
> break;
> }
>
> case BH2L: // B high to low
> {
> switch (state)
> {
> case Q1: //01
> {state = Q0; count--; break;}
> case Q2: //11
> {state = Q3; count++; break;}
> default: { errow(); }
> }
> break;
> }
>
> }
>
This link :-
http://www.mkesc.co.uk/ise.pdf
Points to an excellent method for dealing with Quadrature encoders.
The solution almost comes down to the following code snippet (from the paper)
I used two port pins to trigger a common ISR, and it worked a treat :) Unfortunately for
this group I was using an AVR at the time ;P
I have yet to see a better approach.
extern signed short angle; /* rotation since reset */
static unsigned char ab = 0; /* the old value of the sensor ports */
const signed short table[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
/* increment of angle for the 16 possible bit codes */
ab = ab << 2; /* move the old data left two places */
ab |= (port & 0x3); /* OR in the two new bits */
angle += table[(ab & 0xf)]; /* get the change from the 16 entry table */
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Quadrature Encoder - old_cow_yellow - Aug 5 17:24:28 2009
c is "portable". Is it not?
What I wrote in my previous e-mail is portable -- I think ;)
Actually, it is the same thing as the table look up implementation you quoted. Except that
some of the 0's in your table are my errow()'s while other 0's are true 0's.
BTW, my errow()'s are intended errors.
-- OCY
--- In m...@yahoogroups.com, "David"
wrote:
>
> --- In m...@yahoogroups.com, "old_cow_yellow" wrote:
> >
> > --- In m...@yahoogroups.com, "tintronic" wrote:
> > >
> > > I made a code for a rotary switch many years ago. I connected A and B to 2 P1 inputs
each, to generate an interrupt on each edge of each signal. The ISR consisted of a state
machine with 4 states: 00, 01, 11 and 10 corresponding to the state of the AB inputs.
Depending on the previous state and the current state, the pulses variable was incremented
or decremented. To make sure no pulses were missed, invalid transitions between 00 <-> 11
and 01 <-> 10 were reported as errors (you can't know the direction of rotation in case
you missed a transition, however, you could assume it is maintaining the direction of the
previous transition). No matter how fast I could turn the encoder with my hand (which was
far faster than it would ever rotate once installed), it never detected those invalid
transitions and always kept the correct position, proving the code was robust.
> > > This has also the benefit (or drawback) that the resolution of your enconder is
cuadruplied (1000ppr = 2000 edges per rotation on each signal, 4000 total epr).
> > >
> > > In your case, this would mean:
> > >
> > > 4epp x 1000ppr x 400rpm
> > > -------------------- = 26,666.67 edges per second (int. freq.)
> > > 60 seconds/minute
> > >
> > > Using a 8MHz crystal, you'd have about 300 cycles between interrupts to execute the
ISR and have time left for your other interrupts and/or main loop.
> > >
> > > No matter how you implement the counting, you need to take care of how you read the
variable that stores the pulses. Make sure any read, write and read->modify->write
operation on it is atomic, that is, that the operation can not be interrupted.
> > >
> > > Regards,
> > > Michael K.
> > >
> >
> > Let me see if I can repeat what Michael said:
> >
> > // Signals A & B form a 2-bit Gray code with 4 states
> > enum
> > {
> > Q0, // 00, A low & B low
> > Q1, // 01, A low & B high
> > Q2, // 11, A high & B high
> > Q3, // 10, A high & B low
> > } state;
> >
> > // Changes of A & B are named as 4 kinds of events
> > enum
> > {
> > AL2H, // A low to high
> > AH2L, // A high to low
> > BL2H, // B low to high
> > BH2L, // B high to low
> > } event;
> >
> > // We want to implement a binary counter
> > signed long int count;
> >
> > // The state and counter are driven by events as follows
> > switch (event)
> > {
> >
> > case AL2H: // A low to high
> > {
> > switch (state)
> > {
> > case Q0: //00
> > {state = Q3; count--; break;}
> > case Q1: //01
> > {state = Q2; count++; break;}
> > default: { errow(); }
> > }
> > break;
> > }
> >
> > case AH2L: // A high to low
> > {
> > switch (state)
> > {
> > case Q2: //11
> > {state = Q1; count--; break;}
> > case Q3: //10
> > {state = Q0; count++; break;}
> > default: { errow(); }
> > }
> > break;
> > }
> >
> > case BL2H: // B low to high
> > {
> > switch (state)
> > {
> > case Q0: //00
> > {state = Q1; count++; break;}
> > case Q3: //10
> > {state = Q2; count--; break;}
> > default: { errow(); }
> > }
> > break;
> > }
> >
> > case BH2L: // B high to low
> > {
> > switch (state)
> > {
> > case Q1: //01
> > {state = Q0; count--; break;}
> > case Q2: //11
> > {state = Q3; count++; break;}
> > default: { errow(); }
> > }
> > break;
> > }
> >
> > }
> >
> This link :-
> http://www.mkesc.co.uk/ise.pdf
> Points to an excellent method for dealing with Quadrature encoders.
> The solution almost comes down to the following code snippet (from the paper)
> I used two port pins to trigger a common ISR, and it worked a treat :) Unfortunately for
this group I was using an AVR at the time ;P
> I have yet to see a better approach.
>
> extern signed short angle; /* rotation since reset */
> static unsigned char ab = 0; /* the old value of the sensor ports */
> const signed short table[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
> /* increment of angle for the 16 possible bit codes */
> ab = ab << 2; /* move the old data left two places */
> ab |= (port & 0x3); /* OR in the two new bits */
> angle += table[(ab & 0xf)]; /* get the change from the 16 entry table */
>
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Re: Quadrature Encoder - OneStone - Aug 5 17:27:48 2009
have a look at app note slaa222. This is for the FW42x series scan
interface, and uses LC ssensors, but the theory is the same, and it has
a useful state table that handles direction rotation and sensor bounce.
Or just look up app code from any old mouse wheel. I think there was a
TI one, and there were several for PICs which translate easily.
Cheers
Al
David wrote:
> --- In m...@yahoogroups.com, "old_cow_yellow"
wrote:
>> --- In m...@yahoogroups.com, "tintronic" wrote:
>>> I made a code for a rotary switch many years ago. I connected A and B to 2 P1 inputs
each, to generate an interrupt on each edge of each signal. The ISR consisted of a state
machine with 4 states: 00, 01, 11 and 10 corresponding to the state of the AB inputs.
Depending on the previous state and the current state, the pulses variable was incremented
or decremented. To make sure no pulses were missed, invalid transitions between 00 <-> 11
and 01 <-> 10 were reported as errors (you can't know the direction of rotation in case
you missed a transition, however, you could assume it is maintaining the direction of the
previous transition). No matter how fast I could turn the encoder with my hand (which was
far faster than it would ever rotate once installed), it never detected those invalid
transitions and always kept the correct position, proving the code was robust.
>>> This has also the benefit (or drawback) that the resolution of your enconder is
cuadruplied (1000ppr = 2000 edges per rotation on each signal, 4000 total epr).
>>>
>>> In your case, this would mean:
>>>
>>> 4epp x 1000ppr x 400rpm
>>> -------------------- = 26,666.67 edges per second (int. freq.)
>>> 60 seconds/minute
>>>
>>> Using a 8MHz crystal, you'd have about 300 cycles between interrupts to execute the
ISR and have time left for your other interrupts and/or main loop.
>>>
>>> No matter how you implement the counting, you need to take care of how you read the
variable that stores the pulses. Make sure any read, write and read->modify->write
operation on it is atomic, that is, that the operation can not be interrupted.
>>>
>>> Regards,
>>> Michael K.
>>>
>> Let me see if I can repeat what Michael said:
>>
>> // Signals A & B form a 2-bit Gray code with 4 states
>> enum
>> {
>> Q0, // 00, A low & B low
>> Q1, // 01, A low & B high
>> Q2, // 11, A high & B high
>> Q3, // 10, A high & B low
>> } state;
>>
>> // Changes of A & B are named as 4 kinds of events
>> enum
>> {
>> AL2H, // A low to high
>> AH2L, // A high to low
>> BL2H, // B low to high
>> BH2L, // B high to low
>> } event;
>>
>> // We want to implement a binary counter
>> signed long int count;
>>
>> // The state and counter are driven by events as follows
>> switch (event)
>> {
>>
>> case AL2H: // A low to high
>> {
>> switch (state)
>> {
>> case Q0: //00
>> {state = Q3; count--; break;}
>> case Q1: //01
>> {state = Q2; count++; break;}
>> default: { errow(); }
>> }
>> break;
>> }
>>
>> case AH2L: // A high to low
>> {
>> switch (state)
>> {
>> case Q2: //11
>> {state = Q1; count--; break;}
>> case Q3: //10
>> {state = Q0; count++; break;}
>> default: { errow(); }
>> }
>> break;
>> }
>>
>> case BL2H: // B low to high
>> {
>> switch (state)
>> {
>> case Q0: //00
>> {state = Q1; count++; break;}
>> case Q3: //10
>> {state = Q2; count--; break;}
>> default: { errow(); }
>> }
>> break;
>> }
>>
>> case BH2L: // B high to low
>> {
>> switch (state)
>> {
>> case Q1: //01
>> {state = Q0; count--; break;}
>> case Q2: //11
>> {state = Q3; count++; break;}
>> default: { errow(); }
>> }
>> break;
>> }
>>
>> }
>>
> This link :-
> http://www.mkesc.co.uk/ise.pdf
> Points to an excellent method for dealing with Quadrature encoders.
> The solution almost comes down to the following code snippet (from the paper)
> I used two port pins to trigger a common ISR, and it worked a treat :) Unfortunately for
this group I was using an AVR at the time ;P
> I have yet to see a better approach.
>
> extern signed short angle; /* rotation since reset */
> static unsigned char ab = 0; /* the old value of the sensor ports */
> const signed short table[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
> /* increment of angle for the 16 possible bit codes */
> ab = ab << 2; /* move the old data left two places */
> ab |= (port & 0x3); /* OR in the two new bits */
> angle += table[(ab & 0xf)]; /* get the change from the 16 entry table */
> ------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Re: Quadrature Encoder - Paul Curtis - Aug 5 17:28:48 2009
On Wed, 05 Aug 2009 22:24:22 +0100, old_cow_yellow
wrote:
> c is "portable". Is it not?
Programs written in C *can* be portable. Programs written in C *can* be
non-portable. (In fact, they can be both portable and non-portable at the
same time.)
Writing a program in C does not imply portability just by the act of using
the C language to express yourself.
-- Paul.
------------------------------------
______________________________
controlSUITE software. Comprehensive. Intuitive. Optimized.
Real-world software for real-time control. Details Here!

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )Re: Quadrature Encoder - tintronic - Aug 6 2:43:36 2009
> Let me see if I can repeat what Michael said:
>
> // Signals A & B form a 2-bit Gray code with 4 states
> enum
> {
> Q0, // 00, A low & B low
> Q1, // 01, A low & B high
> Q2, // 11, A high & B high
> Q3, // 10, A high & B low
> } state;
>
> // Changes of A & B are named as 4 kinds of events
> enum
> {
> AL2H, // A low to high
> AH2L, // A high to low
> BL2H, // B low to high
> BH2L, // B high to low
> } event;
>
> // We want to implement a binary counter
> signed long int count;
>
> // The state and counter are driven by events as follows
> switch (event)
> {
>
> case AL2H: // A low to high
> {
> switch (state)
> {
> case Q0: //00
> {state = Q3; count--; break;}
> case Q1: //01
> {state = Q2; count++; break;}
> default: { errow(); }
> }
> break;
> }
>
> case AH2L: // A high to low
> {
> switch (state)
> {
> case Q2: //11
> {state = Q1; count--; break;}
> case Q3: //10
> {state = Q0; count++; break;}
> default: { errow(); }
> }
> break;
> }
>
> case BL2H: // B low to high
> {
> switch (state)
> {
> case Q0: //00
> {state = Q1; count++; break;}
> case Q3: //10
> {state = Q2; count--; break;}
> default: { errow(); }
> }
> break;
> }
>
> case BH2L: // B high to low
> {
> switch (state)
> {
> case Q1: //01
> {state = Q0; count--; break;}
> case Q2: //11
> {state = Q3; count++; break;}
> default: { errow(); }
> }
> break;
> }
>
> }
>
Not quite, OCY.
I don't care what the 'change' on A and B was. All I care are the previous and the current
state of AB. It's easyer that way (or at least easier to follow). Modifying your
example:
// Signals A & B form a 2-bit Gray code with 4 states
enum
{
Q0, // 00, A low & B low
Q1, // 01, A low & B high
Q2, // 11, A high & B high
Q3, // 10, A high & B low
} oldstate,newstate;
__interrupt void P1_ISR (void)
{
newstate = get_AB_state();
clear_AB_ifg();
switch (oldstate)
{
case Q0:
switch (newstate)
{
case Q1:
{count++; break;}
case Q3:
{count--; break;}
default:
{errow(); break;}
}
break;
case Q1:
switch (newstate)
{
case Q2:
{count++; break;}
case Q0:
{count--; break;}
default:
{errow(); break;}
}
break;
case Q2:
switch (newstate)
{
case Q3:
{count++; break;}
case Q1:
{count--; break;}
default:
{errow(); break;}
}
break;
case Q3:
switch (newstate)
{
case Q0:
{count++; break;}
case Q2:
{count--; break;}
default:
{errow(); break;}
}
break;
}
oldstate = newstate;
}
Regards,
Michael K.
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )
Re: Quadrature Encoder - old_cow_yellow - Aug 6 9:06:12 2009
Thank. I think you use interrupt to detect a change in A or B while I was very vague.
Anyway, when there is no change in A or B, there is no need to take any action. The state
machine is event driven, and the event is driven by change or specifically by interrupt
triggered by change.
--- In m...@yahoogroups.com, "tintronic"
wrote:
>
> > Let me see if I can repeat what Michael said:
> >
> > // Signals A & B form a 2-bit Gray code with 4 states
> > enum
> > {
> > Q0, // 00, A low & B low
> > Q1, // 01, A low & B high
> > Q2, // 11, A high & B high
> > Q3, // 10, A high & B low
> > } state;
> >
> > // Changes of A & B are named as 4 kinds of events
> > enum
> > {
> > AL2H, // A low to high
> > AH2L, // A high to low
> > BL2H, // B low to high
> > BH2L, // B high to low
> > } event;
> >
> > // We want to implement a binary counter
> > signed long int count;
> >
> > // The state and counter are driven by events as follows
> > switch (event)
> > {
> >
> > case AL2H: // A low to high
> > {
> > switch (state)
> > {
> > case Q0: //00
> > {state = Q3; count--; break;}
> > case Q1: //01
> > {state = Q2; count++; break;}
> > default: { errow(); }
> > }
> > break;
> > }
> >
> > case AH2L: // A high to low
> > {
> > switch (state)
> > {
> > case Q2: //11
> > {state = Q1; count--; break;}
> > case Q3: //10
> > {state = Q0; count++; break;}
> > default: { errow(); }
> > }
> > break;
> > }
> >
> > case BL2H: // B low to high
> > {
> > switch (state)
> > {
> > case Q0: //00
> > {state = Q1; count++; break;}
> > case Q3: //10
> > {state = Q2; count--; break;}
> > default: { errow(); }
> > }
> > break;
> > }
> >
> > case BH2L: // B high to low
> > {
> > switch (state)
> > {
> > case Q1: //01
> > {state = Q0; count--; break;}
> > case Q2: //11
> > {state = Q3; count++; break;}
> > default: { errow(); }
> > }
> > break;
> > }
> >
> > }
> > Not quite, OCY.
> I don't care what the 'change' on A and B was. All I care are the previous and the
current state of AB. It's easyer that way (or at least easier to follow). Modifying your
example:
>
> // Signals A & B form a 2-bit Gray code with 4 states
> enum
> {
> Q0, // 00, A low & B low
> Q1, // 01, A low & B high
> Q2, // 11, A high & B high
> Q3, // 10, A high & B low
> } oldstate,newstate;
> __interrupt void P1_ISR (void)
> {
> newstate = get_AB_state();
> clear_AB_ifg();
> switch (oldstate)
> {
> case Q0:
> switch (newstate)
> {
> case Q1:
> {count++; break;}
> case Q3:
> {count--; break;}
> default:
> {errow(); break;}
> }
> break;
> case Q1:
> switch (newstate)
> {
> case Q2:
> {count++; break;}
> case Q0:
> {count--; break;}
> default:
> {errow(); break;}
> }
> break;
> case Q2:
> switch (newstate)
> {
> case Q3:
> {count++; break;}
> case Q1:
> {count--; break;}
> default:
> {errow(); break;}
> }
> break;
> case Q3:
> switch (newstate)
> {
> case Q0:
> {count++; break;}
> case Q2:
> {count--; break;}
> default:
> {errow(); break;}
> }
> break;
> }
> oldstate = newstate;
> }
> Regards,
> Michael K.
>
------------------------------------

(You need to be a member of msp430 -- send a blank email to msp430-subscribe@yahoogroups.com )