One of the aspects of amateur radio I enjoy is EME. When I was active on 2m (144MHz) EME I built my own elevation system using a jack-arm but I then needed a way to feedback the angle. I tried many ways in the past such as potentiometers then Sam G4DDK introduced me to the MXD2125 dual axis accelerometer device.
This can be used, along with gravity, to measure tilt, the angle vs down. Comparing both X & Y axis outputs the resolution can be very small, smaller than is required. Up until now the way I got the angle back was from one of the axis digital outputs by converting it to an analogue voltage by using an RC circuit which my elevation controller could work with, but not very well. The main problem is the analogue voltage is not pure DC and I have in the past observed inaccurate readings and sometimes it just fails to work, but this maybe wiring also. To cure this headache I set out to make the system as fully digital as possible so I decided to measure the digital pulses from both X and Y axis’s directly with the PICAXE-18M and then either convert that to a voltage with a DAC/digital pot or send it to the shack by serial and process it there by either re-designing the elevation controller to work with serial feedback or converting the serial to analogue there.
When I searched for info on this idea I came across a webpage by Frederic, F1OAT who has already used a PICAXE-08M with an MXD2125 – info about his circuit is here and at the bottom of this page here. I also came access some code which uses a PICAXE-18M to control a Maxim DS1803 digital potover I2C, which I have some samples of, so in the end my solution uses that. I built a test circuit using a PICAXE-08M and with the help of Frederics code proved I could get it all to work.
The finished project uses a MXD2125, a PICAXE-18M, and a DS1803 and provides a fully ‘digital’ means of reporting the angle by converting it to a voltage. I found at 0 degrees I get a voltage of ~0.2v and at 90 degrees ~4.3v out of the DS1803 which is about 0.045v per degree. The digital pot has a resolution of 0.0195v per bit when fed from 5v. No calibration is needed at the sensor end, only as much ‘swing’ as possible between 0 degrees and 90 degrees. As the output is linear the LVB Tracker is calibrated for 0 degree voltage and 90 degrees voltage and so knows what the angle is based on these to stored values, being digital it shouldn’t drift over time, something I think is happening with the RC circuit…
' 'The code relating to MXD2125 is 'taken from example code by F1OAT (firstname.lastname@example.org) Nov 2006. Symbol pin_x = 7 ; pin #5 <= MXD2125 X output Symbol pin_y = 0 ; pin #3 <= MXD2125 Y output ' CORDIC section variables definition Symbol x = w2 Symbol y = w3 Symbol ang = w4 Symbol ang_l = b8 Symbol ang_h = b9 Symbol dx = w5 Symbol dy = w6 Symbol i = b0 Symbol d = b1 Symbol neg = b2 Symbol tmp = b3 'The code relating to I2C or DS1803 is 'taken from example code by Peter H. Anderson, Elmore, VT, Aug, '04. ' Define IO Terminals Symbol SCL = 0 Symbol SDAIn = Pin1 Symbol SDAOut = 1 Symbol DevAdr = B0 Symbol PotNum = B1 Symbol PotSetting0 = B2 Symbol PotSetting1 = B3 ' Used in I2C Routines Symbol OByte = B4 Symbol IByte = B4 Symbol Ack = B5 Symbol N = B6 Symbol MSBit = B7 setfreq m8 ' increases the sample rate START: p_cordic: ; CORDIC section to guage the XY values (i.e. angle) x = 0 dx = 0 y = 0 dy = 0 ; Cumulate several pulses measurement to enhance accuracy for i=1 to 16 pulsin pin_x,1,ang ; high level pulse duration x = x + ang pulsin pin_x,0,ang ; low level pulse duration dx = dx + ang pulsin pin_y,1,ang ; high level pulse duration y = y + ang pulsin pin_y,0,ang ; low level pulse duration dy = dy + ang next i neg = 0 ; Put vector in proper 90° quadrant if x >= dx then qx1 x = dx - x ang = 2048 ; 180° neg = 1 - neg goto qx2 qx1: x = x - dx ang = 4096 ; 360° qx2: if y >= dy then qy1 y = dy - y neg = 1 - neg goto qy2 qy1: y = y - dy qy2: d = 1 ; CORDIC iterations for i=0 to 9 if y <= 32767 then pos y = 65535 - y neg = 1-neg pos: dx = x / d dy = y / d x = x + dy y = y - dx lookup i, (512,302,159,81,40,20,10,5,2,1), dx ; ATAN table for ang_premult=1024/90 if neg=1 then sub ang = ang + dx goto nextstep sub: ang = ang - dx nextstep: d = d*2 next i 'convert the angle to a value which can be used by the I2C routine. 'In this case it coverts it to numbers close to 0-255 for 0-90 degrees 'which makes it suitable to write this direct to the DS1803 ang = ang - 1965 ang = ang * 2 ang = ang / 10 Top: DevAdr = 0 'debug ang PotNum = 0 PotSetting0 = ang 'write angle to Pot0. 'PotSetting0 = 255 GoSub DS1803WritePot ' PotNum = 1 'Un-comment this code if you wish to use Pot1. 'PotSetting1 = 64 'Gosub DS1803WritePot 'Gosub DS1803ReadPots 'SerTxD (#PotSetting0, " ", #PotSetting1, 13, 10) 'debug PotSetting0 goto start DS1803WritePot: Branch PotNum, (WritePot0, WritePot1) WritePot0: Gosub I2CStart OByte = 2 * DevAdr + $50 Gosub I2COutByte OByte = $A9 GoSub I2COutByte OByte = PotSetting0 GoSub I2COutByte Gosub I2CStop Goto DS1803WritePotDone WritePot1: Gosub I2CStart OByte = 2 * DevAdr + $50 Gosub I2COutByte OByte = $AA GoSub I2COutByte OByte = PotSetting1 GoSub I2COutByte Gosub I2CStop Goto DS1803WritePotDone DS1803WritePotDone: Return DS1803ReadPots: Gosub I2CStart OByte = 2 * DevAdr + $51 Gosub I2COutByte Ack = 1 ' master is to ACK after receipt of byte Gosub I2CInByte PotSetting0 = IByte Ack = 0 ' no ACK as this is the last byte prior to the stop Gosub I2CInByte PotSetting1 = IByte Return I2CStart: High SDAOut High SCL Low SDAOut ' bring SDA low while SCL is high Low SCL Return I2CStop: High SCL High SDAOut ' bring SDA high while SCL is high Return I2COutByte: For N = 1 to 8 ' for eight bits MSBit = OByte / 128 ' beginning with the MSB If MSBit = 1 Then I2COutByte_1 ' most sig bit Low SDAOut GoTo I2COutByte_2 I2COutByte_1: High SDAOut I2COutByte_2: High SCL Low SCL OByte = OByte * 2 ' shift byte such that next bit is in most sig bit position Next High SDAOut ' null clock pulse to allow for slave to acknowledge High SCL Low SCL Low SDAOut Return I2CInByte: ' receives a byte, most sig byte first. ' result returned in I_BYTE High SDAOut For N=1 to 8 ' for eight bits High SCL IByte = IByte * 2 + SDAIn Low SCL Next Branch Ack, (NoAck, YesAck) NoAck: High SDAOut ' high Z on 9th clock pulse Goto I2CInByte1 YesAck: Low SDAOut ' logic zero on 9th clock pulse I2CInByte1: High SCL Low SCL Low SDAOut Return
240711 – Project posted to web.