Imagine a leak detector hidden under a sink. A dashboard notification may be useful later, but the device needs a local story too: flash, beep, show status, and make the warning impossible to miss in the place where the problem happens.
Visual and audio actuators turn invisible system state into human feedback. Choose LEDs, displays, buzzers, tones, and patterns around attention, power, environment, and how quickly a person must understand the message.
In 60 Seconds
Visual actuators (LEDs, LCD/OLED displays, addressable LED strips) and audio actuators (passive and active buzzers) provide essential user feedback in IoT devices. LEDs are controlled via PWM for brightness dimming, addressable strips like NeoPixels allow individual pixel control over a single data wire, and passive buzzers generate variable-frequency tones for alerts and melodies.
Phoebe’s Field Notes: Two Physical Limits Hiding Behind “256 Levels” And “5 kHz”
Phoebe’s Why
This chapter’s 8-bit PWM dimmer and 5 kHz LED switching rate are not arbitrary firmware settings; they sit against two hard physical limits from information theory. First, chopping a continuous brightness command into 256 discrete duty-cycle codes is exactly the same rounding operation an ADC performs on a sensor voltage – it leaves a quantization “noise floor” that a formula can predict, and here the true sensor doing the rounding-back-out is the human eye, whose own brightness discrimination has a floor too. Second, switching an LED on and off is itself a sampled process from the point of view of anything that samples light in time – your eye barely notices, but a rolling-shutter camera samples at its own frame rate, and if the PWM frequency and the camera’s sample rate are not chosen carefully, the fast switching folds down into a slow, very visible beat – the same spectral-folding failure a badly chosen ADC sample rate produces on a sensor signal.
The Derivation
Quantizing an \(N\)-bit duty-cycle code over full-scale range \(\mathrm{FSR}\) leaves a step and a noise floor:
For a full-scale signal, the ratio of signal power to that noise floor reduces to the standard ADC/DAC result (the \(\mathrm{FSR}\) terms cancel):
\[\mathrm{SNR}(\mathrm{dB}) = 6.02N + 1.76\]
Any process that samples a time-varying signal at rate \(f_s\) folds an input component at \(f_{in}\) down to an aliased frequency inside the baseband:
which is zero only when \(f_s \geq 2f_{in}\) places \(f_{in}\) outside the fold range entirely – the Nyquist criterion.
Worked Numbers: This Chapter’s Own 8-bit, 5 kHz PWM
This chapter’s own 8-bit brightness code (\(N=8\)):\(\mathrm{SNR}=6.02\times8+1.76=49.9\) dB. Quantization step at the chapter’s own \(5\) V driver, chapter’s own \(1/255\) convention: \(q=5/255=0.0196\) V, matching the chapter’s own figure; rms noise floor \(q/\sqrt{12}=0.00566\) V \(=5.66\) mV.
Tying it to the transducer that actually reads it – the eye: a catalog-typical luminance just-noticeable-difference (Weber fraction) is about \(1\%\). The 8-bit code step is \(1/255=0.392\%\) of full scale – already about \(2.5\times\) finer than the eye’s own discrimination floor, so more PWM bits could not buy a visibly smoother fade; the eye’s transduction physics, not the PWM resolution, is the limiting stage.
This chapter’s own 5 kHz LED PWM sampled by a catalog-typical camera frame rate:\(f_{alias}=|5000-\mathrm{round}(5000/f_s)\,f_s|\) gives \(8.00\) Hz at \(24\) fps, \(0.00\) Hz at \(25\) fps, \(10.0\) Hz at \(30\) fps, and \(20.0\) Hz at \(60\) fps.
Honest finding: a \(5\) kHz PWM rate is far above anything the naked eye resolves, yet three of these four common frame rates fold it down into an \(8\)-\(20\) Hz beat – squarely inside the range a viewer does notice as banding on video. That is a real, reported LED-flicker-on-camera failure mode, and the fix is a Nyquist-style one: pick a PWM frequency (or a filtering scheme) that does not fold into a low beat against the target frame rates, not just one that is “fast.”
Learning Objectives
After completing this chapter, you will be able to:
Configure PWM parameters to dim LEDs across 256 brightness levels
Program addressable RGB LED strips (NeoPixels/WS2812B) for independent pixel control
Explain why LED matrix blocks use driver ICs such as MAX7219/MAX7221 instead of direct GPIO control
Interface LCD and OLED displays using I2C/SPI communication protocols
Generate tones and melodies with passive buzzers using frequency modulation
Design multi-modal visual and audio feedback systems for IoT applications
Quick Check: Feedback Modality Selection
For Beginners: Visual and Audio Feedback
Think of how a microwave beeps when your food is ready, or how a traffic light changes color to tell you when to stop or go. Visual actuators (like LEDs and screens) and audio actuators (like buzzers) are the ways IoT devices communicate with people. They turn invisible data into something you can see or hear, making smart devices feel responsive and helpful.
Chapter Roadmap
This chapter has four linked stops:
First you choose local feedback channels: LEDs, displays, buzzers, or combinations.
Then you control LEDs with current limiting, PWM brightness, RGB channels, and addressable pixel power budgets.
Next you move from lights to information displays: matrix drivers, LCD character layouts, and OLED frame buffers.
Finally you design audible and multi-modal alerts, then check the selection against power, noticeability, and environment.
Checkpoints recap the main decisions as you go. Existing calculators, quizzes, and deep dives are optional breathers when you want to test the numbers.
10.2 LED Control
LEDs (Light Emitting Diodes) are the simplest visual actuators, used for indicators, status lights, and ambient lighting.
LED Current-Limiting Resistor Calculator
Calculate the required series resistor for safe LED operation:
Show code
viewof supply_voltage = Inputs.range([3,12], {value:5,step:0.5,label:"Supply Voltage (V)"})viewof forward_voltage = Inputs.range([1.8,3.5], {value:2.0,step:0.1,label:"LED Forward Voltage (V)"})viewof forward_current_ma = Inputs.range([5,30], {value:20,step:1,label:"Desired Current (mA)"})
You might think dimming an LED means reducing voltage, but that’s not how it works. Here’s the trick:
Step 1: On/Off at High Speed - Instead of lowering voltage (which would change LED color), the microcontroller rapidly switches the LED fully ON and fully OFF – thousands of times per second (typically 1-20 kHz).
Step 2: Vary the Duty Cycle - - 100% brightness = LED on 100% of the time - 50% brightness = LED on 50%, off 50% (alternating) - 10% brightness = LED on 10%, off 90%
Step 3: Your Eye Averages It - The switching happens so fast (>500 Hz) that your eye perceives a smooth brightness level, not flickering. It’s like spinning a fan – individual blades blur into a circle.
Real-World Analogy: Imagine a light switch you flick on and off 1,000 times per second. If you keep it on 70% of the time (on for 0.7ms, off for 0.3ms in each 1ms cycle), your eye sees 70% brightness – even though the LED is always either fully ON or fully OFF, never “dim.”
Why This Method?
Maintains LED color accuracy (full voltage = correct wavelength)
No heat dissipation in resistors (efficient)
Fine brightness control (8-bit PWM = 256 levels from 0-255)
Works with any LED without special dimming circuits
Interactive PWM Power Calculator
Calculate power consumption and energy savings for LED brightness control:
Example: At 50% PWM brightness (duty cycle = 0.5), an LED with forward voltage \(V_f = 2.1\) V and \(I_f = 20\) mA appears half as bright and uses half the power. Average current is \(I_{avg} = 0.5 \times 20 = 10\) mA, so power is \(P = V_f \times I_{avg} = 2.1 \times 0.01 = 0.021\) W. Over 24 hours, this saves \(E = (0.042 - 0.021) \times 24 = 0.5\) Wh compared to full brightness.
html`<div style="background: var(--bs-light, #f8f9fa); padding: 1rem; border-radius: 8px; border-left: 4px solid #E67E22; margin-top: 0.5rem;"><p><strong>Current per LED:</strong> ${strip_actual_current.toFixed(1)} mA</p><p><strong>Total Current:</strong> ${strip_total_current.toFixed(2)} A</p><p><strong>Total Power (5V):</strong> ${strip_power_5v.toFixed(2)} W</p><p><strong>Recommended Supply:</strong> ${(strip_total_current *1.2).toFixed(2)} A (with 20% safety margin)</p>${strip_total_current >2?'<p style="color: #E74C3C; font-weight: bold;">⚠️ Requires external power supply (not USB)</p>':''}</div>`
Note: WS2812B LEDs draw approximately 60mA at full white (all three RGB channels at maximum). Single colors draw ~20mA. Always add a 20% safety margin to your power supply rating.
Check
Arithmetic carried through
Result to use in the review
Single LED full power
2.1 V x 0.020 A = 0.042 W
One full-bright indicator is about 42 mW.
50% PWM LED current
0.50 x 20 mA = 10 mA; 2.1 V x 0.010 A = 0.021 W
The same LED is about 21 mW before driver losses.
24-hour PWM saving
(0.042 W - 0.021 W) x 24 h = 0.504 Wh
Round at the end: about 0.5 Wh saved per LED-day.
5 kHz PWM timing
1 / 5000 = 0.0002 s = 0.2 ms; 0.2 ms x 0.50 = 0.1 ms
A 50% command is roughly 100 microseconds on and 100 microseconds off.
8-bit brightness step
1 / 255 = 0.0039216; 5 V x 0.0039216 = 0.0196 V
One code step is about 0.392%, or 19.6 mV of ideal average on a 5 V LED driver.
30-pixel full-white strip
30 x 60 mA = 1800 mA = 1.8 A; 5 V x 1.8 A = 9 W
Full-white worst case needs a supply sized above 1.8 A.
20% supply margin
1.8 A x 1.20 = 2.16 A
Choose at least a 2.16 A 5 V supply for the full-white 30-pixel case.
Code brightness limit
50 / 255 = 0.1961; 1.8 A x 0.1961 = 0.353 A; 5 V x 0.353 A = 1.76 W
The code’s setBrightness(50) keeps a full-white frame near 0.35 A, but release evidence should still check startup and fault cases.
The audit conclusion is bounded: PWM reduces average LED power, and the strip code greatly lowers the steady full-white current. It does not remove the need to size wiring, ground return, fuse behavior, and supply margin for the highest credible visual state.
#include <Adafruit_NeoPixel.h>#define LED_PIN 18#define NUM_LEDS 30Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);void setup(){ strip.begin(); strip.setBrightness(50);// 0-255 (limit current draw) strip.show();}void loop(){ rainbow(10);// Cycle all hues colorWipe(strip.Color(0,255,0),50);// Green wipe colorWipe(strip.Color(127,0,0),50);// Red wipe}// Animate a rainbow across the stripvoid rainbow(int wait){for(long hue =0; hue <65536; hue +=256){for(int i =0; i < strip.numPixels(); i++){int pixelHue = hue +(i *65536L/ strip.numPixels()); strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));} strip.show(); delay(wait);}}// Fill strip one pixel at a timevoid colorWipe(uint32_t color,int wait){for(int i =0; i < strip.numPixels(); i++){ strip.setPixelColor(i, color); strip.show(); delay(wait);}}
10.4 LED Matrices and Driver ICs
An LED matrix block packs many ordinary LEDs into a row/column grid. An 8x8 matrix has 64 emitters, but the package usually exposes row and column pins rather than 64 separate LED pairs. The controller lights a pattern by selecting one row or column at a time fast enough that the eye sees a stable image. That multiplexing saves pins, but it creates two practical problems: the firmware must refresh the matrix continuously, and the current peaks through the active row or column must stay inside the matrix and driver ratings.
This is why small LED matrix kits usually include more than the visible block. A review should identify the matrix block, socket or carrier PCB, headers, passive parts, and the display-driver IC before treating the kit as “just LEDs.” The driver owns the repetitive refresh and current-limited switching while the microcontroller sends compact display data.
The MAX7219/MAX7221 family is a common example. It sits between the MCU and the matrix: DIN receives serial data, CLK clocks bits in, LOAD or CS latches a command, and DOUT can pass data to another driver. On the display side, the DIG0 through DIG7 pins select rows or digits, while SEG A through SEG G and SEG DP drive the eight column or segment lines. V+ and GND power the chip, and the ISET resistor sets the peak segment current.
For a raw 8x8 LED matrix, leave decode mode off and write row or column bit patterns directly. The register addresses are part of the wiring evidence: 0x01 through 0x08 hold the eight digit or row data bytes, 0x09 controls decode mode, 0x0A controls intensity, 0x0B sets the scan limit, 0x0C leaves shutdown mode, and 0x0F enables or disables display test. A first proof can write a diagonal or single-row sweep, then record whether the image is rotated, mirrored, or missing rows.
The chip interface is small, but it is still a protocol. Each update is a 16-bit instruction: one address byte selects the target register and one data byte supplies the value. CLK advances each bit, DIN carries the bit value, and LOAD or CS latches the complete command. If the display is blank, check shutdown mode first, then confirm that the data, clock, and load pins match the library constructor.
Treat the display library as an adapter, not as magic. A library such as LedControl hides the bit shifting and latch timing, but the review still needs to name the processor-side pins, the number of chained devices, the matrix orientation, and the character table used by the application. A character library is usually just a set of eight-byte patterns: each byte represents one row or column of an 8x8 glyph. That makes the first message display a useful integration test because it proves both the wiring and the glyph orientation.
When several LED blocks are chained, DOUT from one driver feeds DIN on the next and the constructor’s device count changes. That is the main code difference between a one-block demo and a multi-block message board. Keep the physical order explicit: device 0 might be the block nearest the microcontroller or the farthest block, depending on how the modules are wired. A scrolling message, a dice face, or a small game animation should be treated as a final demo after the evidence path has already proved power, orientation, scan limit, intensity, and per-block addressing.
Keep the evidence close to the hardware. Record supply voltage, common ground, library version, DIN/CLK/CS pins, matrix orientation, current setting, and the known-good test pattern. If the first display appears scrambled, fix the row/column mapping or module orientation before adding animations; otherwise the software may hide a wiring error behind a pretty pattern.
Checkpoint: Pixel Chains and Matrices
You now know:
WS2812B pixels trade GPIO count for power and timing discipline: full white is about 60 mA per pixel.
A 30-pixel full-white case reaches 1.8 A, so the data pin is not the power path.
Matrix drivers such as MAX7219/MAX7221 prove orientation, scan limit, intensity, and row data before animations hide wiring mistakes.
Once the output needs words, values, or menus instead of colored states, a display becomes the clearer actuator.
html`<div style="background: var(--bs-light, #f8f9fa); padding: 1rem; border-radius: 8px; border-left: 4px solid #3498DB; margin-top: 0.5rem;"> <div style="display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; margin-bottom: 0.75rem;">${Array.from({length:Math.min(alert_info.beeps,9)}, (_, i) => {let w = alert_type ==="SOS Pattern"&& i >=3&& i <6? beep_on_ms *3: beep_on_mslet maxW =80let barW =Math.min(Math.max(w /5,10), maxW)return`<div style="display: inline-flex; align-items: flex-end; gap: 2px;"> <div style="width: ${barW}px; height: 30px; background: #3498DB; border-radius: 3px;" title="${w}ms on"></div> <div style="width: ${Math.min(beep_off_ms /10,20)}px; height: 10px; background: #ddd; border-radius: 2px;" title="${beep_off_ms}ms off"></div> </div>` }).join("")} </div> <p style="margin: 0.3rem 0;"><strong>Pattern:</strong> ${alert_type} -- ${alert_info.desc}</p> <p style="margin: 0.3rem 0;"><strong>Frequency:</strong> ${beep_freq} Hz | <strong>Audibility:</strong> <span style="color: ${alert_audibility_color}; font-weight: bold;">${alert_audibility}</span> (1-3 kHz is optimal for human hearing)</p> <p style="margin: 0.3rem 0;"><strong>Total Duration:</strong> ${alert_total_ms} ms | <strong>On/Off Ratio:</strong> ${alert_duty}%</p> <details style="margin-top: 0.5rem;"> <summary style="cursor: pointer; color: #3498DB; font-weight: bold;">Show Arduino Code</summary> <pre style="background: #2C3E50; color: #ecf0f1; padding: 0.75rem; border-radius: 4px; margin-top: 0.5rem; font-size: 0.85em;">${alert_type ==="SOS Pattern"?`// SOS Patternvoid playSOS() { // 3 short beeps for (int i = 0; i < 3; i++) { tone(BUZZER_PIN, ${beep_freq}, ${beep_on_ms}); delay(${beep_on_ms + beep_off_ms}); } // 3 long beeps for (int i = 0; i < 3; i++) { tone(BUZZER_PIN, ${beep_freq}, ${beep_on_ms *3}); delay(${beep_on_ms *3+ beep_off_ms}); } // 3 short beeps for (int i = 0; i < 3; i++) { tone(BUZZER_PIN, ${beep_freq}, ${beep_on_ms}); delay(${beep_on_ms + beep_off_ms}); } noTone(BUZZER_PIN);}`: alert_type ==="Alarm (Alternating)"?`// Alternating Alarmvoid playAlarm() { for (int i = 0; i < 3; i++) { tone(BUZZER_PIN, ${beep_freq}, ${beep_on_ms}); delay(${beep_on_ms + beep_off_ms}); tone(BUZZER_PIN, ${Math.round(beep_freq /2)}, ${beep_on_ms}); delay(${beep_on_ms + beep_off_ms}); } noTone(BUZZER_PIN);}`:`// ${alert_type}void playAlert() { for (int i = 0; i < ${alert_info.beeps}; i++) { tone(BUZZER_PIN, ${beep_freq}, ${beep_on_ms}); delay(${beep_on_ms + beep_off_ms}); } noTone(BUZZER_PIN);}`}</pre> </details></div>`
Buzzers add urgency, but they also add fatigue. The selection guide that follows treats sound as one channel in a larger feedback design, not as the default answer for every event.
10.8 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
Bedside Feedback Actuators
Scenario: A team is designing bedside monitors for a clinical ward. Each monitor tracks several patient readings and must draw staff attention to urgent conditions while avoiding constant, low-value beeping.
Constraints:
Requirement
Specification
Why
Critical alarm response
Immediate local awareness
Urgent states should not depend on someone watching the display
Ambient noise level
Variable, with conversation and equipment noise
Audio must be noticeable without being constant
Night shift visibility
Low-light conditions
Visual cues essential
False alarm handling
Suppress nuisance alerts and escalate confirmed problems
Prevents alarm fatigue
Power budget
Mains-powered (not a constraint)
Hospital monitors plugged in
Actuator Selection Analysis:
Feedback Channel
Component Selected
Rationale
Critical alarm (audio)
Passive buzzer or speaker with distinct tone patterns
Variable frequency can distinguish alarm classes
Critical alarm (visual)
Red strobe or high-visibility LED pattern
Visible when staff are not looking at the screen
Warning (audio)
Shorter, quieter pulse pattern
Distinct from critical alarms and less fatiguing
Warning (visual)
Amber LED steady glow
Visible but non-urgent; amber = caution
Normal status
Green LED steady
“All OK” at a glance; no audio (reduces noise floor)
Detailed readings
OLED or LCD display sized for the enclosure
High contrast and readable labels for local inspection
Nurse station
Larger graphical display
Multiple patients and alert states can be compared quickly
Why NOT these alternatives?
Active buzzer for all alarms: It is simple, but its fixed pitch makes it poor when different alarm classes need different sounds.
E-paper display at bedside: It is excellent for rare updates, but its slow refresh is a poor match for frequently changing waveforms.
Room-scale colored lighting: It can help in some spaces, but it requires building-level integration. A local high-visibility LED or strobe is simpler to verify.
Design Decision: Audio Pattern Differentiation
The system uses distinct alarm patterns so staff can identify urgency without first reading the screen:
Alarm Type
Audio Pattern
Frequency
Priority
Critical physiological alarm
Repeating high-priority pattern
High pitch band
Highest
Urgent measurement alarm
Descending or alternating pattern
Mid/high pitch band
High
Device or sensor problem
Short repeated pulses
Mid pitch band
Medium
Low battery / sensor off
Occasional single pulse
Lower pitch band
Low
Resulting design: Critical alarms use both a visual channel and an audio channel, warnings use lower-intensity patterns, and normal operation stays visual-only. That separation keeps urgent states noticeable while reducing unnecessary sound.
Checkpoint: Alert Selection
You now know:
Passive buzzers need an audio-frequency waveform; active buzzers make their own fixed tone when powered.
Alert tones usually target 1000-3000 Hz, while lower tones around 500 Hz can be useful where hearing protection changes perception.
Critical states should use more than one channel when people may not be watching the device or may not hear it reliably.
10.9 Knowledge Check
Key Takeaway
Visual and audio actuators provide essential user feedback in IoT systems. LEDs range from simple indicators to addressable strips capable of complex animations. Displays should be selected based on power budget (e-paper for battery, OLED for moderate updates, TFT for rich graphics). Passive buzzers offer flexible tone generation for alerts and melodies, while active buzzers provide simple on/off beeping. Always consider power consumption, as displays and LED strips can be the largest power consumers in a battery-powered IoT device.
For Kids: Meet the Actuator Crew!
“Time for the Output Show!” announced Lila the LED, glowing all the colors of the rainbow. “We’re the actuators that you can SEE and HEAR!”
“Let me go first!” Lila said excitedly. She started dim, then slowly grew brighter and brighter. “Max controls my brightness with PWM – the same trick he uses for motors! But instead of spinning faster, I glow brighter!”
Then a whole strip of her NeoPixel friends lit up, each one a different color. “Meet my addressable friends! Even though there are 30 of us, Max only needs ONE wire to talk to all of us. The first pixel reads its color instruction, then passes the rest of the message down the chain – like a game of telephone, but it actually works perfectly!”
Next, Buzzy the Buzzer cleared his throat. “BEEP BOOP BEEEEP!” He played a little melody. “I’m a passive buzzer, which means Max can make me play ANY note by changing how fast he vibrates me. Higher frequency = higher pitch! I can even play songs!”
“And I’m the screen!” said OLED Olivia, displaying a smiley face. “I can show Sammy’s temperature readings, draw pictures, and even make progress bars. I use tiny organic light-emitting dots – each pixel makes its own light, so I’m super bright and clear!”
“We all work together,” said Sammy the Sensor. “I measure the temperature, Max decides what to do, and then Lila shows green for ‘all good,’ Olivia displays the number, and Buzzy beeps if it gets too hot. Input to output – that’s the IoT loop!”
Bella the Battery whispered, “Just remember, all those pretty lights use MY energy. Turn them off when nobody’s looking!”
10.10 Knowledge Check
Quiz: Visual and Audio Actuators
Match: Visual and Audio Actuator Concepts
Order: Steps to Control LED Brightness with PWM on ESP32
🏷️ Label the Diagram
Code Challenge
10.11 Deep Dive: Feedback Loads, Perception, and Timed LEDs
Figure 10.1: Status indicator LED array with a current-limited GPIO LED circuit
LEDs, displays, and buzzers are simple only at the user interface. Electrically, each one still has a load path and a control signal. A small status LED shows the pattern: if a 3.3 V GPIO drives a red LED with about 2.0 V forward drop at 10 mA, the resistor must drop 1.3 V, so R = (3.3 - 2.0) / 0.010 = 130 ohms. Choosing 150 ohms gives I = 1.3 / 150 = 0.0087 A, or 8.7 mA. The resistor dissipates 1.3 V x 0.0087 A = 0.011 W, so a small signal resistor has margin. At 25% PWM duty cycle, the average LED current is about 8.7 mA x 0.25 = 2.2 mA.
The design decision is not only electrical. Feedback actuators differ in noticeability, power, and information density. A single green LED is excellent for a healthy status, but poor for a fault that must be noticed across a room. A display can show numbers and labels, but only helps when someone is looking at it. A buzzer interrupts attention, but repeated audio becomes annoying and may be masked by the environment. Strong products combine channels: quiet visual status for normal operation, stronger visual patterns for warnings, and audio only when the state needs immediate attention.
Displays need the same budget discipline. If a small OLED draws 20 mA from a 3.3 V rail while lit, the display load is 3.3 V x 0.020 A = 0.066 W. Left on for 24 hours, that is 0.066 W x 24 h = 1.58 Wh before regulator losses. On a small battery device, that can dominate the energy budget. If the value changes only occasionally, e-paper is often a better human interface because it can keep an image visible between refreshes without continuous display power.
Buzzers split into two kinds that are often confused. An active buzzer has an internal oscillator and produces one fixed tone when powered. A passive piezo or magnetic buzzer needs the controller to supply an audio-frequency waveform. A 2 kHz passive-buzzer alert has a period of 1 / 2000 = 0.0005 s, or 500 microseconds; a 50% square wave is high for about 250 microseconds and low for about 250 microseconds. A lower 500 Hz warning tone has a period of 1 / 500 = 0.002 s, or 2 ms. The controller changes pitch by changing the period, not by changing the supply voltage.
Addressable LEDs such as WS2812/NeoPixel parts add a different kind of timing constraint. Each pixel contains a driver chip, reads the first 24 bits as its green, red, and blue values, and forwards the rest downstream. There is no clock line; each bit is encoded by pulse width and lasts roughly 1.25 microseconds. A 30-pixel strip therefore needs 30 pixels x 24 bits = 720 bits, or 720 x 1.25 = 900 microseconds, plus the reset interval. An interrupt that pauses the GPIO waveform halfway through a bit can corrupt the data seen by every later pixel.
That timing issue is separate from the power issue. The same 30-pixel strip at full white can draw 30 x 60 mA = 1.8 A, which is 5 V x 1.8 A = 9 W. A microcontroller pin can generate the data waveform, but the 5 V supply and ground return must carry the power. Random flicker can come from data timing or from supply droop, so debug in order: limit brightness, confirm common ground, check the 5 V rail under load, then inspect whether the data driver can keep sub-microsecond timing without interruption.
10.12 Summary
Visual and audio actuators transform digital data into human-perceivable feedback. Key concepts:
LED Control:
PWM dimming varies duty cycle (not voltage) to control perceived brightness
Distinct patterns prevent alarm fatigue in safety-critical applications
Standard resistor values (E12/E24 series) for current limiting
Common Pitfalls
1. LED Without Current Limiting Resistor
An LED connected directly from VCC to GPIO (or directly to a supply) has no resistance to limit current. LED forward voltage (1.8-3.5 V) is much less than supply voltage (3.3-5 V). The excess voltage forces very high current through the LED, burning it out within seconds. Always calculate and install a current limiting resistor: R = (Vsupply - Vf) / If_desired.
2. Passive Buzzer Driven by DC Instead of Oscillating Signal
A passive buzzer requires an oscillating signal (PWM at audio frequency) to produce sound — it is simply a piezo element that vibrates at the applied frequency. Applying a DC HIGH from a GPIO pin to a passive buzzer produces no sound (or a brief click as it deflects). Use analogWrite() or tone() with an audio-range frequency (1 kHz - 5 kHz) for audible output from passive buzzers.
3. Driving High-Current LED Strips Directly from MCU GPIO
WS2812B addressable LED strips draw up to 60 mA per RGB LED at full white brightness. A strip of 30 LEDs draws 1.8 A. This exceeds GPIO current limits by 100x and exceeds typical USB power adapter capacity. Always power LED strips from a dedicated 5 V power supply rated for the full strip current, with a shared common ground to the MCU.
4. Active Buzzer and Passive Buzzer Confusion
Active buzzers contain an internal oscillator and produce a fixed tone when voltage is applied (just connect VCC and GND). Passive buzzers require an external oscillating signal. They look identical externally and share the same package styles. Testing with a DC supply: active buzzers beep immediately; passive buzzers are silent. Apply the wrong driving method to the wrong buzzer type and you will get no sound.
10.13 What’s Next?
Now that you understand visual and audio actuators, explore related actuator types and deeper control techniques.