577  Visual and Audio Actuators

Learning Objectives

After completing this chapter, you will be able to:

  • Control LEDs with PWM for brightness dimming
  • Drive addressable RGB LED strips (NeoPixels/WS2812B)
  • Interface LCD and OLED displays using I2C/SPI
  • Generate tones and melodies with passive buzzers
  • Create visual and audio feedback for IoT devices

577.1 LED Control

LEDs (Light Emitting Diodes) are the simplest visual actuators, used for indicators, status lights, and ambient lighting.

577.1.1 Basic LED with PWM Brightness

#define LED_PIN 25

void setup() {
  // Configure PWM for LED dimming
  ledcSetup(0, 5000, 8);  // Channel 0, 5kHz, 8-bit resolution
  ledcAttachPin(LED_PIN, 0);
}

void loop() {
  // Fade in
  for (int brightness = 0; brightness <= 255; brightness++) {
    ledcWrite(0, brightness);
    delay(10);
  }

  // Fade out
  for (int brightness = 255; brightness >= 0; brightness--) {
    ledcWrite(0, brightness);
    delay(10);
  }
}

577.1.2 RGB LED Control

// RGB LED pins (common cathode)
#define RED_PIN 25
#define GREEN_PIN 26
#define BLUE_PIN 27

void setup() {
  // Configure PWM for each color channel
  ledcSetup(0, 5000, 8);  // Red
  ledcSetup(1, 5000, 8);  // Green
  ledcSetup(2, 5000, 8);  // Blue

  ledcAttachPin(RED_PIN, 0);
  ledcAttachPin(GREEN_PIN, 1);
  ledcAttachPin(BLUE_PIN, 2);
}

void setColor(int red, int green, int blue) {
  ledcWrite(0, red);
  ledcWrite(1, green);
  ledcWrite(2, blue);
}

void loop() {
  setColor(255, 0, 0);    // Red
  delay(1000);
  setColor(0, 255, 0);    // Green
  delay(1000);
  setColor(0, 0, 255);    // Blue
  delay(1000);
  setColor(255, 255, 0);  // Yellow
  delay(1000);
  setColor(0, 255, 255);  // Cyan
  delay(1000);
  setColor(255, 0, 255);  // Magenta
  delay(1000);
  setColor(255, 255, 255);// White
  delay(1000);
}

577.2 Addressable LED Strips (NeoPixel/WS2812B)

Addressable LEDs allow individual control of each LED in a strip using a single data wire.

#include <Adafruit_NeoPixel.h>

#define LED_PIN 18
#define NUM_LEDS 30

Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.setBrightness(50);  // 0-255
  strip.show();  // Initialize all pixels to 'off'
}

void loop() {
  rainbow(10);
  theaterChase(strip.Color(127, 0, 0), 50);  // Red
  colorWipe(strip.Color(0, 255, 0), 50);     // Green
}

void rainbow(int wait) {
  for (long firstPixelHue = 0; firstPixelHue < 65536; firstPixelHue += 256) {
    for (int i = 0; i < strip.numPixels(); i++) {
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show();
    delay(wait);
  }
}

void theaterChase(uint32_t color, int wait) {
  for (int a = 0; a < 10; a++) {
    for (int b = 0; b < 3; b++) {
      strip.clear();
      for (int c = b; c < strip.numPixels(); c += 3) {
        strip.setPixelColor(c, color);
      }
      strip.show();
      delay(wait);
    }
  }
}

void colorWipe(uint32_t color, int wait) {
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, color);
    strip.show();
    delay(wait);
  }
}

577.3 LCD Displays

577.3.1 16x2 LCD with I2C

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Address 0x27, 16 columns, 2 rows

void setup() {
  lcd.init();
  lcd.backlight();

  lcd.setCursor(0, 0);
  lcd.print("IoT System");
  lcd.setCursor(0, 1);
  lcd.print("Initializing...");

  delay(2000);
}

void loop() {
  // Display temperature
  float temperature = 25.4;

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Temperature:");
  lcd.setCursor(0, 1);
  lcd.print(temperature);
  lcd.print(" C");

  delay(2000);

  // Display humidity
  float humidity = 65.2;

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Humidity:");
  lcd.setCursor(0, 1);
  lcd.print(humidity);
  lcd.print(" %");

  delay(2000);
}

577.4 OLED Displays

OLED displays offer high contrast, low power consumption, and graphical capabilities.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  Serial.begin(115200);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 allocation failed");
    while (1);
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
}

void loop() {
  displaySensorData(25.4, 65.2, 1013.25);
  delay(2000);

  drawGraphics();
  delay(2000);

  progressBar("Loading...", 100);
  delay(1000);
}

void displaySensorData(float temp, float humidity, float pressure) {
  display.clearDisplay();

  display.setTextSize(2);
  display.setCursor(0, 0);
  display.print("IoT Data");

  display.setTextSize(1);
  display.setCursor(0, 20);
  display.print("Temp: ");
  display.print(temp);
  display.print(" C");

  display.setCursor(0, 35);
  display.print("Humid: ");
  display.print(humidity);
  display.print(" %");

  display.setCursor(0, 50);
  display.print("Press: ");
  display.print(pressure);
  display.print(" hPa");

  display.display();
}

void drawGraphics() {
  display.clearDisplay();

  display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
  display.fillRect(10, 10, 30, 20, SSD1306_WHITE);
  display.drawCircle(80, 32, 20, SSD1306_WHITE);
  display.drawLine(0, 0, 127, 63, SSD1306_WHITE);

  display.display();
}

void progressBar(String message, int duration) {
  for (int progress = 0; progress <= 100; progress += 2) {
    display.clearDisplay();

    display.setTextSize(1);
    display.setCursor(0, 10);
    display.print(message);

    // Draw progress bar outline
    display.drawRect(10, 30, 108, 10, SSD1306_WHITE);

    // Fill progress bar
    int fillWidth = (progress * 104) / 100;
    display.fillRect(12, 32, fillWidth, 6, SSD1306_WHITE);

    // Display percentage
    display.setCursor(50, 45);
    display.print(progress);
    display.print("%");

    display.display();
    delay(duration / 50);
  }
}

577.5 Buzzers and Tone Generation

577.5.1 Passive Buzzer (Tone Generation)

Passive buzzers can play different frequencies/tones.

#define BUZZER_PIN 25

// Musical notes (frequencies in Hz)
#define NOTE_C4 262
#define NOTE_D4 294
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_G4 392
#define NOTE_A4 440
#define NOTE_B4 494
#define NOTE_C5 523

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

void loop() {
  playMelody();
  delay(2000);

  playAlarm();
  delay(2000);

  playNotification();
  delay(5000);
}

void playMelody() {
  int melody[] = {NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5};
  int durations[] = {250, 250, 250, 500};

  for (int i = 0; i < 4; i++) {
    tone(BUZZER_PIN, melody[i], durations[i]);
    delay(durations[i] * 1.3);  // Pause between notes
  }

  noTone(BUZZER_PIN);
}

void playAlarm() {
  for (int i = 0; i < 5; i++) {
    tone(BUZZER_PIN, 1000, 200);
    delay(250);
    tone(BUZZER_PIN, 500, 200);
    delay(250);
  }

  noTone(BUZZER_PIN);
}

void playNotification() {
  tone(BUZZER_PIN, NOTE_A4, 100);
  delay(150);
  tone(BUZZER_PIN, NOTE_C5, 200);
  delay(250);
  noTone(BUZZER_PIN);
}

577.5.2 Active Buzzer (Simple On/Off)

Active buzzers have built-in oscillators - just supply power.

#define BUZZER_PIN 25

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

void beep(int count, int onTime, int offTime) {
  for (int i = 0; i < count; i++) {
    digitalWrite(BUZZER_PIN, HIGH);
    delay(onTime);
    digitalWrite(BUZZER_PIN, LOW);
    delay(offTime);
  }
}

void loop() {
  // Single beep
  beep(1, 100, 0);
  delay(2000);

  // Double beep
  beep(2, 100, 100);
  delay(2000);

  // Alarm pattern
  beep(5, 50, 50);
  delay(2000);
}

577.6 Display Selection Guide

Display Power Contrast Update Rate Best Use Case
16x2 LCD 20-100mA Medium Fast Indoor, mains powered
OLED 10-50mA High Fast Battery, frequent updates
E-paper 0.001mA Highest Slow (1s) Battery, infrequent updates
TFT LCD 100-300mA Medium Very fast Mains powered, graphics

577.7 What’s Next?

Now that you understand output devices, you’re ready to explore PWM control in depth with interactive calculators.

Continue to PWM Control β†’