You are on page 1of 30

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;
}