#define HEARTBEAT_LED LED_BUILTIN // GP25
#define BLINK_LED 15 // LED (GP28)
#define POT_PIN 26 // ADC0
const unsigned long HEARTBEAT_INTERVAL = 500;
bool blinkEnabled = false; // Toggled by Serial command
bool blinkLedState = false;
unsigned long lastHeartbeatTime = 0;
unsigned long lastBlinkTime = 0;
bool heartbeatState = false; // Current heartbeat state
unsigned long lastPrintTime = 0;
const unsigned long PRINT_INTERVAL = 200;
// Serial command buffer
char serialBuffer[128];
int bufferIndex = 0;
void setup() {
pinMode(HEARTBEAT_LED, OUTPUT);
pinMode(BLINK_LED, OUTPUT);
pinMode(POT_PIN, INPUT);
digitalWrite(HEARTBEAT_LED, LOW);
digitalWrite(BLINK_LED, LOW);
Serial1.begin(115200);
delay(100);
Serial1.println("UART Communication");
Serial1.println("========================================");
}
void loop() {
unsigned long now = millis();
// ===== HEARTBEAT (onboard LED) =====
if (now - lastHeartbeatTime >= HEARTBEAT_INTERVAL) {
lastHeartbeatTime = now;
heartbeatState = !heartbeatState;
digitalWrite(HEARTBEAT_LED, heartbeatState ? HIGH : LOW);
}
// ===== READ POTENTIOMETER =====
int potRaw = analogRead(POT_PIN); // 0–4095
unsigned long blinkInterval = map(potRaw, 0, 4095, 50, 1000);
// ===== BLINK CONTROL =====
if (blinkEnabled) {
if (now - lastBlinkTime >= blinkInterval) {
lastBlinkTime = now;
blinkLedState = !blinkLedState;
digitalWrite(BLINK_LED, blinkLedState ? HIGH : LOW);
}
} else {
digitalWrite(BLINK_LED, LOW);
blinkLedState = false;
}
// ===== PRINT STATUS =====
if (now - lastPrintTime >= PRINT_INTERVAL) {
lastPrintTime = now;
Serial1.print("Blink: ");
Serial1.print(blinkEnabled ? "ON" : "OFF");
Serial1.print(" | POT raw: ");
Serial1.print(potRaw);
Serial1.print(" | Interval (ms): ");
Serial1.print(blinkInterval);
Serial1.print(" | LED: ");
Serial1.println(blinkLedState ? "HIGH" : "LOW");
}
// ===== HANDLE SERIAL INPUT =====
handleSerialInput();
}
/**
* Read and process Serial commands
*/
void handleSerialInput() {
while (Serial1.available()) {
char c = Serial1.read();
// If newline or carriage return, process command
if (c == '\n' || c == '\r') {
if (bufferIndex > 0) {
serialBuffer[bufferIndex] = '\0';
processCommand(serialBuffer);
bufferIndex = 0;
}
}
// Add character to buffer
else if (bufferIndex < sizeof(serialBuffer) - 1) {
serialBuffer[bufferIndex++] = c;
}
}
}
/**
* Process UART commands
* Commands: ON, OFF, BLINK, NOBLINK, STATUS
*/
void processCommand(char *cmd) {
// Trim whitespace
trimString(cmd);
// Convert to uppercase
toUpperCase(cmd);
if (strlen(cmd) == 0) {
return; // Empty command
}
Serial1.print("CMD: ");
Serial1.println(cmd);
if (strcmp(cmd, "ON") == 0) {
blinkEnabled = true;
blinkLedState = true;
digitalWrite(BLINK_LED, HIGH);
Serial1.println("ACK:ON - Blink enabled");
}
else if (strcmp(cmd, "OFF") == 0) {
blinkEnabled = false;
digitalWrite(BLINK_LED, LOW);
blinkLedState = false;
Serial1.println("ACK:OFF - Blink disabled");
}
else if (strcmp(cmd, "BLINK") == 0) {
blinkEnabled = true;
Serial1.println("ACK:BLINK - Blink started");
}
else if (strcmp(cmd, "NOBLINK") == 0) {
blinkEnabled = false;
digitalWrite(BLINK_LED, LOW);
blinkLedState = false;
Serial1.println("ACK:NOBLINK - Blink stopped");
}
else if (strcmp(cmd, "STATUS") == 0) {
int potRaw = analogRead(POT_PIN);
unsigned long blinkInterval = map(potRaw, 0, 4095, 50, 1000);
Serial1.print("STATUS: Blink=");
Serial1.print(blinkEnabled ? "ON" : "OFF");
Serial1.print(", LED=");
Serial1.print(blinkLedState ? "HIGH" : "LOW");
Serial1.print(", Interval=");
Serial1.print(blinkInterval);
Serial1.println("ms");
Serial1.println("ACK:STATUS");
}
else {
Serial1.print("NACK:UNKNOWN_COMMAND [");
Serial1.print(cmd);
Serial1.println("]");
}
}
/**
* Trim leading and trailing whitespace
*/
void trimString(char *str) {
int start = 0;
int end = strlen(str) - 1;
// Find first non-whitespace
while (start <= end && isspace(str[start])) {
start++;
}
// Find last non-whitespace
while (end >= start && isspace(str[end])) {
end--;
}
// Shift string
int i = 0;
while (start <= end) {
str[i++] = str[start++];
}
str[i] = '\0';
}
/**
* Convert string to uppercase
*/
void toUpperCase(char *str) {
while (*str) {
if (*str >= 'a' && *str <= 'z') {
*str = *str - 32;
}
str++;
}
}