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.
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.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Temperature sensor, LM35
- 1 × Hall sensor, A3144
- 1 × Photo interrupter, slot
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 pin | Connects to |
|---|---|
| Photo interrupter, slot pin GND | Arduino Uno R3 pin GND |
| Photo interrupter, slot pin SIG | Arduino Uno R3 pin 3 |
| Hall sensor, A3144 pin OUT | Arduino Uno R3 pin 2 |
| Hall sensor, A3144 pin VCC | Arduino Uno R3 pin IOREF |
| Photo interrupter, slot pin VCC | Arduino Uno R3 pin 3V3 |
| Temperature sensor, LM35 pin VS | Arduino Uno R3 pin 5V |
| Temperature sensor, LM35 pin GND | Arduino Uno R3 pin GND |
| Hall sensor, A3144 pin GND | Arduino Uno R3 pin GND |
| Temperature sensor, LM35 pin VOUT | Arduino 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.
// 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.