Skip to content
Phuc's Blog
Go back

Some basic hardware devices in IoT

Edit page
📌Series:Internet of Things
Part 7 of 7
View all articles in this series

This blog is my diary recording my journey of learning about IoT, particularly the hardware devices used in IoT applications. I will introduce some basic hardware devices in IoT, including sensors and actuators.

Some basic hardware devices in IoT

Table of contents

Open Table of contents

Sensor Devices

Photoresistor Sensor (LDR Module) ☀️

Photoresistor Sensor Module Figure 1: The standard 4-pin photoresistor (LDR) sensor module.

Main Components

Pinout


Simulation & Arduino Code ⚡

Here is a simple simulation circuit connecting an LDR with an Arduino Uno using a voltage divider configuration:

Photoresistor Arduino Simulation Figure 2: Breadboard simulation circuit connecting an LDR to Arduino Uno analog pin A0.

Circuit Connections
Arduino Example Code
const int LDR_PIN = A0; // Connect to Analog pin A0

void setup() {
  Serial.begin(9600);
}

void loop() {
  int lightLevel = analogRead(LDR_PIN); // Reads value between 0 - 1023
  
  Serial.print("Ambient Light Level: ");
  Serial.println(lightLevel);

  delay(500); // Read every half second
}
Tip

Higher ambient light reduces the LDR resistance, causing the voltage reading on A0 to increase towards 10231023. In pitch black, the value drops closer to 00.


Automatic Night Light: Integrating with an LED 💡

Now, let’s turn this into a real-world smart application: an automatic night light that turns an LED on when it gets dark and turns it off when the room is bright!

Photoresistor and LED Integrated Circuit Figure 3: Arduino circuit controlling an LED based on LDR light readings.

Additional Circuit Connections
Arduino Example Code
const int LDR_PIN = A0;   // Photoresistor connected to Analog A0
const int LED_PIN = 5;    // LED connected to Digital Pin 5
const int THRESHOLD = 500; // Darkness threshold value

void setup() {
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int lightLevel = analogRead(LDR_PIN);
  Serial.print("Light level: ");
  Serial.println(lightLevel);

  // If it's dark (reading below threshold), turn on the LED
  if (lightLevel < THRESHOLD) {
    digitalWrite(LED_PIN, HIGH);
  } else {
    digitalWrite(LED_PIN, LOW);
  }

  delay(200);
}

Ultrasonic Sensor (HC-SR04) 🦇

Ultrasonic Sensor Module Figure 4: The HC-SR04 Ultrasonic distance sensor and its echo-ranging principle.

The HC-SR04 uses high-frequency sound waves (ultrasound at 40 kHz40\text{ kHz}) to measure distance without physical contact—just like bats navigate in the dark!

How It Works (Echo Principle)

  1. Trigger (Transmitter “T”): Sends out an ultrasonic sound burst (8 pulses at 40 kHz40\text{ kHz}).
  2. Reflect: The sound wave travels forward, hits an obstacle, and bounces back.
  3. Echo (Receiver “R”): Detects the reflected wave and outputs a pulse whose duration equals the round-trip travel time.

Pinout

Distance Formula

Since sound travels through air at approximately 0.034 cm/μs0.034\text{ cm}/\mu\text{s} (or 340 m/s340\text{ m/s}), and the wave travels to the object and back:

Distance (cm)=Time×0.0342\text{Distance (cm)} = \frac{\text{Time} \times 0.034}{2}


Simulation & Arduino Code ⚡

Here is a simple simulation wiring the HC-SR04 with an Arduino Uno:

Ultrasonic Arduino Simulation Figure 5: HC-SR04 ultrasonic sensor simulation connected to Arduino Uno pins 5 (Trig) and 4 (Echo).

Circuit Connections

Arduino Example Code

const int trigger_pin = 5;
const int echo_pin = 4;

void setup() {
    Serial.begin(9600);
    pinMode(trigger_pin, OUTPUT);
    pinMode(echo_pin, INPUT);
}

long getDistance() {
    digitalWrite(trigger_pin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigger_pin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigger_pin, LOW);
    long duration = pulseIn(echo_pin, HIGH);
    long distance = duration * 0.034 / 2;
    return distance;
}

void loop() {
    int distance = getDistance(); // unit: cm
    Serial.print("Distance: ");
    Serial.print(distance);
    Serial.println(" cm");
    delay(200);
}
Note

Why 10μs10\mu\text{s} on Trig? HC-SR04 requires a HIGH pulse of at least 10μs10\mu\text{s} to fire its 8-cycle ultrasonic burst (40 kHz40\text{ kHz}). The preceding 2μs2\mu\text{s} LOW ensures a clean signal edge.

Push Button (Tactile Switch) 🔘

Push Button Pinout Figure 6: Tactile push button internal connection diagram.

A push button (or tactile switch) is an input sensor that connects two points in a circuit when pressed.

Pin Configuration

Although it has 4 pins, they are connected in pairs internally:


Simulation & Arduino Code ⚡

Here is a push button connected to an Arduino Uno using a pull-down resistor (10kΩ10\text{k}\Omega):

Push Button Arduino Simulation Figure 7: Push button circuit with a pull-down resistor connected to Arduino Pin 12.

Circuit Connections

Note

Why a pull-down resistor? Without it, an unpressed button leaves the pin “floating” (reading random noise). The 10kΩ10\text{k}\Omega resistor holds the pin steadily at LOW (0V0\text{V}) until pressed.

Arduino Example Code

const int BUTTON_PIN = 12;

void setup() {
  Serial.begin(9600);
  pinMode(BUTTON_PIN, INPUT);
}

void loop() {
  int buttonState = digitalRead(BUTTON_PIN);

  if (buttonState == HIGH) {
    Serial.println("Button Pressed!");
  } else {
    Serial.println("Button Released");
  }

  delay(200);
}

Potentiometer (Variable Resistor) 🎛️

Potentiometer Figure 8: Rotary potentiometers (variable resistors).

A potentiometer (biến trở) is a 3-terminal variable resistor. Turning its knob adjusts electrical resistance, producing a variable output voltage that functions as an adjustable voltage divider.

3-Terminal Pinout

Potentiometer Pinout Figure 9: Potentiometer 3-pin configuration and internal wiper diagram.

PinConnected ToDescription
1 (Terminal 1)Arduino GNDGround reference (or 5V)
2 (Wiper / Output)Arduino Analog Pin (A0)Variable voltage output (0V−5V0\text{V} - 5\text{V})
3 (Terminal 2)Arduino 5VPower supply (or GND)
Tip

Pins 1 and 3 are interchangeable. Swapping them simply reverses which direction of knob rotation increases or decreases the reading. The center pin (Pin 2) is always the wiper signal output.


Simulation & Arduino Code ⚡

Here is a potentiometer connected to an Arduino Uno on analog pin A0:

Potentiometer Arduino Simulation Figure 10: Potentiometer wired to Arduino Uno analog pin A0.

Circuit Connections
1. Basic Analog Reading

The Arduino reads the voltage on pin A0 as a 10-bit integer from 0 (0V0\text{V}) to 1023 (5V5\text{V}):

const int POT_PIN = A0;

void setup() {
  Serial.begin(9600);
  pinMode(POT_PIN, INPUT);
}

void loop() {
  int value = analogRead(POT_PIN); // Reads 0 to 1023
  Serial.println(value);
  delay(100);
}
2. Controlling LED Brightness (Dimming)

Translate the 10-bit analog reading (0−10230 - 1023) to an 8-bit PWM value (0−2550 - 255) using map(), and drive an LED on Pin ~6 with analogWrite():

const int POT_PIN = A0;
const int LED_PIN = 6; // PWM pin

void setup() {
  pinMode(POT_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int value = analogRead(POT_PIN);               // Range: 0 - 1023
  int led_value = map(value, 0, 1023, 0, 255);   // Convert to PWM: 0 - 255
  analogWrite(LED_PIN, led_value);               // Adjust LED brightness
  delay(100);
}

Actuator Devices

Buzzer (Active & Passive) 🔊

Buzzer Module Figure 11: A standard buzzer module.

A buzzer is a small component that makes sound—like beeps, clicks, or alarms.

Active vs. Passive Buzzer

There are two main types of buzzers:

FeatureActive Buzzer 🟢Passive Buzzer 🔵
How it worksHas a built-in sound generatorNeeds an external sound wave
How to controlJust turn power on/off (HIGH / LOW)Send frequencies using tone()
SoundOne fixed “beep” soundCan play different musical notes
Best used forSimple warning beeps & alarmsSongs, melodies, and sound effects

Pins (Polarity)


Simulation & Arduino Code 🎵

Here is a simple simulation wiring a buzzer to an Arduino Uno to play a melody:

Buzzer Arduino Simulation Figure 12: Buzzer simulation connected to Arduino Uno Pin 5 and GND.

Circuit Connections

Arduino Example Code

int buzzer_pin = 5;

void setup() {
  pinMode(buzzer_pin, OUTPUT);
}

void loop() {
  int notes_len = 25;
  int frequency[] = {262, 262, 294, 262, 349, 330, 262, 262, 294, 262, 
  392, 349, 262, 262, 523, 440, 349, 330, 294, 466, 466, 440, 349, 392, 349};
  float duration[] = {0.5, 0.5, 1, 1, 1, 2, 0.5, 0.5, 1, 1, 1, 2, 0.5, 
  0.5, 1, 1, 1, 1, 3, 0.5, 0.5, 1, 1, 1, 2};

  for (int i = 0; i < notes_len; i++) {
    tone(buzzer_pin, frequency[i], duration[i] * 1000);
    delay(500);
  }
  noTone(buzzer_pin);
}
Tip
  • tone(pin, frequency, duration) sends a sound frequency (in Hz) to the buzzer for a set duration.
  • noTone(pin) shuts off the sound when the melody finishes.

Relay Module 🔌

5V Relay Module Figure 13: A standard 5VDC single-channel relay module.

A relay is an electrically operated switch. It allows a low-power microcontroller (like an Arduino running on 5V5\text{V}) to safely turn on and off high-power electrical devices (like 220V220\text{V} light bulbs, fans, or motors).

Note

What does “5VDC” mean?

  • Coil power: VCC requires a constant 5V5\text{V} DC to power the internal electromagnet.
  • Triggering: While VCC is always 5V5\text{V}, the IN pin depends on the module: Active-HIGH triggers on 5V5\text{V} (HIGH), while Active-LOW (common in Arduino kits) triggers on 0V0\text{V} (LOW).

How It Works (Working Mechanism)

Inside the relay is an electromagnet and a physical mechanical switch:

Relay Working Mechanism Figure 14: Internal working mechanism of an electromagnetic relay.

  1. Control Signal (1): The microcontroller sends a small signal to the relay.
  2. Electromagnet Coil (2): Current flows through the coil, creating a magnetic field.
  3. Movable Switch (3): The magnet pulls the contact arm closed (this makes the characteristic “click” sound!).
  4. High-Power Load (4): The high-voltage circuit completes, safely powering the light bulb or appliance.

When the signal turns off, the magnetic pull stops, and an internal spring pulls the switch back open to disconnect power.

Terminals & Pinout Breakdown

Relay Terminals Figure 15: Relay module terminal connections (Control side vs. High-power load side).

A relay module has two separate sides:

1. Control Side (Low Voltage - Arduino):

2. Load Side (High Voltage - Appliances):


Circuit Integration: Controlling an AC Light Bulb 💡

Here is how an Arduino Uno safely controls an AC light bulb using the relay module:

Relay with Arduino and AC Light Bulb Figure 16: Wiring diagram of an Arduino controlling an AC light bulb via relay.

Circuit Connections
Arduino Example Code
const int RELAY_PIN = 7;

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
}

void loop() {
  // Turn ON the light bulb (for Active-HIGH modules)
  digitalWrite(RELAY_PIN, HIGH);
  delay(3000); // Wait 3 seconds

  // Turn OFF the light bulb
  digitalWrite(RELAY_PIN, LOW);
  delay(3000); // Wait 3 seconds
}
Tip

Complete electrical isolation: the 5V5\text{V} control side and high-voltage AC side never touch, protecting your Arduino from surges.


SPDT Relay (Single Pole Double Throw) 🔀

SPDT Relay Component Figure 17: A standalone SPDT relay component (LU-5-R).

The most common mechanical relay used in electronics and simulation platforms (such as Wokwi) is the SPDT (Single Pole Double Throw) relay:

SPDT Pinout Configuration

Standalone SPDT relays feature 6 pins directly on the casing:

SPDT Relay Pinout Figure 18: 6-pin SPDT relay layout and connection mapping.

Note

Digital Pin as direct power source: Unlike the 3-wire module above (which has separate VCC power and IN signal pins), this standalone SPDT relay has no VCC pin. The Arduino Digital Pin itself directly powers the coil with 5V5\text{V} when set to HIGH.


Practical Simulation: Switching a DC Light Bulb with a 9V Battery 💡

Here is a practical simulation wiring an SPDT relay to control a DC light bulb powered by an external 9V battery:

SPDT Relay Simulation Circuit Figure 19: Arduino controlling a 9V battery-powered bulb through an SPDT relay.

Connection Table
Relay PinArduino Uno9V BatteryBulb
Digital PinPin 3——
GNDGND——
NO—Positive (+)—
COM——Positive (+)
——Negative (-)Negative (-)
How It Works
Arduino Example Code
const int RELAY_PIN = 3;

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
}

void loop() {
  // Turn ON the bulb for 2 seconds
  digitalWrite(RELAY_PIN, HIGH);
  delay(2000);

  // Turn OFF the bulb for 2 seconds
  digitalWrite(RELAY_PIN, LOW);
  delay(2000);
}

LCD 16x2 Display 📟

LCD 16x2 Module Figure 20: A standard 16x2 Liquid Crystal Display (LCD).

An LCD (Liquid Crystal Display) 16x2 displays visual text, numbers, and symbols across 2 rows of 16 characters.

16-Pin Pinout Breakdown

LCD 16x2 Pinout Figure 21: LCD 16x2 pinout and functional signal lines.

The 16 pins are divided into four main roles:


4-Bit Parallel Mode: Wiring & Simulation ⚡

LCD 16x2 Arduino Wiring Figure 22: Arduino Uno controlling an LCD 16x2 in 4-bit mode with contrast potentiometer.

Connection Table
LCD PinConnected ToPurpose
VSS, RW, KArduino GNDGround references
VDDArduino 5VLogic power
V0Potentiometer Center PinContrast tuning
RSArduino Pin 12Register select
EArduino Pin 11Enable clock
D4, D5, D6, D7Arduino Pins 5, 4, 3, 24-bit data bus
AArduino 5V (via 220Ω220\Omega)Backlight power
Arduino Example Code (LiquidCrystal.h)
#include <LiquidCrystal.h>

// Initialize library with interface pins: RS, E, D4, D5, D6, D7
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);              // Set up columns and rows
  lcd.print("Hello, World!");    // Print message on row 0
}

void loop() {
  lcd.setCursor(0, 1);           // Move cursor to column 0, row 1
  lcd.print(millis() / 1000);    // Print seconds elapsed
}

Upgrade: LCD with I2C Module (Save Wiring) 🚀

Standard 4-bit parallel wiring takes up at least 6 digital GPIO pins. An I2C backpack module soldered onto the back reduces all connections to just 4 wires!

LCD I2C Module Figure 23: LCD 16x2 equipped with an I2C adapter backpack.

I2C Pin Connections
Tip
  • Most LCD I2C backpacks use the address 0x27 (or 0x3F).
  • Contrast can be adjusted using the small blue potentiometer directly on the I2C backpack.
Arduino I2C Code (LiquidCrystal_I2C.h)
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Set the LCD address (0x27 or 0x3F) for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();
  lcd.backlight();               // Turn on LCD backlight
  lcd.setCursor(0, 0);
  lcd.print("Hello World!");
}

void loop() {
  // Blinking backlight example
  lcd.backlight();
  delay(1000);
  lcd.noBacklight();
  delay(1000);
}

Servo Motor (Micro Servo SG90) 🦾

Micro Servo Motor Figure 24: Micro Servo SG90 motor.

A servo motor is an actuator designed for precise angular position control. Unlike regular DC motors that spin continuously, a standard micro servo rotates precisely between 0∘0^\circ and 180∘180^\circ.

3-Wire Pinout

Wire ColorConnected ToFunction
RedArduino 5VPower supply
Brown / BlackArduino GNDGround reference
Orange / YellowArduino PWM Pin (~9)Control signal pulse

Simulation & Arduino Code ⚡

Here is a simple simulation wiring a micro servo to an Arduino Uno:

Servo Motor Arduino Simulation Figure 25: Micro Servo connected to Arduino Uno Pin ~9 (PWM), 5V, and GND.

Basic Angle Control (Servo.h)
#include <Servo.h>

Servo myservo; // Create servo object

void setup() {
  myservo.attach(9); // Attach servo to digital pin 9
}

void loop() {
  myservo.write(0);    // Rotate to 0 degrees
  delay(1000);
  myservo.write(90);   // Rotate to 90 degrees (center)
  delay(1000);
  myservo.write(180);  // Rotate to 180 degrees
  delay(1000);
}
Practical Control: Steering with a Potentiometer

Using Arduino’s map() function, you can translate the potentiometer’s analog input (0−10230 - 1023 on pin A0) directly into an angle (0∘−180∘0^\circ - 180^\circ):

#include <Servo.h>

Servo myservo;
const int POT_PIN = A0;

void setup() {
  myservo.attach(9);
}

void loop() {
  int val = analogRead(POT_PIN);          // Read potentiometer (0 - 1023)
  int angle = map(val, 0, 1023, 0, 180);  // Map to servo angle (0 - 180)
  myservo.write(angle);                   // Command servo to rotate
  delay(15);                              // Short wait for movement
}

Edit page
Share this post:

Previous Post
Getting Started with PlatformIO & ESP32
Next Post
Overview of Physical Works in IoT

Comments