Built-in project · Arduino Uno R3

Heat, magnet and wheel, on an Arduino Uno

An LM35 on A0, an A3144 Hall switch on pin 2 and a slotted photo interrupter counting a 20-slot wheel on pin 3, read on the serial monitor. The whole build, an Arduino Uno and 3 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 20 minutes to build and run. Runs in your browser. Free, and no account needed.

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

The circuit runs here once the page has loaded.

What you'll learn

  • Analog temperature sensing with the LM35
  • Open-collector outputs and INPUT_PULLUP
  • Counting pulses with attachInterrupt
  • Turning pulses per second into RPM
  • Integer math instead of floating point
  • Difficulty: Beginner
  • Time: About 20 minutes
  • Board: Arduino Uno R3
  • Parts: 4

How it works

Three sensors, three ways to read them. The LM35 gives a voltage that rises 10 mV per degree. The A3144 Hall sensor pulls its pin LOW when a magnet is near. The slot sensor makes a pulse each time a wheel slot passes.

Once a second the sketch prints the temperature, whether a magnet is present, and the wheel speed in RPM. The wheel has 20 slots, so RPM is pulses counted in a second times 3.

The Uno's built-in LED on pin 13 lights while the magnet is detected. Wheel pulses are counted by an interrupt so none are missed between prints.

Parts list

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

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
Photo interrupter, slot pin GNDArduino Uno R3 pin GND
Photo interrupter, slot pin SIGArduino Uno R3 pin 3
Hall sensor, A3144 pin OUTArduino Uno R3 pin 2
Hall sensor, A3144 pin VCCArduino Uno R3 pin IOREF
Photo interrupter, slot pin VCCArduino Uno R3 pin 3V3
Temperature sensor, LM35 pin VSArduino Uno R3 pin 5V
Temperature sensor, LM35 pin GNDArduino Uno R3 pin GND
Hall sensor, A3144 pin GNDArduino Uno R3 pin GND
Temperature sensor, LM35 pin VOUTArduino Uno R3 pin A0

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
// Heat, magnet and wheel: three kit sensors that each read a different way.
//
//   A0     the LM35's middle leg; its outer legs go to 5V and GND
//   pin 2  the A3144's OUT, with the Uno's own pull-up (INPUT_PULLUP); the
//          sensor runs from IOREF, which is 5 V on an Uno
//   pin 3  the photo interrupter's S, counted by interrupt; the board runs
//          from 3V3, and its 3.3 V high is still a HIGH to a 5 V Uno
//   pin 13 the built-in LED, lit while the magnet is there
//
// # The LM35: a voltage
//
// Ten millivolts a degree from 0 V at 0 C, with no offset. The ADC gives
// 0 to 1023 against 5 V, so millivolts = reading x 5000 / 1024, which is
// exactly reading x 625 / 128, and one millivolt is a tenth of a degree. No
// floating point anywhere. An LM35 needs 4 V or more, which is why it is on
// 5 V here and why a 3.3 V board wants a TMP36 instead.
//
// # The A3144: an open collector
//
// It only ever pulls OUT down, so the pin needs a pull-up and reads LOW while
// a south pole is near its printed face. Turn the magnet round and nothing
// happens: it is unipolar.
//
// # The photo interrupter: pulses
//
// S goes HIGH each time a spoke of the wheel cuts the beam. Counting rising
// edges for a second gives slots a second, and the disc has 20 slots, so
// RPM = pulses x 60 / 20 = pulses x 3.

const int LM35_PIN = A0;
const int HALL_PIN = 2;
const int SLOT_PIN = 3;
const int LAMP = 13;
const int SLOTS = 20;

volatile unsigned int pulses = 0;

void countSlot() {
  pulses++;
}

/** Sixteen conversions, averaged, as tenths of a degree. */
int readTenths() {
  unsigned int total = 0;
  for (int i = 0; i < 16; i++) {
    total += (unsigned int)analogRead(LM35_PIN);
  }
  long mean = total >> 4;
  return (int)(mean * 625 / 128);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Mokxi Arduino Uno: LM35, A3144 and a slotted wheel");
  pinMode(HALL_PIN, INPUT_PULLUP);
  pinMode(SLOT_PIN, INPUT);
  pinMode(LAMP, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(SLOT_PIN), countSlot, RISING);
}

void loop() {
  static unsigned long last = 0;
  bool magnet = digitalRead(HALL_PIN) == LOW;
  digitalWrite(LAMP, magnet ? HIGH : LOW);

  if (millis() - last >= 1000) {
    last += 1000;
    noInterrupts();
    unsigned int counted = pulses;
    pulses = 0;
    interrupts();

    int tenths = readTenths();
    Serial.print("temperature ");
    Serial.print(tenths / 10);
    Serial.print(".");
    Serial.print(tenths % 10);
    Serial.print(" C   magnet ");
    Serial.print(magnet ? "yes" : "no ");
    Serial.print("   wheel ");
    Serial.print((long)counted * 60 / SLOTS);
    Serial.println(" RPM");
  }
}

Code walkthrough

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

countSlot sketch.ino

Runs every time pin 3 rises. It adds one to pulses. Because an interrupt changes it, the variable is declared volatile, so the main loop always sees the latest value.

void countSlot() {
  pulses++;
}

readTenths sketch.ino

Takes 16 readings from A0 and averages them by shifting right 4 bits. It then multiplies by 625 / 128, which turns counts into millivolts. With 10 mV per degree, millivolts equals tenths of a degree.

/** Sixteen conversions, averaged, as tenths of a degree. */
int readTenths() {
  unsigned int total = 0;
  for (int i = 0; i < 16; i++) {
    total += (unsigned int)analogRead(LM35_PIN);
  }
  long mean = total >> 4;
  return (int)(mean * 625 / 128);
}

loop sketch.ino

Reads the Hall pin and lights the pin 13 LED when it is LOW. Every second it copies and resets pulses with interrupts off. Then it prints temperature, magnet yes or no, and RPM as pulses times 60 divided by SLOTS.

void loop() {
  static unsigned long last = 0;
  bool magnet = digitalRead(HALL_PIN) == LOW;
  digitalWrite(LAMP, magnet ? HIGH : LOW);

  if (millis() - last >= 1000) {
    last += 1000;
    noInterrupts();
    unsigned int counted = pulses;
    pulses = 0;
    interrupts();

    int tenths = readTenths();
    Serial.print("temperature ");
    Serial.print(tenths / 10);
    Serial.print(".");
    Serial.print(tenths % 10);
    Serial.print(" C   magnet ");
    Serial.print(magnet ? "yes" : "no ");
    Serial.print("   wheel ");
    Serial.print((long)counted * 60 / SLOTS);
    Serial.println(" RPM");
  }
}

Troubleshooting

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

  • The magnet is never detected This project
    The A3144 only reacts to one magnetic pole facing its printed side. Turn the magnet around.
  • The RPM stays at 0 This project
    Check that the slot sensor's signal goes to pin 3. Only pins 2 and 3 can use interrupts on an Uno.
  • The temperature looks off This project
    The LM35 needs 5V. Its middle pin goes to A0, and the outer pins go to 5V and ground.
  • Readings are about 0 V or make no sense on a 3.3 V board. Temperature sensor
    The LM35 needs at least 4 V supply to work. Use a 5 V supply, or choose another sensor like the TMP36 for 3.3 V boards.
  • The temperature is noisy or jumps around. Temperature sensor
    It outputs 10 mV per degree C. Use the matching ADC reference, average several readings, and add a 0.1 uF capacitor near the output.
  • OUT never changes, or floats. Hall sensor
    The A3144 has an open-collector output. Add a pull-up of about 10 k ohms from OUT to VCC. VCC may be 4.5 V to 24 V. The output goes LOW near a magnet.
  • The sensor ignores the magnet. Hall sensor
    Bring the south pole to the marked face of the sensor. A north pole does nothing. If it still fails, flip the magnet or the sensor.
  • The output never changes, or is always the same. The LED side needs a series resistor, and the phototransistor side needs a pull-up. Photo interrupter
    Put about 220 ohms in series with the LED from 5 V. Pull the output up with about 10k, or use INPUT_PULLUP. Output goes low when the beam is clear and high when blocked, or the reverse on some modules.

Change it and keep it

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