Built-in project · Arduino Uno R3

Pocket gaussmeter on an Arduino Uno

A 49E linear Hall sensor on A0 and a 16x2 I2C LCD: the field in gauss, which pole it is, and the strongest seen since power on. The whole build, an Arduino Uno and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Beginner About 15 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $34. On Mokxi they're free.

Step by step, with the wiring and the common mistakes: Arduino Hall Effect Sensor (49E): Wiring and Code

The circuit runs here once the page has loaded.

What you'll learn

  • How a linear Hall sensor turns magnetic field into voltage
  • Zeroing a sensor at startup
  • Averaging readings to steady a signal
  • Integer math instead of floating point
  • Showing results on an I2C LCD
  • Difficulty: Beginner
  • Time: About 15 minutes
  • Board: Arduino Uno R3
  • Parts: 4

How it works

A 49E linear Hall sensor puts out half the 5 V supply when there is no magnet near. A south pole at its printed face pushes the voltage up, a north pole pushes it down, by 1.4 mV per gauss. The Uno reads it on A0.

At power on the meter zeroes itself by averaging 64 readings, so a sensor that does not rest at exactly 2.5 V still reads zero. After that it averages 8 readings every 250 ms. A 16x2 I2C LCD shows the size in gauss, the pole (SOUTH or NORTH) and the biggest value so far. Below 5 G it says no field. Near the range ends it shows over range.

Parts list

4 parts, plus the jumper wires. They retail for about $34; on Mokxi they're free.

Kits that can build it

This starter kit has every part in the circuit. Each kit's page lists what else it can build.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Hall sensor, 49E linear pin VCCArduino Uno R3 pin 5V
Character LCD with I2C backpack pin VCCArduino Uno R3 pin 5V
Hall sensor, 49E linear pin GNDArduino Uno R3 pin GND
Character LCD with I2C backpack pin GNDArduino Uno R3 pin GND
Hall sensor, 49E linear pin OUTArduino Uno R3 pin A0
Character LCD with I2C backpack pin SDAArduino Uno R3 pin A4
Character LCD with I2C backpack pin SCLArduino Uno R3 pin A5

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Pocket gaussmeter: a 49E linear Hall sensor on A0, and the field on a 16x2
// I2C LCD.
//
//   A0      the 49E's OUT (its VCC on 5 V, GND on GND, printed face out)
//   LCD     SDA -> A4    SCL -> A5    VCC -> 5 V    GND -> GND
//
// The 49E puts out half its supply with no field, and moves 1.4 mV a gauss:
// up for a south pole at its printed face, down for a north pole. So
//
//   gauss = (mV - zero mV) / 1.4
//
// One ADC count on 5 V is 4.89 mV, about 3.5 G: that is the meter's
// resolution. Its range ends where the output does, 0.95 V from either rail,
// about 1100 G each way; a neodymium magnet held against the face reads
// "over".
//
// # Zeroing
//
// The null is 2.50 V typical, but anything from 2.25 to 2.75 V on the sheet.
// So the meter zeroes itself at power on, with no magnet near, from the
// average of 64 readings, as a real one does when you press its zero button.
//
// Everything is whole numbers: this board has no floating point to spare.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

const int HALL = A0;
// mV per count x 1000, on 5 V: 5000 / 1023.
const long UV_PER_COUNT = 4888;
// Sensitivity in microvolts per gauss.
const long UV_PER_GAUSS = 1400;
// Where the output stops: 0.95 V from either rail, as counts.
const int LOW_END = 195;
const int HIGH_END = 828;

LiquidCrystal_I2C lcd(0x27, 16, 2);
long zero4 = 0;  // the null, in quarter counts
long peak = 0;

long readQuarters(int n) {
  long sum = 0;
  for (int i = 0; i < n; i++) sum += analogRead(HALL);
  return sum * 4 / n;
}

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: pocket gaussmeter");
  lcd.init();
  lcd.backlight();
  lcd.print("Zeroing...");
  zero4 = readQuarters(64);
  Serial.print("zero at count ");
  Serial.println(zero4 / 4);
  lcd.clear();
}

void loop() {
  long raw4 = readQuarters(8);
  int raw = (int)(raw4 / 4);
  bool over = raw <= LOW_END || raw >= HIGH_END;
  long gauss = (raw4 - zero4) * UV_PER_COUNT / 4 / UV_PER_GAUSS;
  long size = gauss < 0 ? -gauss : gauss;
  if (size > peak) peak = size;

  lcd.setCursor(0, 0);
  if (over) {
    lcd.print("over range      ");
  } else {
    lcd.print(size);
    lcd.print(" G ");
    if (size < 5) {
      lcd.print("no field    ");
    } else {
      lcd.print(gauss > 0 ? "SOUTH       " : "NORTH       ");
    }
  }
  lcd.setCursor(0, 1);
  lcd.print("peak ");
  lcd.print(peak);
  lcd.print(" G        ");

  Serial.print("field ");
  Serial.print(gauss);
  Serial.println(over ? " G (over)" : " G");
  delay(250);
}

Code walkthrough

The key functions of the sketch, and what each one does.

readQuarters sketch.ino

Adds up n readings from the sensor and returns the average multiplied by 4. Keeping the answer in quarter counts gives finer steps than whole counts without using floating point.

long readQuarters(int n) {
  long sum = 0;
  for (int i = 0; i < n; i++) sum += analogRead(HALL);
  return sum * 4 / n;
}

setup sketch.ino

Starts serial and the LCD, shows Zeroing, and stores the average of 64 readings in zero4. Keep magnets away until it finishes, because that reading becomes the zero point.

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: pocket gaussmeter");
  lcd.init();
  lcd.backlight();
  lcd.print("Zeroing...");
  zero4 = readQuarters(64);
  Serial.print("zero at count ");
  Serial.println(zero4 / 4);
  lcd.clear();
}

loop sketch.ino

Takes a fresh 8-sample reading and checks if the raw count is at or beyond LOW_END or HIGH_END. Otherwise it subtracts the zero, scales by microvolts per count and per gauss, and keeps the absolute size and the running peak. The sign picks SOUTH or NORTH. It prints to the LCD and serial, then waits 250 ms.

void loop() {
  long raw4 = readQuarters(8);
  int raw = (int)(raw4 / 4);
  bool over = raw <= LOW_END || raw >= HIGH_END;
  long gauss = (raw4 - zero4) * UV_PER_COUNT / 4 / UV_PER_GAUSS;
  long size = gauss < 0 ? -gauss : gauss;
  if (size > peak) peak = size;

  lcd.setCursor(0, 0);
  if (over) {
    lcd.print("over range      ");
  } else {
    lcd.print(size);
    lcd.print(" G ");
    if (size < 5) {
      lcd.print("no field    ");
    } else {
      lcd.print(gauss > 0 ? "SOUTH       " : "NORTH       ");
    }
  }
  lcd.setCursor(0, 1);
  lcd.print("peak ");
  lcd.print(peak);
  lcd.print(" G        ");

  Serial.print("field ");
  Serial.print(gauss);
  Serial.println(over ? " G (over)" : " G");
  // ... 2 more lines in the editor

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The meter shows a field with no magnet near. This project
    A magnet was close during the Zeroing step. Move magnets away and restart so it zeroes on a quiet field.
  • Nothing appears on the LCD. This project
    Check SDA goes to A4 and SCL to A5, and that the sketch uses address 0x27.
  • SOUTH and NORTH look backwards. This project
    The sensor must face out. A south pole at its printed face reads as SOUTH.
  • The reading never changes or sits at a strange value with no magnet. Hall sensor
    With no field the output rests near half the supply, about 2.5 V at 5 V. Read the change from that rest value, not from zero. Check pin order: VCC, GND, output.
  • The output is weak or looks wrong when a magnet is close. Hall sensor
    Pole matters. A south pole facing the marked side raises the output and a north pole lowers it. The part saturates near the rails, so keep the magnet at a distance that stays within range.
  • The screen stays blank or shows only a row of blocks. Character LCD with I2C backpack
    The I2C address is usually 0x27 or 0x3F. Run an I2C scanner to find yours. Then turn the contrast trimmer on the backpack slowly until text appears.
  • The backlight is on but there is no text, or text is garbled. Character LCD with I2C backpack
    Wire SDA and SCL to the right pins (A4 and A5 on an Uno), power it from 5 V, and call lcd.init() and the backlight call in setup.
  • Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
    Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.