PICAXE-18M & MXD2125 Based Elevation Module

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.

Elevation_PCB_Bottom_Arrow  Elevation_PCB_Top

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 (frible@teaser.fr) 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


	; 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
	x = x - dx
	ang = 4096	; 360°
	if y >= dy then qy1
	y = dy - y
	neg = 1 - neg
	goto qy2
	y = y - dy

	d = 1

	; CORDIC iterations

	for i=0 to 9
		if y <= 32767 then pos
		y = 65535 - y
		neg = 1-neg
		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
		ang = ang - dx 

		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

   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

    Branch PotNum, (WritePot0, WritePot1)

    Gosub I2CStart

    OByte = 2 * DevAdr + $50
    Gosub I2COutByte

    OByte = $A9
    GoSub I2COutByte

    OByte = PotSetting0
    GoSub I2COutByte

    Gosub I2CStop

    Goto DS1803WritePotDone

    Gosub I2CStart

    OByte = 2 * DevAdr + $50
    Gosub I2COutByte

    OByte = $AA
    GoSub I2COutByte

    OByte = PotSetting1
    GoSub I2COutByte

    Gosub I2CStop

    Goto DS1803WritePotDone




    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


    High SDAOut
    High SCL
    Low SDAOut			' bring SDA low while SCL is high
    Low SCL

    High SCL
    High SDAOut         ' bring SDA high while SCL is high


    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
       High SDAOut
       High SCL
       Low SCL
       OByte = OByte * 2	' shift byte such that next bit is in most sig bit position
    High SDAOut 			' null clock pulse to allow for slave to acknowledge
    High SCL
    Low SCL
    Low SDAOut

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
    Branch Ack, (NoAck, YesAck)

     High SDAOut             ' high Z on 9th clock pulse
     Goto I2CInByte1

     Low SDAOut              ' logic zero on 9th clock pulse
     High SCL
     Low SCL

     Low SDAOut



MXD2125_Elevation_Mounted MXD2125_Elevation_Mounting_Info

MXD2125_Elevation_Boxed MXD2125_Elevation_Closed

Elevation_PCB_Bottom Elevation_PCB_Top_(Boxed)



240711 – Project posted to web.


  1. Bill

    Hello Gavin,

    I am very interested in your Elevation PICAXE design using the MXD2125 Chip. The only problem I have is the software is in a format where when I cut and paste it, I just end up with a block of code which is very difficult to evaluate. I have even tried pasting it into Notepad and Notepad+ but still end up with unreadable code.

    When you get time, could you email me the code with the proper lines etc in it.

    73, Bill

  2. Paul Tomlinson

    Could this be used to drive a LCD display?

  3. EA7UU - Jesus


    Do you have RFI problems with this device when you transmit?… I think (I may be wrong) when this acelerometer is exposed to RF camps their measurements will be incorrect.

    Thank you.

    1. m1bxf (Post author)

      Hello Jesus,

      I never seen any issue with the reading on this with RF fields nearby. The digital lines between the MXD2125 and the PICAXE-18M chip are very short also.




Leave a Reply

%d bloggers like this: