User Tools

Site Tools


great_cow_basic:gauss_meter

Gauss Meter

gm_probe.docx image11.gif thumbs.db FIXME

I found this article: http://www.thebackshed.com/windmill/articles/GaussMeter.asp - seems to be no credit on it though - if you know different please update this article.

A Gauss Meter is something I have wanted for some time but I needed more than this circuit offered. The Field sensor is quite nice and gives a reasonably calibrated, linear output over it's magnetic range, so I decided to augment the original circuit to include a PIC and LCD to give a more precise reading and to provide two different probes (auto detected) that provide x1 and x10 ranges. NOTE: this isn't a professional unit so only use its readings as a reasonable approximation.

The UGN3503 sensor is a 5V device so best to run on a PIC at 5V which precludes a micromite (this would have made the software easier and a 28pin beastie is £5 so there is no reason not to use one if you can).

The sensor is centre-zero at ~2.5V, with South poles reading below this and North above, at 1.3mV per Gauss (or 13mV per mT) so 2.5V / 1.3mV gives a theoretical maximum of around 1900Gs although the device doesn't swing to the supply rails and you'll get a maximum of N/S 1300ish. Tests show ~1320+Gs - nice. There are two inter-changeable probes using a 4-pole 3.5mm jack plug/socket (get gold plated if you can), the x1 with the sensor mounted right at the extremity of the probe and x10 with a plastic packing piece which reduces the magnetic field by 10 (as measured on the sensor). You'll have to get this just right - with a single iron magnet (i.e. low Gauss so as not to swamp the sensor), measure it ON the sensor then move it away until the reading is ten times lower - measure that distance and that is the size for your packing piece. TIP: measure with the sensor you intend to use in each probe, i.e. use the sensor for the x10 probe for the packing piece measurement. This minimizes any tolerance error. The probes are auto-configuring - AN1 measures the voltage divider R2/R3 and a pull-up or pull-down resistor in each probe provides the intel for the processor to decide how to interpret the measurement. For the measurement, I used a plastic ruler with blue-tack to hold the setup. It makes it easy to slowly slide the magnet up and down but will hold it in place when you let go.

It is important to remember what Gauss is a measurement of. You can't simply stick a magnet on the sensor and say it is an x Gauss magnet - even a small weak magnet will swamp the sensor at 0mm and appear to be the same density as a powerful neodymium magnet. You need to measure the magnets a set distance from the sensor and apply a multiplication factor. As an example here, on a breadboard I had a prominent capacitor and a small magnet near the sensor but on top of the capacitor measured at 22.5Gs. A cube NIB in the same position came in at 394.3Gs. Both placed on the sensor gave a FSD reading, see what I mean? Read this article to get a better understanding: https://en.wikipedia.org/wiki/Gauss_(unit). I find it helps to think of the magnet as a fan. The magnetic flux is represented by the airflow. If you sit right on top of it, even a small fan appears to have a good force, but on the other side of the room, the effect is much attenuated - that is a good place to measure its force in more meaningful terms for this illustration.

The sensor should have a fairly precise packing piece inserted between it and the test subject which will reduce the sensitivity. Magnetic flux follows a rule similar to the inverse-proportion laws of light, radio energy etc. It is rough but generally acceptable and is given as 1/r3 where r is the radius (read; distance) from the subject. So basically, magnetic flux density drops off rapidly as the cube-root of the distance between the flux source (a complex subject in its own right) and the point of measurement (the sensor). Using this equation we can develop a multiplication factor so even very large magnets can be measured reliably. This will reduce the resolution still further (down to about 20Gs per bit) but increase the range substantially.

Measuring the output voltage with the PIC's ADC and converting to Gauss is fairly straight forward. The code uses fixed point maths with everything multiplied by 1E+6 to preserve precision and simply formatted right at the output. The ADC is only 10 bits wide so the 5V/1024 means I can only measure to a resolution of 4.88mV. This is way above the 1.3mV of the sensor but is probably good enough for hobby use. A 12bit ADC would get me to 1.22mV which is nice but small (read: inexpensive) PICs don't have 12 bit ADCs :o(

The code compiles to ~1.5K so you do need a PIC with that at least 2K of flash (so the 16F818 won't do).

Main Unit schematic:

Probes schematic:

The unit boots to a greeting for two seconds to allow everything to stabilise then auto-calibrates itself to find the centre-point of the sensor. During this time, keep the probe well away from magnetic fields. This is used as a reference point for all further measurements. If you think it isn't calibrated right (hint: check the number top right - mine always seems to be around 524 - ideal would be 512), check for possible magnetic contaminants near the probe (tools, CRTs etc.) and press SW2 to jump to the calibrate routine. You can omit SW2 and R6 and just power cycle the whole unit but I wanted to avoid the delay at start up - it's pennies.

Here it is lashed up on the breadboard (ignore the stuff to the right) - you can see the reference and present reading on the right hand side of the display. It illustrates that with a 10bit ADC (actually 9bit because readings can be either side of the centre for FSD) gives us a resolution of 3.7Gs. The display also shows milliTesla which is Gs/10 but I round up or down to make it more meaningful so 7.5Gs is 0.8mT)

gmbb.jpg

Code:

' Gauss meter, based on this article:
' http://www.thebackshed.com/windmill/articles/GaussMeter.asp
'
' Controller code uses 16F819 (wanted to use up stock of 16F628 but it doesn't have a proper ADC)
'
' Single push button applies power to the device. Keep the wand away from magnetic sources during boot.
' It measures the output of the UGN3503 which is centered around 2.5V and this measurement is our reference
' (It should be about 1/2 FSD of the ADC). Volts on the ADC is (5/1024) = 4.882mV per bit. This is quite course
' and gives a resolution worse than 3Gs. An ADC with 12 bit resolution would get us to 1.22mV per bit which is
' close to the UGN3503 of 1.3mV/Gs.
'
' So need a small PIC with 12bit ADC for a better Gauss meter. If you use a different device, change the #CHIP line
' to suit and set #define ADCBits= to the number of bit on its ADC, Everything else will drop into place.
'
' It's auto-calibrating - The midway point on the sensor may not be exact but we measure it as a reference.
' On the UGN3503, 0Gs is ~2.5v, below that is South, above North. We measure with the ADC during boot and subtract
' the reference if the reading is above 1/2FSD or subtract it from the reference if it's below to give an absolute
' value for North/South (and we set a flag). Then convert to true volts - all voltages are  multiplied by 1e6 to
' maintain accuracy in a LONG. Divide this by 1300 (0.0013*1e6) to get Gauss reading. Actually we divide by 130 to
' get a single decimal. Perfect (but unlikely) range is thus (5/0.0013)/2 = N/S 1923.0Gs or 192mT with a 0.66mm
' packing piece between the direct-contact surfaces of the sensor and the magnet.
'
'*************************************************************
; ----- Configuration
  #chip 16F819, 4

  #config osc=int
  #config wdt=off

  ' #include
  ' no solution specifc includes, default includes are always included                                  ; no solution specifc includes, default includes are always included


; ----- Define Hardware settings
  ' this is required to tell the microprocessor the port is an output


    ' Have to use fixed point maths so multiply everything
    ' by 1e6 to maintain accuracy


    '#DEFINE mVPG=130           ' mV per Gauss = 0.0013 * 1e6  /10 gives xxxx.x

    ' Use LCD in 4 pin mode and define LCD pins
    #DEFINE LCD_IO     4
    #DEFINE LCD_SPEED  MEDIUM  'FAST, MEDIUM or SLOW.
    #DEFINE LCD_RW     PORTB.1
    #DEFINE LCD_Enable PORTB.2
    #DEFINE LCD_RS     PORTB.3
    #DEFINE LCD_DB4    PORTB.4
    #DEFINE LCD_DB5    PORTB.5
    #DEFINE LCD_DB6    PORTB.6
    #DEFINE LCD_DB7    PORTB.7

    ' Here are various LCD commands which can be used.
    ' These are the LCD commands for the HD44780 controller
    #DEFINE clrHome = 1     ;clear the display, home the cursor
    #DEFINE home    = 2     ;home the cursor only
    #DEFINE RtoL    = 4     ;print characters right to left
    #DEFINE insR    = 5     ;insert characters to right
    #DEFINE LtoR    = 6     ;print characters left to right
    #DEFINE insL    = 7     ;insert characters to left
    #DEFINE lcdOff  = 8     ;LCD screen off
    #DEFINE lcdOn   = 12    ;LCD screen on, no cursor
    #DEFINE curOff  = 12    ;an alias for the above
    #DEFINE block   = 13    ;LCD screen on, block cursor
    #DEFINE under   = 14    ;LCD screen on, underline cursor
    #DEFINE undblk  = 15    ;LCD screen on, blinking and underline cursor
    #DEFINE CLeft   = 16    ;cursor left
    #DEFINE CRight  = 20    ;cursor right
    #DEFINE panR    = 24    ;pan viewing window right
    #DEFINE panL    = 28    ;pan viewing window left
    #DEFINE bus4    = 32    ;4-bit data bus mode
    #DEFINE bus8    = 48    ;8-bit data bus mode
    #DEFINE mode1   = 32    ;one-line mode (alias)
    #DEFINE mode2   = 40    ;two-line mode
    #DEFINE line1   = 128   ;go to start of line 1
    #DEFINE line2   = 192   ;go to start of line 2

Start:

    DIM xx      AS LONG
    dim yy      AS LONG
    dim zz      AS LONG
    DIM ref     AS LONG
    DIM nn      AS BYTE
    DIM mm      AS INTEGER
    DIM LN      AS STRING * 5
    DIM tLN     AS STRING * 5
    DIM NS      AS BIT
    DIM decimal AS BIT
    DIM fg      AS BIT
    DIM xc      AS BYTE

    DIR PortA.0 IN
    DIR PortA.1 IN
    DIR PortA.7 IN

    LCDCMD(mode2)
    LCDCMD(lcdOn)
    LCDCMD(clrHome)
    PRINT " LogiTEL (C)2017"' need a space after a clrhome... dunno why
    LCDCMD(line2)
    PRINT "Magnetometer 2.0"
    PAUSE 2000

Calibrate:
    ' Calibrate. Run thru on power up and jump here on pushbutton
    LCDCMD(clrHome)
    PRINT " Calibrating..."

    repeat 10
      ref=READAD10(AN0) ' use the ADC a few times just to settle it
    end repeat

    xx=0

    FOR nn=1 TO 100     ' average of 100 readings
        LCDCMD(line2)
        PRINT STR(nn)
        print "%"
        PAUSE 10
        xx=xx+READAD10(AN0)
    NEXT

    ref=xx/100

    LCDCMD(clrHome)

Main:

    repeat 25           ' wait for 25x10mS rather than 250mS in one lump to make the calibrate
                        ' button a bit more responsive - same ting. Doesn't need debonce coz
                        ' calibration takes about 1sec
      if PORTA.7=0 then goto Calibrate' calibrate pushbutton - pull-up through 10K
      pause 10
    end repeat


    LCDCMD(line1)        ' coz of clrhome

    zz=READAD10(AN1)
    select case zz      ' work out which probe we are using
      case <250         ' ~0V is the x1 probe
        decimal=1
      case >750         ' ~5V is the x10 probe
        decimal=0
      case else
        print "Check Probe"
        LCDCMD(line2)
        print zz
        print "  "
        goto Main
    end select

    zz=0
    REPEAT 1024         ' average loads of readings
        zz=zz+READAD10(AN0)
    END REPEAT
    xx=zz/1024
    zz=xx

    IF xx<ref THEN      ' normalise the bits to an absolute reading of north or south
        xx=ref-xx:NS=0  ' south
    ELSE
        xx=xx-ref:NS=1
    END IF

    xx=(xx*4882)/130

    yy=xx

    FmtLN(yy,5)

    PRINT " Gs "

    IF NS=0 THEN
      PRINT "S "
    ELSE
      PRINT "N "
    end if

    print ref
    print "  "

    '1mT=10Gs
    LCDCMD(line2)

    FmtLN((yy+5)/10,5)  ' round for mT

    PRINT " mT   "

    print zz

    print "  "

    goto Main



    Sub FmtLN(vv as long, fl as byte)
      fg=0
      LN=STR(vv)
      DO WHILE LEN(LN)<fl ' pad with leading zeroes for fixed width so we get xxx0.0 format
          tLN="0"+LN
          LN=tLN
      LOOP
      for nn=1 to fl
        if decimal=1 then
          if nn=fl then
            print "."
          end if
        end if

        xc=asc(LN,nn)
        if xc<>48 then fg=1
        if nn=fl then fg=1
        if decimal=1 then
          if nn=(fl-1) then fg=1
        end if

        if fg=1 then
          print chr(xc)
        else
          print " "
        end if

      next
    end sub

Two files attached top right are the PCB foils for the probes

great_cow_basic/gauss_meter.txt · Last modified: 2024/01/20 22:36 by gerry