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.