Circular LED Clock
with Proximity Sensor
60 NeoPixel LEDs arranged in a ring display hours, minutes & seconds in colour. Wave your hand to switch between 4 animated display modes — gesture control, no touch required.
What You'll Build & Learn
The Circular LED Clock uses 60 NeoPixel LEDs in a ring to show hours, minutes and seconds in different colours — just like a real clock face. The HC-SR04 ultrasonic sensor detects hand gestures to switch between 4 animated display modes. You'll learn addressable LEDs, sensor integration, button debouncing, and non-blocking animation loops.
NeoPixel Control
Drive 60 addressable RGB LEDs with precise colour & brightness
Clock Logic
Map hours, minutes & seconds to LED positions on a ring
Ultrasonic Sensor
Detect hand proximity to trigger gesture-based mode changes
4 Display Modes
Clock, Equalizer, Radar, and Rainbow animations
Button Debounce
Clean button input with millis()-based debouncing
Browser Simulation
Full circuit simulation free in Wokwi — no hardware needed
Components Used
All of these are available as virtual parts in Wokwi — no shopping needed.
Setting Up the Wokwi Simulation
Wokwi is a free online Arduino simulator. Run this entire project in your browser — no account required to start, no software to install.
🌐 Open Wokwi & Create a New Project
Go to wokwi.com in any modern browser.
- Click "New Project" on the homepage
- Select "Arduino MEGA" from the board list
- A blank canvas appears with the Arduino MEGA already placed
📋 Paste the diagram.json — Circuit in One Click!
The easiest way to set up the circuit is to paste the diagram.json file. This automatically places AND wires all components.
- In the Wokwi editor, click the "diagram.json" tab (next to sketch.ino)
- Select all existing text (Ctrl+A) and delete it
- Paste the complete diagram.json code below
- Press Ctrl+S to save — the circuit appears automatically ✅
{ and ends with }. Don't miss any brackets!
{
"version": 1,
"author": "NeoPixel Clock",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-mega", "id": "mega", "top": 200, "left": 100, "attrs": {} },
{ "type": "wokwi-led-ring", "id": "ring1", "top": -180, "left": -180, "attrs": { "pixels": "60" } },
{ "type": "wokwi-hc-sr04", "id": "sonar1", "top": 450, "left": 250, "attrs": { "distance": "25" } },
{ "type": "wokwi-pushbutton", "id": "btnA", "top": 450, "left": 50, "attrs": { "color": "blue" } },
{ "type": "wokwi-pushbutton", "id": "btnB", "top": 450, "left": 130, "attrs": { "color": "green" } }
],
"connections": [
[ "ring1:GND", "mega:GND.1", "black", [] ],
[ "ring1:VCC", "mega:5V", "red", [] ],
[ "ring1:DIN", "mega:6", "green", [] ],
[ "sonar1:GND", "mega:GND.2", "black", [] ],
[ "sonar1:VCC", "mega:5V", "red", [] ],
[ "sonar1:TRIG", "mega:10", "orange", [] ],
[ "sonar1:ECHO", "mega:11", "yellow", [] ],
[ "btnA:1.l", "mega:2", "blue", [] ],
[ "btnA:2.l", "mega:GND.3", "black", [] ],
[ "btnB:1.l", "mega:3", "green", [] ],
[ "btnB:2.l", "mega:GND.4", "black", [] ]
],
"dependencies": {}
}
📚 Install the NeoPixel Library
This project needs the Adafruit NeoPixel library. In Wokwi, create a file called libraries.txt and paste this line:
Adafruit NeoPixel
🔗 Use the Pre-Built Simulation Link
The fastest way — we've already built the complete circuit with code. Just click:
Open Complete Simulation
Pre-built circuit with all components wired. Click ▶ Play and the ring boots with a rainbow spiral, then shows the clock!
Circuit Wiring Reference
If you used diagram.json above, wiring is already done. This table is for reference or manual wiring.
| Component | Pin | Arduino Pin | Wire Colour |
|---|---|---|---|
| NeoPixel Ring | VCC | 5V | Red |
| NeoPixel Ring | GND | GND | Black |
| NeoPixel Ring | DIN (Data) | Pin 6 | Green |
| HC-SR04 | VCC | 5V | Red |
| HC-SR04 | GND | GND | Black |
| HC-SR04 | TRIG | Pin 10 | Orange |
| HC-SR04 | ECHO | Pin 11 | Yellow |
| Button A (Blue) | Pin 1.l | Pin 2 | Blue |
| Button A (Blue) | Pin 2.l | GND | Black |
| Button B (Green) | Pin 1.l | Pin 3 | Green |
| Button B (Green) | Pin 2.l | GND | Black |
INPUT_PULLUP — the Arduino's internal pull-up resistor holds the pin at HIGH until pressed. No external resistors needed for buttons!
The Full Explained Code
Click sketch.ino in Wokwi, delete any existing code, and paste the complete code below. Each part is explained.
① Libraries, Pins & Variables
We include the NeoPixel library and define which pin connects to each component. Variables track time, mode, and button state.
// ===================================================== // NEOPIXEL RING CLOCK — Arduino MEGA // MakeMindz Summer Course · Module 4 // Pins: DIN→6 | TRIG→10 | ECHO→11 | BTN_A→2 | BTN_B→3 // ===================================================== #include <Adafruit_NeoPixel.h> #define LED_PIN 6 // NeoPixel data pin #define NUM_LEDS 60 // 60 pixels in the ring #define TRIG_PIN 10 // HC-SR04 trigger #define ECHO_PIN 11 // HC-SR04 echo #define BTN_A 2 // Mode switch button (blue) #define BTN_B 3 // Minute advance button (green) Adafruit_NeoPixel ring(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); int hh = 10, mm = 9, sc = 0; // start at 10:09:00 unsigned long prevMs = 0; uint8_t dispMode = 0; // 0=Clock 1=EQ 2=Radar 3=Rainbow bool prevA = HIGH, prevB = HIGH; unsigned long dbA = 0, dbB = 0;
② Utility Functions (ping & colour wheel)
The ping() function reads the ultrasonic sensor. The wheel() function converts 0-255 into a smooth colour — used by rainbow and equalizer modes.
// ── Ultrasonic ping — returns distance in cm ── long ping() { digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2); digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW); long t = pulseIn(ECHO_PIN, HIGH, 23000); return t ? t * 17L / 1000 : 60; } // ── Colour wheel: maps 0-255 to smooth colour ─ uint32_t wheel(uint8_t p) { p = 255 - p; if (p < 85) return ring.Color(255-p*3, 0, p*3); if (p < 170) { p-=85; return ring.Color(0, p*3, 255-p*3); } p-=170; return ring.Color(p*3, 255-p*3, 0); } uint32_t scalec(uint32_t c, uint8_t f) { return ring.Color( ((c>>16)&0xFF)*f/255, ((c>>8) &0xFF)*f/255, ( c &0xFF)*f/255); }
③ All 4 Display Mode Functions
// ── MODE 0: Classic Clock ───────────────────── void modeClock() { ring.clear(); for (int i=0;i<60;i+=5) ring.setPixelColor(i,ring.Color(14,14,14)); int hc=(int)round(((hh%12)*60.0f+mm)/720.0f*60.0f)%60; for (int d=-2;d<=2;d++){ int px=(hc+d+60)%60; uint8_t b=(d==0)?230:(abs(d)==1?100:35); ring.setPixelColor(px,ring.Color(b,0,0)); } int mc=(int)round((mm*60.0f+sc)/3600.0f*60.0f)%60; ring.setPixelColor((mc-1+60)%60,scalec(ring.Color(0,255,80),70)); ring.setPixelColor(mc,ring.Color(0,255,80)); ring.setPixelColor((mc+1)%60,scalec(ring.Color(0,255,80),70)); ring.setPixelColor(sc%60,ring.Color(0,210,255)); ring.show(); } // ── MODE 1: Equalizer ───────────────────────── uint8_t eqH[8]={20,42,16,52,34,28,46,22}; int8_t eqV[8]={ 1,-1, 1,-1, 1,-1, 1,-1}; unsigned long eqMs=0; void modeEQ() { if(millis()-eqMs>65){ for(int i=0;i<8;i++){ eqH[i]+=eqV[i]*(int8_t)random(2,7); if(eqH[i]>=58||eqH[i]<=4){eqV[i]=-eqV[i];eqH[i]=constrain(eqH[i],4,58);} } eqMs=millis(); } ring.clear(); for(int b=0;b<8;b++){ int ctr=b*7+3; uint32_t c=wheel(map(eqH[b],4,58,0,185)); uint8_t br=map(eqH[b],4,58,40,255); for(int d=-2;d<=2;d++) ring.setPixelColor((ctr+d+60)%60,scalec(c,(uint16_t)br*(d==0?255:abs(d)==1?130:45)/255)); } ring.show(); } // ── MODE 2: Radar + Proximity ───────────────── int radarHead=0; unsigned long radarMs=0; void modeRadar() { if(millis()-radarMs>22){radarHead=(radarHead+1)%60;radarMs=millis();} ring.clear(); for(int i=0;i<18;i++) ring.setPixelColor((radarHead-i+60)%60,ring.Color(0,map(i,0,17,210,4),0)); long cm=ping(); if(cm<40){ int obj=map(cm,2,40,0,59); ring.setPixelColor(obj,ring.Color(255,80,0)); ring.setPixelColor((obj+1)%60,ring.Color(80,20,0)); ring.setPixelColor((obj-1+60)%60,ring.Color(80,20,0)); } ring.show(); } // ── MODE 3: Rainbow (speed = hand distance) ─── uint16_t rbPos=0; unsigned long rbMs=0; void modeRainbow() { long cm=constrain(ping(),2,40); uint8_t spd=map(cm,2,40,14,1); if(millis()-rbMs>spd){rbPos=(rbPos+1)%256;rbMs=millis();} for(int i=0;i<NUM_LEDS;i++) ring.setPixelColor(i,wheel((i*4+rbPos)&0xFF)); ring.show(); }
④ setup() & loop()
void checkButtons() { unsigned long now=millis(); bool a=digitalRead(BTN_A), b=digitalRead(BTN_B); if(prevA==HIGH&&a==LOW&&now-dbA>200){ dispMode=(dispMode+1)%4; dbA=now; ring.fill(ring.Color(25,25,25)); ring.show(); delay(55); ring.clear(); } if(prevB==HIGH&&b==LOW&&now-dbB>200){ mm=(mm+5)%60; sc=0; dbB=now; } prevA=a; prevB=b; } void setup() { ring.begin(); ring.setBrightness(75); ring.show(); pinMode(TRIG_PIN,OUTPUT); pinMode(ECHO_PIN,INPUT); pinMode(BTN_A,INPUT_PULLUP); pinMode(BTN_B,INPUT_PULLUP); // Boot spiral animation for(int i=0;i<NUM_LEDS;i++){ring.setPixelColor(i,wheel(i*4));ring.show();delay(16);} delay(250); for(int i=NUM_LEDS-1;i>=0;i--){ring.setPixelColor(i,0);ring.show();delay(9);} prevMs=millis(); randomSeed(42); } void loop() { checkButtons(); if(millis()-prevMs>=1000){ prevMs+=1000; if(++sc>=60){sc=0;if(++mm>=60){mm=0;if(++hh>=24)hh=0;}} } switch(dispMode){ case 0: modeClock(); break; case 1: modeEQ(); break; case 2: modeRadar(); break; case 3: modeRainbow(); break; } delay(8); }
The 4 Display Modes Explained
Press the blue button to cycle through modes. The HC-SR04 interacts with Modes 2 and 3.
🔑 Why Use millis() Instead of delay()?
All 4 modes use millis() for timing rather than delay(). This is critical for smooth animation:
- delay(65) — Freezes the whole Arduino for 65 ms. Buttons won't respond. Clock won't tick.
- millis() — Loop keeps running every 8 ms. It just checks if 65 ms has passed. Buttons, clock, and animations all work simultaneously.
Run & Test Your Simulation
Click the Green Play Button
In Wokwi, press the big green ▶ Play button. You should see:
- A rainbow boot spiral — LEDs light up one by one, then fade off
- The ring switches to Clock Mode showing 10:09:00
- The cyan second dot ticks around the ring once per second
Adafruit NeoPixel (correct capitalisation).
Test the Ultrasonic Sensor
Click on the HC-SR04 in the simulation. A popup shows a distance slider. Try this:
- Switch to Mode 2 (Radar) with the blue button
- Drag the slider to 15 cm — an orange blip appears on the ring!
- Switch to Mode 3 (Rainbow) — move slider to 5 cm — rainbow spins faster!
Press the Buttons
- Blue Button (Pin 2) → Cycles modes: 0 → 1 → 2 → 3 → 0. A white flash confirms the switch.
- Green Button (Pin 3) → Advances the minute by 5. Great for quick time-setting.
Quick Quiz
Answer all 5 questions before moving to the next module. Select an answer and click "Check Answer".
.png)
Comments
Post a Comment