1 changed files with 146 additions and 0 deletions
@ -0,0 +1,146 @@ |
|||||
|
/*
|
||||
|
* LED + Button Controller with Serial Commands and Smooth Pulsing |
||||
|
* ================================================================ |
||||
|
* |
||||
|
* HARDWARE WIRING NOTES: |
||||
|
* ---------------------- |
||||
|
* The switch (TRU Components LAS1-AGQ-11E/R/G) has an integrated LED rated |
||||
|
* for +12V with a built-in resistor. Since the Arduino cannot: |
||||
|
* a) Supply 12V (it outputs 5V max) |
||||
|
* b) Drive enough current for the LED directly |
||||
|
* c) Do PWM dimming at 12V |
||||
|
* |
||||
|
* ...you MUST use an NPN Darlington transistor (TIP122) as a low-side switch. |
||||
|
* |
||||
|
* WIRING: |
||||
|
* +12V PSU (+) --> LED+ on switch |
||||
|
* LED- on switch --> COLLECTOR (TIP122 middle pin) |
||||
|
* Arduino Pin 10 --> 1k Ohm resistor --> BASE (TIP122 left pin) |
||||
|
* EMITTER (TIP122 right pin) --> GND |
||||
|
* Arduino GND + 12V PSU GND --> tied together (common ground) |
||||
|
* |
||||
|
* SWITCH (button) WIRING: |
||||
|
* COM --> Arduino Pin 9 |
||||
|
* NO --> GND |
||||
|
* NC --> leave unconnected |
||||
|
* |
||||
|
* Pin 10 must be PWM-capable (Uno/Nano/Mega all support this). |
||||
|
* |
||||
|
* SERIAL COMMANDS: |
||||
|
* LED_ON -> Turn LED fully on (100%, stops pulsing) |
||||
|
* LED_OFF -> Turn LED fully off (stops pulsing) |
||||
|
* LED_DIM:xx -> Turn LED on at xx percent (0-100), e.g. LED_DIM:50 |
||||
|
* LED_PULSE_ON -> Start smooth breathing/pulse animation |
||||
|
* LED_PULSE_OFF -> Stop pulsing (LED goes off) |
||||
|
* CLEAR -> Turn LED off (legacy command) |
||||
|
* |
||||
|
* BUTTON OUTPUT: |
||||
|
* "B/true" when pressed (LOW with pull-up) |
||||
|
* "B/false" when released (HIGH) |
||||
|
*/ |
||||
|
|
||||
|
// Constants for pin assignments
|
||||
|
const int ledPin = 10; // Must be PWM-capable!
|
||||
|
const int buttonPin = 9; |
||||
|
|
||||
|
// Button state variables
|
||||
|
int buttonState = 1; |
||||
|
int lastButtonState = 1; |
||||
|
|
||||
|
// Debounce timing
|
||||
|
unsigned long lastDebounceTime = 0; |
||||
|
unsigned long debounceDelay = 50; |
||||
|
|
||||
|
// LED state machine
|
||||
|
enum LedMode { |
||||
|
LED_MODE_OFF, |
||||
|
LED_MODE_ON, |
||||
|
LED_MODE_DIM, |
||||
|
LED_MODE_PULSE |
||||
|
}; |
||||
|
|
||||
|
LedMode ledMode = LED_MODE_OFF; |
||||
|
|
||||
|
// Pulse animation variables
|
||||
|
unsigned long pulseStartTime = 0; |
||||
|
const unsigned long pulseCycleMs = 3000; // Full breath cycle duration in ms
|
||||
|
|
||||
|
void setup() { |
||||
|
buttonState = 1; |
||||
|
pinMode(ledPin, OUTPUT); |
||||
|
pinMode(buttonPin, INPUT_PULLUP); |
||||
|
analogWrite(ledPin, 0); |
||||
|
|
||||
|
Serial.begin(9600); |
||||
|
} |
||||
|
|
||||
|
void loop() { |
||||
|
// --- Button debouncing ---
|
||||
|
int reading = digitalRead(buttonPin); |
||||
|
|
||||
|
if (reading != lastButtonState) { |
||||
|
lastDebounceTime = millis(); |
||||
|
} |
||||
|
|
||||
|
if ((millis() - lastDebounceTime) > debounceDelay) { |
||||
|
if (reading != buttonState) { |
||||
|
buttonState = reading; |
||||
|
if (buttonState == 0) { |
||||
|
Serial.println("B/true"); |
||||
|
} else { |
||||
|
Serial.println("B/false"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
lastButtonState = reading; |
||||
|
|
||||
|
// --- Serial command handling ---
|
||||
|
if (Serial.available() > 0) { |
||||
|
String command = Serial.readStringUntil('\n'); |
||||
|
command.trim(); |
||||
|
|
||||
|
if (command == "LED_ON") { |
||||
|
ledMode = LED_MODE_ON; |
||||
|
analogWrite(ledPin, 255); |
||||
|
} |
||||
|
else if (command == "LED_OFF") { |
||||
|
ledMode = LED_MODE_OFF; |
||||
|
analogWrite(ledPin, 0); |
||||
|
} |
||||
|
else if (command.startsWith("LED_DIM:")) { |
||||
|
int percent = command.substring(8).toInt(); |
||||
|
percent = constrain(percent, 0, 100); |
||||
|
int pwmValue = map(percent, 0, 100, 0, 255); |
||||
|
ledMode = LED_MODE_DIM; |
||||
|
analogWrite(ledPin, pwmValue); |
||||
|
} |
||||
|
else if (command == "LED_PULSE_ON") { |
||||
|
ledMode = LED_MODE_PULSE; |
||||
|
pulseStartTime = millis(); |
||||
|
} |
||||
|
else if (command == "LED_PULSE_OFF") { |
||||
|
ledMode = LED_MODE_OFF; |
||||
|
analogWrite(ledPin, 0); |
||||
|
} |
||||
|
else if (command.startsWith("CLEAR")) { |
||||
|
ledMode = LED_MODE_OFF; |
||||
|
analogWrite(ledPin, 0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// --- Pulse animation (non-blocking) ---
|
||||
|
if (ledMode == LED_MODE_PULSE) { |
||||
|
unsigned long elapsed = millis() - pulseStartTime; |
||||
|
unsigned long pos = elapsed % pulseCycleMs; |
||||
|
|
||||
|
// Sine wave: 0 -> 1 -> 0 over one full "breath" cycle
|
||||
|
float phase = (float)pos / (float)pulseCycleMs; |
||||
|
float brightness = sin(phase * PI); |
||||
|
brightness = brightness * brightness; // Squared for organic ease-in-out
|
||||
|
|
||||
|
// Min ~8 so LED never fully goes dark (subtle "alive" glow at trough)
|
||||
|
int pwmValue = 2 + (int)(brightness * 247.0); |
||||
|
analogWrite(ledPin, pwmValue); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue