This project demonstrates how to control an RGB LED, a separate red LED, an active buzzer, and a passive buzzer using two push buttons connected to an Arduino Uno R3.
The project originally started as a simple RGB LED and two-button controller. Over approximately 2–3 days of experimenting, debugging, and adding new ideas, the project evolved into a multi-mode light and sound controller with custom siren frequencies, multiple buzzer behaviors, button-controlled states, and timed LED sequences.
The project uses digital inputs, digital outputs, conditional logic, loops, arrays, custom header files, tone generation, modulo operations, and persistent state variables to determine how the system reacts to different button presses.
This project was designed and programmed from scratch as part of my journey learning Arduino programming and C++.
- Arduino Uno R3
- 1 × RGB LED (Common Cathode)
- 1 × Red LED
- 4 × 220 Ω Resistors
- 2 × Push Buttons
- 1 × Active Buzzer
- 1 × Passive Buzzer
- Breadboard
- Jumper Wires
| Arduino Pin | Component |
|---|---|
| D3 | RGB LED - Red |
| D4 | Passive Buzzer |
| D5 | RGB LED - Green |
| D6 | RGB LED - Blue |
| D7 | Left Push Button |
| D8 | Right Push Button |
| D11 | Active Buzzer |
| D12 | Separate Red LED |
| GND | RGB LED, Red LED, Both Push Buttons, and required component grounds |
- Controls an RGB LED and a separate red LED using two push buttons.
- Uses
INPUT_PULLUPfor reliable button input detection. - Uses one button as a multi-mode switch with a persistent state variable.
- Uses an active buzzer for a custom multi-stage sound sequence.
- Uses a passive buzzer for frequency-based tone generation.
- Uses custom siren frequencies stored in a modified header file.
- Alternates between two siren frequencies using an array and modulo.
- Activates a custom dual-button police-style light and siren mode.
- Uses multiple timing stages to change active buzzer behavior.
- Produces green, yellow, and red RGB LED states.
- Runs a timed traffic-light-style sequence.
- Uses PWM-capable pins for all three RGB LED channels for future 0–255 brightness control.
- Resets the left-button mode counter after completing the final sequence.
The Arduino continuously checks the state of both push buttons using the INPUT_PULLUP configuration.
Because INPUT_PULLUP is used:
- Button not pressed:
HIGH - Button pressed:
LOW
The program checks the button conditions in a specific order.
When both buttons are pressed simultaneously, the Arduino activates the passive buzzer siren mode.
The passive buzzer uses two custom frequencies stored in an array:
SIREN_2 and SIREN_1
The program alternates between the two frequencies using:
two_freq % 2
This produces a repeating array index pattern:
0, 1, 0, 1, 0, 1...
This allows the program to repeatedly alternate between two siren frequencies without reading beyond the available array values.
The mode also activates the separate red LED and the blue channel of the RGB LED to create a police-style light effect.
When only the right button is pressed, the Arduino runs a custom active-buzzer sequence.
A for loop counts from 0 to 99, and different if / else if conditions change the buzzer timing during different sections of the loop.
The active buzzer timing changes through multiple stages:
- First stage uses a slower delay.
- Second stage increases the speed.
- Third stage increases the speed again.
- Final active stage continues with the most recently assigned buzzer timing.
The separate red LED and RGB red channel are activated during the sequence using a custom blink delay.
The left button acts as a multi-mode switch.
A persistent global variable named r starts at:
r = 0
Each button press increments the value:
r++
The current value of r determines which mode runs:
- Press 1 (
r == 1): Green - Press 2 (
r == 2): Yellow using red + green - Press 3 (
r == 3): Red - Press 4 (
r == 4): Runs a timed light sequence and resetsrback to 0
This allows one physical push button to perform multiple functions instead of being limited to one action.
When no buttons are pressed, the program turns off:
- RGB LED channels
- Separate red LED
- Active buzzer
The project includes a modified header file:
pitchesMODIFIED.h
This file contains the original musical frequency definitions along with custom siren frequency constants.
Example:
#define SIREN_1 900
#define SIREN_2 1500
The main Arduino program includes the file using:
#include "pitchesMODIFIED.h"
The custom frequencies are stored in an array:
int siren_sounds[] = {SIREN_2, SIREN_1};
The passive buzzer then uses tone() to generate the selected frequency.
RGB_LED_Button_Controller.ino- Main Arduino programpitchesMODIFIED.h- Modified frequency definitions containing custom siren valuesREADME.md- Project documentationimages/- Circuit and connection documentation images
Note: The circuit schematic should be updated to reflect the final project wiring, including the active buzzer, passive buzzer, and updated RGB LED pin assignments.
Note: The pin connection summary should be updated to reflect the final pin configuration used by the completed code.
Note: The components image should be updated to include the active and passive buzzers used in the final project.
While building this project, I learned how to:
- Configure Arduino pins as inputs and outputs.
- Use
INPUT_PULLUPfor button detection. - Read button states using
digitalRead(). - Control LEDs and an active buzzer using
digitalWrite(). - Generate frequencies using
tone(). - Build decision-making logic using
if,else if, andelse. - Repeat code using
forloops. - Create and use integer variables.
- Increment values using
++. - Create arrays using
[]. - Access array values using an index.
- Use modulo
%to alternate between array positions. - Use a persistent global variable to track button modes.
- Make one physical button perform multiple actions.
- Include an external header file using
#include. - Create custom constants using
#define. - Modify a pitch header file with custom siren frequencies.
- Understand the difference between active and passive buzzers.
- Use PWM-capable pins for future RGB brightness control.
- Organize an Arduino project with documentation using GitHub.
One of the biggest bugs I encountered happened when I created an array containing only two siren frequencies:
int siren_sounds[] = {SIREN_2, SIREN_1};
I initially used a loop that attempted to access far more than two array positions.
This caused the Arduino to read beyond the valid array values and produce unexpected tones.
I corrected the behavior using:
two_freq % 2
This allowed the program to safely alternate between array indexes 0 and 1 while still running a longer loop.
I initially attempted to track multiple button presses using a local for loop variable.
I learned that a for loop automatically iterates and that a variable created inside the loop does not work as persistent memory for separate physical button presses.
I changed the design to use a global variable:
int r = 0;
Each left-button press increments the value using:
r++;
This allowed the Arduino to remember the current mode between repeated executions of loop().
While building the active buzzer and LED sequence, I learned that adding or removing a single delay() can change the timing of the entire system.
I repeatedly adjusted:
- Buzzer delays
- LED blink delays
- Loop thresholds
- Tone duration
- Frequency values
This helped me understand how sequential code execution affects the timing and synchronization of hardware.
This project originally began as a simple controller with:
- 2 push buttons
- 1 RGB LED
- 1 separate red LED
The original behavior was:
- Left button → Green
- Right button → Red
- Both buttons → COP Mode
- No buttons → Off
The final version expanded the original idea with:
- Active buzzer sequences
- Passive buzzer tone generation
- Custom siren frequencies
- Arrays
- Modulo operations
- Multi-stage timing
- Persistent button states
- Multi-function button controls
- Traffic-light color states
- Timed light sequences
- PWM-capable RGB pin assignments
- A custom modified pitch header file
Completed
This is my first major self-directed Arduino project and was completed after approximately three days of learning Arduino and C++.
The code is not intended to be perfectly optimized. It represents my learning process, experimentation, debugging, and growing understanding of how software and hardware interact.
- Replace some blocking
delay()calls withmillis()-based timing. - Implement proper button debouncing.
- Use
analogWrite()for RGB brightness control and smoother color mixing. - Refactor repeated code into reusable functions.
- Improve the passive buzzer siren with smoother frequency sweeps.
- Update the circuit schematic and connection images to match the completed hardware.
- Continue learning through the Elegoo Uno R3 Super Starter Kit.


