Circular LED Clock with Proximity Sensor Display using Arduino & NeoPixels

Circular LED Clock with Proximity Sensor – Arduino MEGA + NeoPixel | MakeMindz ▶ Simulate
Arduino MEGA · Module 4

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.

🔌 Arduino MEGA 2560 💡 60x NeoPixel (WS2812B) 📡 HC-SR04 Sensor 🖥️ Free on Wokwi 🎨 4 Display Modes

🖥️ Simulation Platform: Wokwi — Free, Online, Zero Installation

Run the complete circuit in your browser. Click → paste code → simulate instantly!

🔗 Open Simulation →
00 · Overview

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

01 · Components

Components Used

All of these are available as virtual parts in Wokwi — no shopping needed.

01
Arduino MEGA 2560Main controller — more I/O pins than UNO, great for complex projects.
02
NeoPixel Ring (60 LEDs)WS2812B addressable LEDs in a 60-pixel ring — the clock face display.
03
HC-SR04 UltrasonicMeasures distance 2–400 cm. Triggers mode change when hand is detected.
04
Push Button (Blue)Cycles through the 4 display modes manually. Uses INPUT_PULLUP.
05
Push Button (Green)Advances the minute by 5 for quick time setting.
06
330Ω ResistorPlace on NeoPixel data line to protect against signal ringing.
07
1000µF CapacitorAcross 5V/GND on NeoPixels — absorbs power spikes on startup.
08
5V Power SupplyExternal supply recommended when all 60 LEDs are at full brightness.
02 · Simulation Setup

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.

💡 Works in Chrome, Firefox, and Edge. Create a free Wokwi account to save & share your project with a link.

🌐 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
Teachers can view your simulation without running any software — just share the Wokwi link!

📋 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 ✅
⚠️ Copy the COMPLETE JSON — starts with { and ends with }. Don't miss any brackets!
diagram.json — Paste this into Wokwi
{
  "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:

libraries.txt
Adafruit NeoPixel
💡 Click the "+" icon next to the file tabs to create libraries.txt. Wokwi auto-downloads the library when simulation starts — no manual installing needed!

🔗 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!

▶ Open Simulation →
💡 Once open, click the green ▶ Play button. The ring shows a boot animation spiral, then starts the clock at 10:09:00!


 

03 · Circuit Wiring

Circuit Wiring Reference

If you used diagram.json above, wiring is already done. This table is for reference or manual wiring.

Pin connections between Arduino MEGA and all peripherals
ComponentPinArduino PinWire Colour
NeoPixel RingVCC5VRed
NeoPixel RingGNDGNDBlack
NeoPixel RingDIN (Data)Pin 6Green
HC-SR04VCC5VRed
HC-SR04GNDGNDBlack
HC-SR04TRIGPin 10Orange
HC-SR04ECHOPin 11Yellow
Button A (Blue)Pin 1.lPin 2Blue
Button A (Blue)Pin 2.lGNDBlack
Button B (Green)Pin 1.lPin 3Green
Button B (Green)Pin 2.lGNDBlack
💡 Both buttons use INPUT_PULLUP — the Arduino's internal pull-up resistor holds the pin at HIGH until pressed. No external resistors needed for buttons!
04 · Arduino Code

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.

sketch.ino — Part 1/4
// =====================================================
//  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.

sketch.ino — Part 2/4
// ── 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

sketch.ino — Part 3/4
// ── 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()

sketch.ino — Part 4/4
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);
}
05 · Display Modes

The 4 Display Modes Explained

Press the blue button to cycle through modes. The HC-SR04 interacts with Modes 2 and 3.

MODE 0
🕐 Classic Clock
🔴 Red = Hour · 🟢 Green = Minute · 🔵 Cyan = Second. Dim tick marks at 5-minute positions.
MODE 1
🎵 Equalizer
8 colour blobs bounce randomly around the ring with random speeds — looks like an audio equalizer!
MODE 2
📡 Radar Sweep
A green sweep rotates continuously. Wave your hand close — it appears as an orange blip on the radar!
MODE 3
🌈 Rainbow
Full rainbow rotation. Move your hand closer to speed it up — gesture-controlled speed!

🔑 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.
💜 This is called Non-Blocking Code — the professional way to write multi-tasking Arduino sketches. Store a timestamp, check the difference on every loop iteration.
06 · Run & Test

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
⚠️ If you get a compile error, make sure libraries.txt contains exactly: 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!
💡 In Mode 3, the proximity sensor acts like a theremin-style controller — your hand distance directly controls animation speed without touching anything!

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.
💡 Notice the 200 ms debounce — you can hold the button down and it won't cycle too fast. This is exactly how professional Arduino code handles buttons!
07 · Knowledge Check

Quick Quiz

Answer all 5 questions before moving to the next module. Select an answer and click "Check Answer".

1 What does ring.setBrightness(75) do?

2 How does the HC-SR04 measure distance?

3 In clock mode, which colour represents the second hand?

4 Why does the code use millis() instead of delay()?

5 What does INPUT_PULLUP do for the buttons?

🧠 MakeMindz

Summer Course · Module 4 · Circular LED Clock with Proximity Sensor Display

Simulate free at wokwi.com · Visit makemindz.com

Comments

Product Cards
Buddy Bot eBook
⭐ New 2026 Release
Build Your
Own Robot!
3D design, wiring &
Arduino coding.
Young inventors love it!
🖨️
3D Print
All parts
Wire it
Circuit guide
💻
Code it
Arduino IDE
🤖
Watch it
Walk & react
📋 Your Details
Enter your name
Valid 10-digit no.
Enter a valid email
Special Website Offer
₹499 300
🌍 International: $5 USD
One-time · Instant digital delivery
🔒 Secured by Razorpay · Your data is safe
📄 Download Free Sample Copy
🔒 Secured by Razorpay · Your data is safe
🍓
Raspberry Pi Pico Mastery
21 Projects
⚡ Launch Price — 80% OFF
Learn Pico
Build 21 Projects!
MicroPython · Wokwi
IoT · Certificate
Perfect for beginners!
🖥️
Wokwi
No hardware
🐍
MicroPy
From zero
🔨
21 Projects
IoT + sensors
📄
Certificate
Verified cert
📋 Your Details
Enter your name
Valid 10-digit no.
Enter a valid email
Special Launch Offer
₹999 200 80% OFF
🌍 International: $5 USD
One-time · Lifetime access · No subscription
🔒 Secured by Razorpay · UPI · Cards · NetBanking
🎉

You're in!

Payment successful! Your Buddy Bot eBook is ready. Time to build!

📖 Access Your eBook Now
🎉

Enrolled!

Payment successful! Lifetime access to all 21 Pico Projects is yours!

🍓 Go to My Course