Hands-On Arduino
Incremental Encoders I
Overview
Motion Input!
Encoder Basics!
Unidirectional Decoding!
Bi-Directional Decoding!
Using Pin Change Interrupts!
Using Assembly Language
Hands On Arduino: Encoders
How Can We Input Motion?
We need something that will change when the
thing we want to measure moving moves.!
Generally, something electrical!
Example: Potentiometers
(Resistance Changes)
Hands On Arduino: Encoders
Types of Motion Input
Position!
Encoder!
Potentiometer!
Velocity!
Tachometer!
Rate Gyro!
Estimator!
Acceleration!
Accelerometer
Hands On Arduino: Encoders
What is an Encoder?
A General concept.!
Implementation depends on the application!
Used for!
Data Compression!
Information Security
Hands On Arduino: Encoders
What does the Encoder
Encode?
Converts a change in position to digital signals.!
The resolution depends upon the number of
pulses in a specified distance!
If measuring only in one direction, only one
channel is required.!
If measuring in both directions, two channels
are needed: A & B, or I & Q.
Hands On Arduino: Encoders
Pulse Technology
Magnetic!
Switch Contacts!
Optical Reflective!
Optical Transmissive
Hands On Arduino: Encoders
Encoder & Decoder
Encoder
Hands On Arduino: Encoders
Decoder
Absolute Encoders
Encoders where each position provides a unique
code.!
Often based on a Gray code, where the codes for
adjacent positions differ by at most 1 bit.!
No data compression, thus requires n channels.!
More complicated to work with!
Exact position is always known.
Hands On Arduino: Encoders
Absolute Encoders
8 bit absolute encoder disc!
each ring corresponds to a
different bit.!
The number of PPR is 28 = 256!
Requires 8 channels!
only get 1x decoding!
know where you are at startup!
Hands On Arduino: Encoders
Gray code decoding
Single Direction: Encode
Detector
Emitter
Number of!
Pulses per !
Revolution!
(PPR): N
1x Resolution: 360/N!
2x Resolution: 180/N
Hands On Arduino: Encoders
Single Direction: Decode
Count the pulses (1x)!
Count the transitions (2x)!
The counting can be done by either:!
polling the channel!
using the channel to trigger interrupts
An unsigned
long
(uint32_t) is recommended for the!
counter!
Hands On Arduino: Encoders
Sample Code: Polling
unsigned
long
count=0;
unsigned
long
timep,
time,
etime;
byte
A,Ap;
!
void
setup()
{
Serial.begin(9600);
//connect
Channel
A
to
pin
3
pinMode(3,
INPUT);
//set
the
initial
time
timep
=
micros();
//set
the
initial
value
of
A
Ap
=
digitalRead(3);
}
Hands On Arduino: Encoders
void
loop()
{
A
=
digitalRead(3);
if
(A^Ap)//is
there
a
difference?
{
count++;//if
so,
increment.
}
Ap
=
A;
time
=
micros();
etime
=
time
-
timep;
if
(etime
>
1000000)//every
1
sec
{
Serial.println(count);
timep
=
time;//reset
timer
}
}
Sample Code:
Using Interrupts
unsigned
long
count=0;
unsigned
long
timep,
time,
etime;
void
setup()
{
Serial.begin(9600);
//connect
Channel
A
to
pin
3
pinMode(3,
INPUT);
attachInterrupt(1,transition,
CHANGE);
//set
the
initial
time
timep
=
micros();
}
!
void
transition()
{
count++;
}
!
Hands On Arduino: Encoders
void
loop()
{
time
=
micros();
etime
=
time
-
timep;
if
(etime
>
1000000)//
1
second
{
Serial.println(count);
timep
=
time;
//reset
timer
}
}
Sample Code:
Velocity Estimation
//This
displays
the
number
of
transitions
//
per
second.
unsigned
long
count=0;
unsigned
long
timep,
time,
etime;
void
setup()
{
Serial.begin(9600);
//connect
Channel
A
to
pin
3
pinMode(3,
INPUT);
attachInterrupt(1,transition,
CHANGE);
//set
the
initial
time
timep
=
micros();
}
!
void
transition()
{
count++;
}
!
Hands On Arduino: Encoders
void
loop()
{
time
=
micros();
etime
=
time
-
timep;
if
(etime
>
1000000)//
1
second
{
Serial.println(count);
count
=
0;
//reset
the
counter
timep
=
time;
//reset
timer
}
}
Units, Units, Unite!
Units are essential information for real systems.!
The units relate to what the relevant quantity is.!
The encoders have a fixed construction:!
Linear: pulses per inch, pulses per mm!
Rotary: pulses per revolution.
Hands On Arduino: Encoders
Units, Units, Unite!
Example: a rotary encoder on a motor shaft with
512 pulses per revolution.!
Since one revolution equals 360, then !
for 1x decoding, each count means the motor has turned
360/512 = 0.7031.!
for 2x decoding, there are 512x2 = 1024 transitions per
revolution, and each count corresponds to
360/1024 = 0.3516
Hands On Arduino: Encoders
Absolute Encoders
Encoders where each position provides a unique
code.!
Often based on a Gray code, where the codes for
adjacent positions differ by at most 1 bit.!
No data compression, thus requires n channels.
Hands On Arduino: Encoders
BiDirectional Encoding
Detectors
Emitters
A
1 1 0 0
1 1 0 0
In-Phase
1 0 0
1 0 0
Quadrature
Hands On Arduino: Encoders
BiDirectional Encoding
Hands On Arduino: Encoders
BiDirectional Encoding
A
1
B
1
state: 1
Hands On Arduino: Encoders
State
BiDirectional Encoding
A
FORWARD:
t
B switches before A
Reverse
t
A switches before B
t
Hands On Arduino: Encoders
BiDirectional (1x) Decoding
When B = 1, use the transitions of A to determine
whether to increment or decrement the counter.
A
1
B
1
state: 1
Hands On Arduino: Encoders
Edge
counter
A-rising
increment
A-falling
decrement
BiDirectional (2x) Decoding
A
B
1
B
1
state: 1
Hands On Arduino: Encoders
Edge
counter
A-rising
decrement
A-falling increment
A-falling decrement
A-rising
increment
BiDirectional (4x) Decoding
prior!
state
present
state
AB
11
11
dec
inc
10
inc
dec
00
inc
dec
01
dec
inc
Hands On Arduino: Encoders
2
10
3
00
4
01
A
1
state: 1
X
=
do
nothing.
BiDirectional (4x) Decoding
switchcase !
ifelseelse!
Array!
Pin Position
Hands On Arduino: Encoders
BD4x: SwitchCase
long
count=0;
unsigned
long
timep,
time,
etime;
boolean
A,B;
byte
state,
statep;
void
setup()
{
Serial.begin(9600);
pinMode(2,
INPUT);//Channel
A
pinMode(3,
INPUT);//Channel
B
attachInterrupt(0,Achange,CHANGE);
attachInterrupt(1,Bchange,CHANGE);
timep
=
micros();
//set
the
initial
time
//read
the
initial
value
of
A
&
B
A
=
digitalRead(2);
B
=
digitalRead(3);
//set
initial
state
value
if
((A==HIGH)&&(B==HIGH))
statep
=
1;
if
((A==HIGH)&&(B==LOW))
statep
=
2;
if
((A==LOW)&&(B==LOW))
statep
=
3;
if
((A==LOW)&&(B==HIGH))
statep
=
4;
}
Hands On Arduino: Encoders
void
loop()
{
time
=
micros();
etime
=
time
-
timep;
if
(etime
>
1000000)
{
Serial.println(count);
timep
=
time;
}
}
BD4x: SwitchCase
void
Achange()
{
A
=
digitalRead(2);
B
=
digitalRead(3);
//determine
state
value
if
((A==HIGH)&&(B==HIGH))
state
=
1;
if
((A==HIGH)&&(B==LOW))
state
=
2;
if
((A==LOW)&&(B==LOW))
state
=
3;
if
((A==LOW)&&(B==HIGH))
state
=
4;
switch
(state)
{
case
1:
{
if
(statep
==
2)
count--;
if
(statep
==
4)
count++;
break;
}
Hands On Arduino: Encoders
case
2:
{
if
(statep
==
1)
count++;
if
(statep
==
3)
count--;
break;
}
case
3:
{
if
(statep
==
2)
count++;
if
(statep
==
4)
count--;
break;
}
default:
{
if
(statep
==
1)
count--;
if
(statep
==
3)
count++;
}
}
statep
=
state;
}
BD4x: Array
State
present
0
1
2
3
prior
AB
11
10
00
01
0
11
X
inc
X
dec
1
10
dec
X
inc
X
2
00
X
dec
x
inc
3
01
inc
X
dec
x
Quadrature
Encoder
Matrix
(Array):
QEM[16]
=
{0,-1,0,1,1,0,-1,0,0,1,0,-1,-1,0,1,0}
Index
=
4*state
+
statep;
count
=
count
+
QEM[Index];
Hands On Arduino: Encoders
BD4x: Array
void
Achange()
{
A
=
digitalRead(2);
B
=
digitalRead(3);
//determine
state
value
if
((A==HIGH)&&(B==HIGH))
state
=
0;
if
((A==HIGH)&&(B==LOW))
state
=
1;
if
((A==LOW)&&(B==LOW))
state
=
2;
if
((A==LOW)&&(B==HIGH))
state
=
3;
index
=
4*state
+
statep;
count
=
count
+
QEM[index];
statep
=
state;
}
Hands On Arduino: Encoders
void
Bchange()
{
A
=
digitalRead(2);
B
=
digitalRead(3);
//determine
state
value
if
((A==HIGH)&&(B==HIGH))
state
=
0;
if
((A==HIGH)&&(B==LOW))
state
=
1;
if
((A==LOW)&&(B==LOW))
state
=
2;
if
((A==LOW)&&(B==HIGH))
state
=
3;
index
=
4*state
+
statep;
count
=
count
+
QEM[index];
statep
=
state;
}