Arduino Development
Senior 6 · ICT
Arduino Development
Lesson 3 of 5
25 min
A school gate opens itself when a car is close; a classroom fan starts when the room gets hot; the lights of a corridor come on when it gets dark and someone walks by. Each of these needs the Arduino to measure something. Sensors come in two families. Digital sensors give the board a HIGH or LOW signal, or a timed pulse; analog sensors give a voltage that varies smoothly, which the board converts into a number. This lesson wires and programs one of each kind of sensor you are most likely to meet.
Definition
Digital sensor: a sensor whose output is HIGH or LOW, or a pulse whose timing carries the measurement. Examples: a PIR motion sensor; an HC-SR04 ultrasonic distance sensor.
Analog sensor: a sensor whose output voltage varies continuously with the quantity measured. Examples: a light-dependent resistor (LDR) in a voltage divider; an LM35 temperature sensor.
Analog-to-digital converter (ADC): the circuit that turns a voltage into a number. The Uno's ADC is 10-bit: analogRead() returns 0 for 0 V up to 1023 for 5 V.
A passive infrared (PIR) sensor such as the HC-SR501 notices the change in infrared radiation when a warm body moves. It has three pins: VCC (to 5 V), GND, and OUT, which goes HIGH (about 3.3 V, enough for the Uno to read as HIGH) for a few seconds after motion. Reading it is the same as reading a button, without the pull-up: pinMode(2, INPUT); then digitalRead(2) == HIGH means "motion". Two small knobs on the module set the sensitivity and how long OUT stays HIGH.
The HC-SR04 sends a burst of ultrasound when its Trig pin receives a 10 µs pulse, then holds its Echo pin HIGH until the echo returns. The sketch measures that time with pulseIn(). Sound travels at about 343 m/s in air at 20 °C, which is per microsecond, and it travels to the object and back, so
with in microseconds and in centimetres.
// HC-SR04: measure distance and report it; warn when closer than 20 cm
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
const int LED_PIN = 8;
void setup() {
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
}
float readDistanceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH); // a 10 microsecond pulse starts a measurement
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
unsigned long us = pulseIn(ECHO_PIN, HIGH, 30000UL); // echo time, give up after 30 ms
if (us == 0) return -1; // no echo: nothing in range
return us * 0.0343 / 2; // sound: 0.0343 cm per microsecond, there and back
}
void loop() {
float cm = readDistanceCm();
if (cm < 0) {
Serial.println("Out of range");
} else {
Serial.print("Distance: ");
Serial.print(cm, 1);
Serial.println(" cm");
}
digitalWrite(LED_PIN, (cm > 0 && cm < 20) ? HIGH : LOW);
delay(200);
}
The red LED from the last lesson, still on pin 8, lights when something is closer than 20 cm. The third argument of pulseIn is a time-out: without it, a missing echo would freeze the sketch for a whole second.
Worked example 1: from echo time to distance
pulseIn returns 1166 µs. How far away is the object?
The LED is on when , so at 20.0 cm it is just off. In a hot room (30 °C) sound is a little faster, about 349 m/s, so the true distance is about 1.7% more; for a parking sensor that does not matter, but for a measuring instrument it would.
An analog pin returns a number from 0 to 1023. Each step is
so a reading corresponds to the voltage .
Light (LDR). An LDR's resistance falls as light increases: very roughly 1 kΩ in bright light and 100 kΩ or more in darkness. The board cannot measure resistance directly, so the LDR is put in a voltage divider with a fixed 10 kΩ resistor, and the board measures the voltage at the junction:
Temperature (LM35). The LM35 outputs 10 mV for every degree Celsius, so with in volts.
// Read an LDR divider on A0 and an LM35 on A1; print raw values and units
const int LDR_PIN = A0;
const int LM35_PIN = A1;
void setup() {
Serial.begin(9600);
}
void loop() {
int light = analogRead(LDR_PIN); // 0 to 1023
int raw = analogRead(LM35_PIN);
float volts = raw * 5.0 / 1023.0; // reading -> voltage
float celsius = volts * 100.0; // LM35: 10 mV per degree
int lightPercent = map(light, 0, 1023, 0, 100);
Serial.print("Light: ");
Serial.print(lightPercent);
Serial.print(" % Temperature: ");
Serial.print(celsius, 1);
Serial.println(" C");
delay(1000);
}
map(light, 0, 1023, 0, 100) rescales the reading to a percentage, using whole-number arithmetic.
Worked example 2: predict the readings
LDR in bright light ():
LDR in darkness (): , so . A threshold of about 500 separates light from dark.
LM35 reading 62: , so . One ADC step is 4.89 mV, about , so the sketch cannot resolve temperatures more finely than about half a degree.
Some sensors send their readings as coded digital messages, which a library decodes for you. The DHT22 (and the cheaper, less accurate DHT11) measures temperature and humidity on a single data pin. Install the DHT sensor library by Adafruit from the IDE's Library Manager (it also installs the Adafruit Unified Sensor library), connect VCC to 5 V, GND to GND and DATA to pin 4 (bare sensors also need a 10 kΩ resistor from DATA to VCC; most modules have one built in), and upload:
// DHT22 temperature and humidity sensor on pin 4 (library: "DHT sensor library" by Adafruit)
#include <DHT.h>
const int DHT_PIN = 4;
DHT dht(DHT_PIN, DHT22); // use DHT11 for the cheaper blue sensor
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
delay(2000); // the DHT22 needs about 2 s between readings
float humidity = dht.readHumidity();
float celsius = dht.readTemperature();
if (isnan(humidity) || isnan(celsius)) {
Serial.println("Sensor read failed: check the wiring");
return;
}
Serial.print("Humidity: ");
Serial.print(humidity, 0);
Serial.print(" % Temperature: ");
Serial.print(celsius, 1);
Serial.println(" C");
}
All three sketches in this lesson were compiled for the Arduino Uno with arduino-cli without errors.
Science Buddies: HC-SR04 Ultrasonic Distance Sensor and Arduino (Lesson #9). Watch how the Trig and Echo pins are wired and how the echo time becomes a distance; check the formula against worked example 1.
Warning
Check the sensor's voltage and pins before connecting. Most sensors here run at 5 V, but some modules are 3.3 V only and can be damaged by 5 V. Pin orders differ between makers: read the labels on the module, not a picture from another seller. Never connect a sensor's VCC to GND, and wire with the USB cable unplugged.
Tip
Print raw values first. Before converting a reading to centimetres or degrees, print the raw number and watch it change as you cover the LDR, warm the LM35 with your finger, or move your hand in front of the HC-SR04. If the raw value does not change, the problem is wiring, not maths.
light_temp and record the LDR reading in light and in darkness (in the simulator, drag the light-level slider). Choose a threshold.millis() for the 10 seconds.Check: the LED never lights in bright light, lights within a second of motion in the dark, and goes off 10 seconds after the last motion.
Practice
analogRead() return on the Uno, and why that range?analogRead value.map(700, 0, 1023, 0, 100) return? (It uses whole numbers.)Sources and credits
This lesson adapts CC BY-SA material and is shared under CC BY-SA 4.0.