A Shaft Encoder using Opto-reflectors

copyright, H. Paul Roach, Peter H. Anderson
Department of Electrical Engineering, Morgan State University
Baltimore, MD, Sept, 96


This section discusses the use of opto-reflectors in the context of determining the angular position of shaft which is driven by a stepping motor.


See Figure #1. An optoreflector is a self contained LED and opto-transistor pair which are mounted at an angle such that the light from the LED will reflect off a surface and be detected by the opto-transistor. The angle of the mounting of the LED and o pto-ransistor determines the distance from the sensor which will cause the reflection to be detected by the transistor. This is usually 3-5 mm. (5 mm is about 0.2 inches). Common applications of optoref;ective sensors are detecting whether there is pap er in a copy machine or printer and in determining the distance that a shaft has turned or determining the angular position of a shaft.

In this discussion, I identified two different types of opto-reflectors sold by Digikey and I have attempted to include enough information from the catalog such that you can design using these devices. These devices are;

     Digikey   Omron     Description                   Price Per 

     OR502-ND  EE-SB5B   Reflective, 5 mm, Non-amplified    $4.43

     OR525-ND  EE-SY310  Reflective, 5 mm, Amplified        $3.19
     OR526-ND  EE-SY410  Inverted logic of EE-SY310         $3.19

(Digikey sells an Omron Catalog; "Photomicrosensors Product Data Book", Omron Cat No. E05-DAX2, $5.00. You may be able to get it from Omron at tel (800) -55-OMRON.)

Non-Amplified. Omron EE-SB5B. (Data sheet is included).

A typical circuit is illustrated in Figure #2. Note that this has been designed for an I_forward of 20 mA and an output current of 200 uA. When there is no reflection, the optotransistor is off and the emmitter voltage is close to zero. When there is r eflection, the transistor turns on and the emitter goes toward +5 VDC. Thus, dark equates to logic 0 and light to logic 1.

The limited output current precludes direct interfacing with TTL, where even with LS devices I_input_low is typically 0.4 mA. However, with the CMOS logic family, the input impedance is very high with typical currents of less than 1.0 uA. Thus, a 4049 C MOS buffer has been used between the optoreflector and the TTL inputs associated with the parallel port.

Amplified. EE-SY310 and EE-SY410. (Data sheet is included).

A typical circuit is shown in Figure #3. Note that I_forward is again 20 mA. However, the output can sink 16 mA without the output rising above 0.4 VDC and thus, it may be directly interfaced with TTL.

The difference between the SY310 and 410 is simply the logic. With the 310, the output transistor is on (logic 0) when "dark" (no reflection) and with the 410, the output is at logic 0 when light (reflection).

(If anyone asked why would anyone prefer a non-amplified over an amplified, particulalry when the non-amplified is more expensive, I would have to say, I don't know! However, Digikey's pricing may not be indicative of actual factory pricing. That is, D igikey may have to price the non-amplifed higher as they don't sell all that many.)

Shaft Encoder. (See Figure #4).

In our application, we mounted four optoreflectors so as to read four concentric bands on a disk attached to the shaft of a stepping motor. Note that a non-amplified reflective sensor was used and thus, the outputs were buffered using a 4049 CMOS inverto r to interface with the TTL inputs on the parallel port.

The disk was coded using a 4-bit Gray code with a zero state being defined as dark. Thus, in reading "dark", the transistor associated with the opto-reflector is off and the output is ground through 22K which is a CMOS logic zero. This is then inverted by the 4049, and thus, the reading of dark results in a logic one at the input to the parallel port. Thus, in reading the highest four bits on the Status Port, the logic is inverted from what we originally defined. This can be easily corrected by invert ing the input in the program itself as illustrated below.

     input = ((inportb(STATUS)^0x80)>>4) & 0x0f; 
                      /* fetech input and put in lower nibble */

     gray = (input ^0x0f); /* invert */

     binary_position = gray ^ (gray >>1);
     /* this is discussed below */

In the following program, the stepping motor is simply turned 1000 steps in one direction and then in the other direction, and the gray_code and the binary position are continually displayed. This may be easily modified by the user to do more complex thi ngs such as to turn in one direction n revolutions and then stop on a specified binary position.

Note that the functions associated with the stepping motor differ from those presented in Volume 1, where the motor was advanced eight steps at a time. In the following routines, the array of patterns and a pointer to the index in the array are passed to the function. This permits the index to be changed in the functions and the changed value is avaiable to the calling program.

** Program GRAY.C
** Turns stepping motor in one direction, continually displaying the
** position.  Then turns in opposite direction.
** Uses pointers for stepping motor patterns and index.
** H. P. Roach, P. H. Anderson, Sept 21, '96

#include <stdio.h>
#include <dos.h>

#define DATA 0x03bc
#define STATUS DATA+1
#define CONTROL DATA+2

void advance_one_way_one_step(int *patt, int *p_index);
void advance_other_way_one_step(int *patt, int *p_index);
int get_position(void);

void main(void)
   int patts[8] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x09};
   int n, binary_position, index=0;

   for (n=0; n<1000; n++)
   /* turn one way, continually displaying position */
      advance_one_way_one_step(patts, &index);
      binary_position = get_position();
      printf("%x  ", binary_position);

   for (n=0; n<1000; n++)
   /* turn the other way, displaying position */
      advance_other_way_one_step(patts, &index);
      binary_position = get_position();
      printf("%x  ", binary_position);

void advance_one_way_one_step(int *patt, int *p_index)
   outportb(DATA, patt[*p_index]);
   if(*p_index == 8)
   /* if beyond 7, set back to zero */
      *p_index = 0;

void advance_other_way_one_step(int *patt, int *p_index)
   outportb(DATA, patt[*p_index]);
   if(*p_index <0)
   /* if lower than 0, set back to 7 */
      *p_index = 7;

int get_position(void)
   int input, gray, binary;
   input = ((inportb(STATUS)^0x80)>>4)&0x0f;
   gray = input ^ 0x0f;
   binary = gray ^ (gray >>1);

The Gray Code.

Unlike natural binary, the Gray Code is defined such that there is only one transistion in going between adjacent states. The advantage of this code in applications such as this is shown in Figure #5.

An interesting property of the Gray Code is the algorithm to convert from Gray to natural binary. Take the Gray Code state and exclusive-or this value with the right shifted Gray Code state. For example; for binary position 8;

     Gray Code      1100
     Right Shift    0100

Exclusive oring the above, results in 1000 or natural binary 8.

The four bit Gray Code is provided below for general reference. You may wish to verify the above algorithm or use the table to lay out your own template for mouting on a disk.

     Position  Binary    Gray 

     0         0000      0000
     1         0001      0001
     2         0010      0011
     3         0011      0010
     4         0100      0110
     5         0101      0111
     6         0110      0101
     7         0111      0100
     8         1000      1100
     9         1001      1101
     10        1010      1111
     11        1011      1110
     12        1100      1010 
     13        1101      1011
     14        1110      1001
     15        1111      1000