Weather stations measure wind speed with a cup anemometer: three or four cups on arms that the wind spins round. The faster the wind, the faster it turns. In this lesson you print one, count its turns with the photo-interrupter and turn the count into km/h. You also learn about interrupts, a way for the UNO to notice very short events even when it is busy doing something else.
What you'll learn
- How to count fast pulses with an interrupt
- How to turn pulses into turns per second, and turns into a speed
- Why measuring instruments need calibrating
- How a slotted disc, called an encoder disc, measures rotation
What you need
- UNO R3 board and USB cable (UNO R3 Starter Kit)
- Photo-interrupter module (45-in-1 Sensor Kit)
- 3–6 V DC motor, used only as a bearing (UNO R3 Starter Kit)
- 3 female-to-male jumper wires
- A fan or a hair dryer on its cold setting to test with
- The printed parts from the 3D printing box below (disc, cups and mast), or the cardboard version described there
- Breadboard and jumper wires (UNO R3 Starter Kit)
Wiring

| From | To |
|---|---|
| Photo-interrupter S | UNO pin 2 |
| Photo-interrupter + | 5V |
| Photo-interrupter − | GND |
| DC motor | Not connected |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
The sensor must be on pin 2 or 3: those are the two UNO pins that can trigger an interrupt.
The sketch
const int SENSOR_PIN = 2;
const int SLOTS = 4; // windows in the rotor's disc
const float CUP_RADIUS = 0.05; // metres from the shaft to the middle of a cup
const float FACTOR = 2.5; // wind speed / cup speed; set it when you calibrate
volatile unsigned long pulses = 0;
volatile unsigned long lastPulseUs = 0;
void countPulse() {
unsigned long now = micros();
if (now - lastPulseUs > 2000) { // ignore bounces shorter than 2 ms
pulses++;
lastPulseUs = now;
}
}
void setup() {
Serial.begin(9600);
pinMode(SENSOR_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), countPulse, RISING);
Serial.println("turns/s\tkm/h");
}
void loop() {
delay(1000); // count for one second
noInterrupts(); // copy and reset the counter safely
unsigned long count = pulses;
pulses = 0;
interrupts();
float turnsPerSecond = (float)count / SLOTS;
float cupSpeed = turnsPerSecond * 2 * PI * CUP_RADIUS; // metres per second
float windKmh = cupSpeed * FACTOR * 3.6;
Serial.print(turnsPerSecond, 2);
Serial.print("\t");
Serial.println(windKmh, 1);
}
Test and calibrate
- Upload the sketch, open the Serial Monitor at 9600 baud and turn the rotor slowly by hand. Every quarter turn adds one pulse.
- Blow on the cups or hold the anemometer in front of a fan. Open Tools → Serial Plotter to see the speed as a graph.
- To calibrate, you need a known wind. On a calm day, an adult can hold the anemometer out of a car window (passenger side, never the driver) at a steady 10, 20 and 30 km/h on a quiet road. Compare the readings with the car's speed and change
FACTORuntil they match. - Real anemometers are calibrated in a wind tunnel. Without one, your readings are a good estimate, not an exact value.
How it works
An interrupt makes the UNO stop whatever it is doing the moment pin 2 goes from LOW to HIGH, run countPulse() and then carry on. That way no pulse is missed, even during delay(). Variables that an interrupt changes are marked volatile, and the main loop switches interrupts off for a moment while it copies and resets the counter, so the number can't change halfway through.
Each turn of the rotor gives 4 pulses, because the disc has 4 windows. The middle of each cup travels round a circle of 2 × π × 0.05 m = 0.31 m per turn. The wind moves faster than the cups, because the cups also catch some wind on their back side; for cup anemometers the wind is usually 2 to 3 times faster than the cups. That is the FACTOR.
Try this next
- Show the speed on the 1602 LCD, with the highest gust since you switched on.
- Convert km/h to the Beaufort scale (0 to 12) and print names like "fresh breeze".
- Move it to the ESP32 and send the wind speed to ThingSpeak, like in the cloud weather logger.
Troubleshooting
- The count doesn't change: watch the module's LED as you turn the rotor slowly. If it never changes, the disc doesn't pass through the middle of the slot; move the module.
-
Far too many pulses: the disc wobbles and touches the slot. Push the rotor straight onto the shaft, or make the 2000 in
countPulse()bigger. - It only spins in strong wind: the motor's brushes add a little friction. Spin it by hand for a minute to run it in, and keep the cups clean of strings.
- A printed part is too tight or too loose: printers differ by a few tenths of a millimetre. Sand or file a tight hole, and fix a loose part with a drop of hot glue or a strip of tape.