Numbers on a screen are precise, but a needle on a dial can be read from across the room. Old cars, kitchen thermometers and barometers all use one. In this lesson the DHT11 measures the temperature, and the servo turns a needle to the matching place on a scale from 0 to 40 °C. The needle moves smoothly, just like a real instrument.
What you'll learn
- How to turn a measurement into an angle with a formula
- How to move a servo smoothly, one degree at a time
- How to make the scale of a dial match the code
- How to keep a value inside a range with
constrain()
What you need
- UNO R3 board and USB cable (UNO R3 Starter Kit)
- DHT11 temperature and humidity sensor (UNO R3 Starter Kit)
- Servo motor (UNO R3 Starter Kit)
- A piece of card, a straw or toothpick for the needle, and tape
- Breadboard and jumper wires (UNO R3 Starter Kit)
Make it real: draw a half circle on card with 0 °C on the left, 20 °C at the top and 40 °C on the right, with marks every 5 °C. Push the servo shaft through the middle and tape a straw to the servo horn as the needle.
Wiring

| From | To |
|---|---|
| DHT11 S (signal) | UNO pin 7 |
| DHT11 + and − | 5V and GND |
| Servo orange / yellow wire | UNO pin 9 |
| Servo red wire | 5V |
| Servo brown / black wire | GND |
The sketch
Install the DHT sensor library by Adafruit (and Adafruit Unified Sensor when asked). The Servo library is built in.
#include <Servo.h>
#include <DHT.h>
DHT dht(7, DHT11);
Servo needle;
const float LOWEST = 0.0; // temperature at the left end of the scale
const float HIGHEST = 40.0; // temperature at the right end of the scale
int needleAngle = 90;
int angleFor(float celsius) {
float t = constrain(celsius, LOWEST, HIGHEST);
// cold = 180 degrees (left), hot = 0 degrees (right)
return 180 - (int)((t - LOWEST) * 180.0 / (HIGHEST - LOWEST));
}
void moveNeedle(int target) {
while (needleAngle != target) {
needleAngle += (target > needleAngle) ? 1 : -1;
needle.write(needleAngle);
delay(15); // one degree every 15 ms: smooth like a gauge
}
}
void setup() {
Serial.begin(9600);
dht.begin();
needle.attach(9);
needle.write(needleAngle);
}
void loop() {
delay(2000); // the DHT11 needs 2 s between readings
float celsius = dht.readTemperature();
if (isnan(celsius)) {
Serial.println("Sensor error");
return;
}
int angle = angleFor(celsius);
Serial.print(celsius, 1);
Serial.print(" °C -> needle at ");
Serial.print(angle);
Serial.println(" degrees");
moveNeedle(angle);
}
Line up the dial
- Upload the sketch. While it waits for the first reading, the servo goes to 90 degrees.
- Take the horn off, and push it back on with the needle pointing straight up at 20 °C.
- Warm the DHT11 between your fingers and check that the needle moves to the right. If it moves left, see Troubleshooting.
How it works
The dial covers 40 degrees Celsius on a half circle of 180 degrees, so each degree Celsius is 4.5 degrees of needle movement. angleFor() does that sum, and constrain() keeps the needle on the scale when it is colder than 0 or warmer than 40 °C. Because a servo's 0° is usually on the right when you look at it from the front, the result is reversed with 180 - … so that cold is on the left, as on most gauges.
servo.write() on its own makes the servo jump at full speed. moveNeedle() moves it one degree at a time instead, which looks like a real instrument and is gentler on the servo's gears.
Try this next
- Change the scale to −10 … 30 °C for an outdoor thermometer, and redraw the dial.
- Add a second dial for humidity from 0 to 100 %.
- Light a red LED when the needle is in a "too warm" zone that you colour on the dial.
Troubleshooting
-
The needle moves the wrong way: remove
180 -from the return line, so it readsreturn (int)(…);. - "Sensor error": check the DHT11 signal wire on pin 7 and its power pins.
- The servo buzzes at the end of the scale: it is pushing against its stop. Use 10 to 170 degrees instead of 0 to 180.
- The board restarts when the servo moves: servos draw bursts of current. Use a good USB port or a powered hub, and check that the servo's red wire is on 5V.