const uint8_t BLUE_PIN = 9; // PWM
const uint8_t GREEN_PIN = 10; // PWM
const uint8_t RED_PIN = 11; // PWM
const uint8_t POT_PIN = A5; // analog input
// thresholds for dividing potentiometer into thirds
constexpr int T1 = 341;
constexpr int T2 = 682;
// previous printed values for change detection
int prevBlue = -1;
int prevGreen = -1;
int prevRed = -1;
// manual overrides (-1 = follow potentiometer). Values 0..255
int manualBlue = -1;
int manualGreen = -1;
int manualRed = -1;
// serial command buffer
char cmdBuf[64];
size_t cmdIndex = 0;
static inline void printPrompt() {
Serial.print("> ");
}
static void to_upper_inplace(char *s) {
for (char *p = s; *p; ++p) {
if (*p >= 'a' && *p <= 'z') *p = *p - ('a' - 'A');
}
}
static void trim_trailing_spaces(char *s) {
size_t n = strlen(s);
while (n > 0 && (s[n - 1] == ' ' || s[n - 1] == '\t')) {
s[--n] = '\0';
}
}
// handle a single segment
void handleSegment(char *seg) {
trim_trailing_spaces(seg);
if (seg[0] == '\0') return;
// extract name (up to first whitespace) and optional value
char name[16] = {0};
int value = -1;
char *p = seg;
while (*p && *p != ' ' && *p != '\t') ++p;
size_t n = (size_t)(p - seg);
if (n >= sizeof(name)) n = sizeof(name) - 1;
// copy name and uppercase it
for (size_t i = 0; i < n; ++i) {
char c = seg[i];
if (c >= 'a' && c <= 'z') c = c - ('a' - 'A');
name[i] = c;
}
name[n] = '\0';
if (*p) {
while (*p == ' ' || *p == '\t') ++p;
value = atoi(p);
}
if (strcmp(name, "BLUE") == 0) {
manualBlue = constrain(value, 0, 255);
Serial.print("\r\nManual Blue set to: ");
Serial.println(manualBlue);
} else if (strcmp(name, "GREEN") == 0) {
manualGreen = constrain(value, 0, 255);
Serial.print("\r\nManual Green set to: ");
Serial.println(manualGreen);
} else if (strcmp(name, "RED") == 0) {
manualRed = constrain(value, 0, 255);
Serial.print("\r\nManual Red set to: ");
Serial.println(manualRed);
} else if (strcmp(name, "AUTO") == 0) {
manualBlue = manualGreen = manualRed = -1;
Serial.println("\r\nReturning control to potentiometer");
} else if (strcmp(name, "HELP") == 0) {
Serial.println("\r\nCommands:");
Serial.println(" BLUE <0-255> - set Blue PWM directly");
Serial.println(" GREEN <0-255> - set Green PWM directly");
Serial.println(" RED <0-255> - set Red PWM directly");
Serial.println(" AUTO - return control to potentiometer");
Serial.println(" You may send multiple commands separated by commas:");
Serial.println(" e.g. BLUE 255,GREEN 128,RED 0");
} else {
Serial.print("\r\nUnknown command: '");
Serial.print(name);
Serial.println("'. Type HELP for usage.");
}
}
// process a full command line which may contain comma-separated segments
void processCommand(const char *cmd) {
if (!cmd || !*cmd) return;
const char *p = cmd;
while (*p) {
// skip leading whitespace
while (*p == ' ' || *p == '\t') ++p;
if (!*p) break;
// find segment end
const char *end = p;
while (*end && *end != ',') ++end;
// copy into local buffer
char seg[48];
size_t len = (size_t)(end - p);
if (len >= sizeof(seg)) len = sizeof(seg) - 1;
strncpy(seg, p, len);
seg[len] = '\0';
// trim leading spaces
char *segStart = seg;
while (*segStart == ' ' || *segStart == '\t') ++segStart;
if (segStart != seg) memmove(seg, segStart, strlen(segStart) + 1);
trim_trailing_spaces(seg);
if (seg[0] != '\0') handleSegment(seg);
// advance past comma if present
p = end;
if (*p == ',') ++p;
}
printPrompt();
}
void setup() {
delay(200);
Serial.begin(9600);
Serial.println("\n\nPotentiometer RGB with Serial Control (manual: 0-255)");
printPrompt();
pinMode(BLUE_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(RED_PIN, OUTPUT);
}
void loop() {
// ---- Serial input + echo + backspace ----
while (Serial.available()) {
int c = Serial.read();
if (c == '\r') continue; // ignore CR
// Backspace or DEL
if (c == 8 || c == 127) {
if (cmdIndex > 0) {
cmdIndex--;
Serial.print("\b \b");
}
continue;
}
// Newline -> process command line
if (c == '\n') {
cmdBuf[cmdIndex] = '\0';
Serial.println();
processCommand(cmdBuf);
cmdIndex = 0;
continue;
}
// Printable char -> buffer + echo
if (c >= 32 && c <= 126) {
if (cmdIndex < sizeof(cmdBuf) - 1) {
cmdBuf[cmdIndex++] = (char)c;
Serial.write((char)c);
}
}
}
// ---- Read pot and compute PWM ----
int potValue = analogRead(POT_PIN);
int blueBrightness;
if (manualBlue >= 0) {
blueBrightness = manualBlue;
} else {
if (potValue <= T1) {
// scale (0..T1) -> (0..255)
blueBrightness = (uint32_t)potValue * 255 / T1;
} else {
blueBrightness = 0;
}
}
int greenBrightness;
if (manualGreen >= 0) {
greenBrightness = manualGreen;
} else {
if (potValue > T1 && potValue <= T2) {
greenBrightness = (uint32_t)(potValue - T1) * 255 / (T2 - T1);
} else {
greenBrightness = 0;
}
}
int redBrightness;
if (manualRed >= 0) {
redBrightness = manualRed;
} else {
if (potValue > T2) {
redBrightness = (uint32_t)(potValue - T2) * 255 / (1023 - T2);
} else {
redBrightness = 0;
}
}
analogWrite(BLUE_PIN, blueBrightness);
analogWrite(GREEN_PIN, greenBrightness);
analogWrite(RED_PIN, redBrightness);
// ---- Print changed values with small hysteresis ----
bool anyPrinted = false;
if (abs(blueBrightness - prevBlue) > 3) {
Serial.print("\r\nBlue LED PWM: ");
Serial.println(blueBrightness);
prevBlue = blueBrightness;
anyPrinted = true;
}
if (abs(greenBrightness - prevGreen) > 3) {
Serial.print("\r\nGreen LED PWM: ");
Serial.println(greenBrightness);
prevGreen = greenBrightness;
anyPrinted = true;
}
if (abs(redBrightness - prevRed) > 3) {
Serial.print("\r\nRed LED PWM: ");
Serial.println(redBrightness);
prevRed = redBrightness;
anyPrinted = true;
}
if (anyPrinted) printPrompt();
delay(50);
}