This project uses an Atmel at90s2313 AVR processor to measure resistance values and generate R/C style pulses suitable for driving servos or testing R/C controlled robots without the transmitter. It measures four channels and provides four R/C style pulses. It uses an LCD display to indicate the current pulse width and to indicate when the board is in CALIBRATE mode. Analogue joysticks, by their nature, are highly variable so the tether unit needs to be calibrated for the particular joystick. Once calibrated it appears to be quite stable: pulse width values stay within a few microseconds over several days of operation at room temperatures.
The techniques presented here are easily capable of 8 bits of resolution (256). The display, below, was truncated to 100 discrete values primarily to fit everything on the screen of a 2x16 LCD display. If you have a 2x20 or 2x24 character display, removing a comment from the display code will restore the fourth digit.
Some of the techniques illustrated in this article are:
- Interfacing to a standard PC analogue joystick.
- Measuring a resistance by timing the charge cycle of a capacitor.
- Driving an LCD display in 4 bit mode.
First, they are low powered CMOS devices with a very fast single clock cycle instruction set. That allows S/W loops to make very fast (single uS/loop) timing measurements. It is important to be able to do this in S/W so that many channels (four in this case) can be implemented. The same techniques are used in an 8 channel generator using the at90S8515 chip (40 pin vs. 20 pin AVR processor).
Second, because they are a modern architecture, they are well suited for both assembly and higher language programming. The majority of the code in this project was written in C. The LCD code and the R-C timing and R/C pulse code was written in assembly mainly because they were written before I started using C in my projects. The entire code base takes only 1.5k of the space in the processor.
Third, the AVR processors have a well defined I/O structure that simplifies interfacing to external devices. The I/O pins have a fixed input threshold voltage of .45 * VCC that allows stable R-C timing regardless of minor variations in the supply voltage.
Joysticks
The CH-Products Joystick, is a standard in analogue joysticks. It comes with a joystick with two potentiometers, one for the X and one for the Y axis. A third potentiometer is connected to a throttle wheel. In addition to the analogue signals, the joystick has two buttons: a trigger and a top button. The joystick interfaces with the Game Port with a 15 pin male sub-D connector. The analogue joystick no longer seems supported at CH, but you can call the factory to purchase them.
You can read everything you need to know about Analogue Joysticks at ePanorama.
Measuring the position
Each potentiometer is a 100k linear taper potentiometer connected to +5 source. Switches are connected to a ground terminal. The algorithm for measure the resistance starts with a completely discharged capacitor. The capacitor is kept discharged by driving the output pin of the processor to ground (0). Then, the I/O pin is switched to an input and the capacitor is allowed to charge towards VCC through the joystick resistor. At a particular threshold voltage, .45 * VCC, the input pin will detect that a '1' is present. The processor simply spins in a loop, incrementing a counter, until it reads a '1' at that port. The software then switches the I/O pin to an output with a value of 0, discharging the capacitor. The I/O pin is left as an output pin, with a value of 0 until the next measurement.
Shown above is the schematic of Joystick interface. The series 10k resistors set the minimum charge time and protect the CPU output drivers from the zero ohm position of the potentiometer. Note: Pin 2 is the trigger switch. When open, the capacitor will never charge up. The software for timing the R-C charge time has a timeout. So the switch either shows maximum time or minimum time and nothing in between.
The voltage across a capacitor (Vc) being charged by a voltage (V) is Vc = V*(1-e^(-t/rc)). If V, Vc and C are held constant, then the time, 't' will vary in direct proportion to 'r'. Since the threshold voltage for a 1 value in the AVR processor is well defined and and a ratio of the supply voltage we can use it to measure R with a simple R/C timing circuit.
Minimum and Maximum RC time (.1 ms and 2v/div)
The above photo shows the minimum and maximum charge times for the capacitor on this project.
R-C Time Math
Although I chose a .01uf capacitor mainly because it was what I had in my junk box, It turned out to be a good choice to give a maximum R-C time of less than 1ms. By re-arranging the formula, above, the timing is T = -Ln(.55)RC which gives ~.7ms with .01uf capacitor and 100k + 10k resistor (refer to schematic). Below is the algebra needed to convert the formula for voltage vs. time, to time for a given voltage, resistance and capacitance.
Vc = V(1-e^(-t/rc))
Vc/V = 1-e^(-t/rc)
Vc/V-1 = -e^(-t/rc)
1-Vc/V = e^(-t/rc)
Ln(1-Vc/V) = -T/RC
Ln(1-Vc/V)RC = -T
-Ln(1-Vc/V)RC = T
Substitute in 1 for V and .45 for Vc (the threshold voltage as a fraction of V) to get:
-Ln(.55)RC = T
This formula can be used to calculate R-C timing circuits for any AVR processor since they all have the same I/O structure and thresholds.
Calibrating the unit
The time needed to charge the capacitors is proportional to the resistance and the capacitance. Both joystick resistors and capacitor values are not precise and the unit needs to adjust the internal math to transform the measured R-C time to the 1.0 to 2.0 ms R/C pulse time. Once calibrated, however, the resulting pulses are precise (limited by the precision of the crystal driving the CPU - usually .1% for ceramic resonator, or .01% for a crystal). The calibration algorithm is fairly trivial. Calibration is a three step process. The first two steps occur when the CAL button is pressed and released:
- Stop generating R/C pulses, clear LCD and display "CALIBRATE", Record current R-C timing as the initial minimum and maximum value.
- Start scanning the inputs, recording the maximum and minimum values measured.
The third step occurs when the CAL button is pushed the second time. - The centre position is calculated as 1/2 the distance between the minimum and maximum values. Then the gain is calculated as 1000 * 16 / (maximum - minimum). Both the centre and gain are then recorded in non-volatile EEPROM memory.
The LCD display
LCD display is an industry standard HD44780 compatible character display. These displays are readily available, surplus, for $4-15 dollars in 1x8 to 4x40 character formats. All the displays have a 14 pin connector, either as an in-line or dual 2x7, header. All displays can be operated in an 8 bit or 4 bit I/O mode. The code implements a four bit interface requiring 6 I/O lines of the processor. It is a little more work to use the 4 bit mode, but the payoff is saving 4 I/O lines on your processor. There are other tricks to interfacing an LCD with as little as one line, but these all require an additional chip and even more code.
Normally LCD code reads a register in the display to determine when it is ready for the next command. By using long enough delays, the LCD driver can dispense with this step, save one I/O line and also keep on working when the LCD is disconnected. There are lots of web sites devoted to LCD interface techniques. Try ePanorama for a collection of links. Another place to look is http://www.eio.com, which sells surplus LCD's and has data sheets and interface information.
The schematic the connection between the CPU and the LCD. There is a small potentiometer to adjust the contrast of the display. You can tie the contrast pin (3) to ground and usually the contrast is sufficient. That is what I did on the prototype. The interface to the LCD is defined in the file lcd.inc in the source code. You need to specify the port that the data is on and whether it is high or low nibble. You also need to specify the port and bits that the control lines are assigned.
The code The code is a zip file containing source, makefile and copyright information. You need the latest AVR-GCC compiler from http://www.avrfreaks.net (GCC 3.2 experimental) to compile the code. The resulting .HEX file can be loaded into an Atmel AT90S2313 processor. By changing the processor type in the makefile you can run this code in any 8 mhz part with 15 or more I/O pins. Simple changes in the code will accommodate up to 8 inputs and outputs for an expanded pulse generator, or, if you used one of the tiny AVR parts, you could make a single or dual channel generator with an 8 pin part.
Schematic Note, the schematic needs some changes. The current choice of pins for measuring the R-C timing (PB4-7) prevents In-Circuit-Programming (ISP) and the chip has to be popped into a separate socket for programming. This is simple enough: swap the R-C timing for the R/C pulse output and make the appropriate changes to the file hardware.h.