An incremental optical encoder is nothing more than a slotted
disk and infrared (IR) emitter-detector pairs. Disk
rotation results in IR pulses which must be handled; pulse
counting, timing and quadrature yields the disk's angular position,
velocity and direction respectively. The photo on the left
illustrates a PC based ISA bus card solution that automatically
handles encoder pulses and yields disk measurements.
There are many instances when rotation angle, velocity and direction must be accurately measured. Examples include robot odometry, XYZ (lead screw) table motion measurements, telescope lateral and longitudinal positioning and knob inputs.
PC based solutions are attractive because of event-driving; through software, angle feedback can be used to improve navigation or positioning.
The ISA bus provides you an easy interface to build your PC quadrature card upon. Your card will plug into your PC's motherboard much like a modem or sound card does. Although commercial PC bus based cards cost hundreds of dollars, this tutorial will show you how you can prototype one for less than $50US, in an afternoon.
This tutorial is broken down as follows:
PART DESCRIPTION | VENDOR | PART | PRICE (1999) | QTY | |
PC BUS PROTOTYPING CARD | JAMECO | 21531 | 17.95 | 1 | |
LS7266 QUADRATURE IC | SEE BELOW | 1 | |||
28 PIN WIREWRAP SOCKET | JAMECO | 40336 | 1.35 | 1 | |
74HC138 3-8 DECODER | JAMECO | 45330 | 0.45 | 1 | |
16-PIN WIREWRAP SOCKET | JAMECO | 37436 | 0.95 | 1 | |
8 PIN DOUBLE ROW 0.1" HEADER | JAMECO | 109516 | 0.15 | 1 | |
JUMPER SHORTING BLOCK | JAMECO | 22023 | 0.19 | 2 | |
INCREMENTAL ENCODER | SEE BELOW | ||||
HEADERS | DIGIKEY | ||||
HOUSING | DIGIKEY | ||||
CRIMPS | DIGIKEY | WM2200-ND | |||
Headers, housings and crimps were used for quick and professional looking connections. Example Digikey part numbers are WM4002-ND (headers), WM2002-ND (housings), WM2200-ND (crimps) and WM2312-ND for crimp tool. Of course, you can choose to wirewrap/solder your circuit without these parts.
The heart of this card is the 7266 quadrature IC, a 24-bit encoder to microprocessor interface chip, costing approximately $16. There are two main suppliers: the manufacturer, LSI and US Digital.
Readers may be familiar with the more widely available Hewlett-Packard/Agilent's HCTL-2000 chips. However the 7266 has distinct advantages; the 7266 provides 24-bits of resolution, can handle two encoders and is competitively priced.
To test your PC Quadrature Card, you will need an incremental optical encoder. The one featured in the introductory photo above, is the US Digital ???. You can hack a $5 ubiquitous serial PC mouse as shown in ??? for a cheap source of encoders.
7266Schematic060500.pdf is the Acrobat file of the same schematic. You will need Adobe's free Acrobat reader to view it.
The schematic is relatively straight-forward. One possible (and common) confusing point with ISA bus circuits is the use of the prefix "A". An ISA card has a component and solder side, often called "A" and "B" respectively. There are 62 edge tabs: 31 on the component side (A1-to-A31) and 31 on the solder side (B1-to-B31). However, address lines often use the prefix "A" too. On the PC there are 20 address lines (A0-to-A19).
To avoid this prefix confusion, this tutorial uses the lower case "a" to refer to the component side's 31 edge tabs. For example a11 is the AEN pin. "b" refers to the solder side's 31 edge tabs. For example b13 identifies the /WR pin. The schematic above includes the ISA 62 pinout for referencing connections to other components, namely the 74138 and 7266.
Encoder-to-Card Tethering:
You will need to tether your incremental optical encoder to your ISA card. Typical quadrature-capable encoders have 4 or 5 pins. The figure below shows a commerical encoder (US quarter shown for scale) and 5-pin pinout diagram. A complete tutorial on hacking a mouse for a cheap source of encoders also exists on the Boondog website.
The 7266 can handle encoder index pulses, but to simply illustrate its quadrature and pulse reading capabilities, the index pin is not used in this tutorial.
The encoder uses a conventional 0.1" pin spacing. A standard 4-pin housing, header and ribbon cable are used to tether the encoder to the ISA prototyping card. The housing and headers provide quick connect/disconnect of your encoder as seen in the photo below.
Shorting Block and Address Decoding:
The circuit's 8-position double row header and shorting block are used for address decoding. Like modem or sound cards for example, your Quadrature encoder card will plug into an ISA slot on your PC's motherboard. To distinguish your card from the others, requires it to have a unique address. The shorting block is used for this purpose.
The shorting block allows you to choose one of a possible eight addresses, as shown on Table 2:
ROW POSITION | HEX VALUE | DECIMAL VALUE |
1 | 200 | 512 |
2 | 220 | 544 |
3 | 240 | 576 |
4 | 260 | 608 |
5 | 280 | 640 |
6 | 2A0 | 672 |
7 | 2C0 | 704 |
8 | 2E0 | 736 |
For example, placing the shorting block on row 4, assigns your card an address of 260h (or 608d). The suffixes h and d refer to hex and decimal representations respectively. The Turbo C example, given in the section below, illustrates card reading and/or writing using this address.
The 74138 is a 3-to-8 decoder. The ISA pins a24, a25 and a26 serve as its three inputs and depending on their values, will yield one 8 possible outputs. This output will be used to enable 7266 quadrature chip reading and/or writing.
For example, the card address, 608d is 1001100000 binary:
which results in a24, a25 and a26 to be 0, 1 and 1 respectively. These 3 values feed into the 74138's A, B and C inputs thus selecting the 74138's Y3 output:
In addition, for Y3 to go active low, the 74138's /G2A, /G2B and G1 must 0, 0 and 1 respectively. 608d already sets /G2B and G1 to 0 and 1 respectively, as seen by its binary representation figure above. The 74138's G1 pin is connected to ISA bus pin a11 (AEN). AEN = 0 whenever the expansion bus is called. This happens whenever an outportb(608, someValue) or inportb(608) is invoked in Turbo C. In QuickBasic, AEN = 0 when out(608, someValue) or inp(608) is executed.
In essence, programming your card involves three simple steps: one, initialization; two, transfering the 7266's counters to the output latch, and three, reading the encoder value. If you read the LSI LS7266 data sheet however, you might be overwhelmed by their use of many cryptic acronyms and programming appears complicated.
Furthermore, US Digital, which provides sample C code named pc7266, for their commerical version of the card, equally appears cryptic and difficult to understand for first-time users of the 7266.
To appreciate that programming is actually quite simple, it might be best to avoid reading the 7266 data sheet initially. Instead, accept the #define's used in the Turbo C example (test7266.c). Once you've convinced yourself that it reads and displays your encoders' values, you can use Appendix A, coupled with LSI's LS7266 data sheet to further understand how the code works.
Appendix B provides a glossary of acronymns. This can further assist you in making the LSI 7266 data sheet more comprehensive.
"Big picture" applications such as mobot navigation, telescope pointing, and XYZ-table positioning benefit from this PC-based solution. Some companies charge hundreds of dollars for such a card, but you can construct your own with this tutorial and less than $50 in off-the-shelf parts. Sample Turbo C code was provided to read two encoders (X and Y axes) and serve as a base for your own coding endeavors. The Appendices give code explanations and assist in these endeavors.
Click here to return to Main Page
Click here to email me
Their is a control and a data register for the X and Y axes. Their values depend on the base address and are:
xData = baseAddress; xControl = baseAddress + 1; yData = baseAddress + 2; yControl = baseAddress + 3;Next, main initializes your card with a call to init() and resets the control registers. EFLAG_RESET is #define'd as 86 hex (134 decimal or 10000110 binary). If you refer to the LSI 7266 data sheet, writing 86 hex to the X-axis control register will reset the error flag on both X and Y axes:
outportb(xControl, EFLAG_RESET); outportb(xControl, BP_RESETB);The second line above resets the byte pointer (BP) on both X and Y axes by writing the #define'd variable BP_RESETB (81 hex, 129 decimal or 10000001 binary) to the X-axis control register. You can read about this further if you wish by looking at the "RLD" figure in the LS7266 data sheet. Suffice it say that it makes sense to reset the error flag and byte pointer before your card attempts to acquire encoder pulses.
Initialization continues by telling your card something about its clock. Encoder chips like the 7266 are in essence flip-flops. As such they rely on a clock to synchronize the reading of encoder pulses. Your 7266 card uses your PC's 14.81818 MHz oscillator (OSC) for the clock. This is shown in the schematic where pin 2 on the 7266 is wired to the ISA bus at b30. The code that tells your 7266 this is:
outportb(xData, CLOCK_DATA); outportb(xControl, CLOCK_SETUP);The data sheet says that writing CLOCK_SETUP (98 hex, 152 decimal or 10011000 binary) to the X-axis control register will transfer PR0 to PSC. What this means is that the preset register 0 (PR0) value, which is on the data bus, is tranferred to the filter clock prescaler (PSC). This value is CLOCK_DATA (14 decimal or 00001110 binary), or 14 MHz (rounded from 14.31818 MHz). This seems to be a roundabout way to tell your 7266 card this, but that's how the chip is configured; one loads the preset register via the data bus. You can refer to section on "Filter Clock Prescalers" in the 7266 data sheet for more details.
Next, you tell your 7266 to enable both the A and B channels. Quadrature relies on have two channels. INPUT_SETUP (C1 hex, 193 decimal or 11000001 binary) achieves this:
outportb(xControl, INPUT_SETUP);This statement also configures the carry and borrow pins. In essence, the above just readies your card for quadrature. You can refer to the "Input/Output Control Register XIOR and YIOR" section of the LS7266 data sheet.
The 7266 is powerful because it can effectively increase the resolution of your actual encoder. For example, if you have an 100 slot encoder, the 7266 can provide a 100, 200 or 400 resolution read. The #define'd variables:
QUAD_X1 (A8 hex, 168 decimal, 10101000 binary) QUAD_X2 (B0 hex, 176 decimal, 10110000 binary) and QUAD_X4 (B8 hex, 184 decimal, 10111000 binary)provide times 1, times 2 and times 4 resolution respectively. This is detailed in the "Counter Mode Registers XCMR and YCMR" section of the LS7266 data sheet. The following statement configures your card for times 1 resolution:
outportb(xControl, QUAD_X1);init() finishes using CNTR_RESETB (82 hex, 130 decimal, 10000010 binary) to reset both X and Y axes' counters to zero, and resets the borrow, carry, compare and sign toggles as detailed in the "Reset and Load Signal Decoders (RLD)" section of the LS7266 data sheet:
outportb(xControl, CNTR_RESETB);
outportb(xControl, TRSFRCNTR_OL); outportb(yControl, TRSFRCNTR_OL);The above will transfer the counter value to the output latch, first for the X-axis and second, for the Y-axis. This is detailed in the "Reset and Load Signal Decoders XRLD and YRLD" section of the LS7266 data sheet.
/* Read X-axis encoder value */ outportb(xControl, BP_RESETB); xPosition = inportb(xData); /* least significant byte */ xPosition += inportb(xData) << 8; xPosition += inportb(xData) << 16; /* most significant byte */The X-axis counter's 24-bit value is constructed using C's "<<" bit shift operator. Similarly, to read the Y-axis encoder value:
/* Read Y-axis encoder value */ outportb(yControl, BP_RESETB); yPosition = inportb(yData); /* least significant byte */ yPosition += inportb(yData) << 8; yPosition += inportb(yData) << 16; /* most significant byte */xPosition and yPosition are type long (since their value can range from 0 to (2^24)-1 = 16777215 decimal or FFFFFF hex).
To recap, programming your 7266 is quite simple. There is some startup cost in initialization your card, however actual reading of X and Y encoder values involves a transfer to output latch, then the actual read (i.e. three inportb() statements).
FCK Filter ClocK input PR0 Preset Register byte 0 PSC filter clock PreSCaler BP Byte Pointer CNTR CouNTeR RLD Reset or Load Decode CMR Counter Mode Register IOR Input or Output control Register XIOR X-axis Input or Output control Register YIOR Y-axis Input or Output control Register XA X-axis, channel A XB X-axis, channel B YA Y-axis, channel A YB Y-axis, channel B XLCNTR X-axis, Load CouNTeR YLCNTR Y-axis, Load CouNTeR OL Output Latch XLOL X-axis, Load Output Latch YLOL Y-axis, Load Output Latch XRCNTR X-axis, Reset CouNTeR YRCNTR Y-axis, Reset CouNTeR XABG X-axis, count enABle or disable Gate YABG Y-axis, count enABle or disable Gate FLG FLaG E Error flag BT Borrow Toggle flip-flop CT Carry Toggle flip-flop CPT Ccompare Toggle flip-flop S Sign flag IDX InDeX flag