#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
// Pin definitions
const byte dataPin = 2;
const byte clockPin = 3;
const byte latchPin = 4;
// Analog inputs for potentiometers
const int potPins[] = {A0, A1, A2, A3, A4, A5};
const int numPots = NUMELEMENTS(potPins);
// LED control variables
uint8_t data = 0;
uint16_t pulseWidths[] = { 200, 400, 600, 800, 1000, 1200, 2000 };
// Timing
unsigned long timerInterval = 2000;
// Fading LED (7th LED)
const int fadeLedIndex = 6; // zero-based index: 7th LED
int fadeValue = 0;
// --------------------------
// Setup
// --------------------------
void setup() {
Serial.begin(115200);
Serial.println(F("Software PWM with modular structure"));
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);
// Initialize pulse widths
for (int i = 0; i < numPots + 1; i++) {
pulseWidths[i] = 1000;
}
}
// --------------------------
// Main Loop
// --------------------------
void loop() {
unsigned long currentMicros = micros();
// Update potmeter-based brightness
handlePotmeters();
// Update fading LED brightness
handleFadingLed(currentMicros);
// Handle the software PWM logic
handleBrightness(currentMicros);
// Send output to shift register
updateShiftRegister();
}
// Read all potmeters and map to pulse widths
void handlePotmeters() {
for (int i = 0; i < numPots; i++) {
int potValue = analogRead(potPins[i]);
pulseWidths[i] = map(potValue, 0, 1023, 0, 2000);
}
}
// Create a fade effect for the 7th LED
void handleFadingLed(unsigned long currentMicros) {
static unsigned long lastFadeUpdate = 0;
const unsigned long fadeInterval = 5000; // µs between fade updates
if (currentMicros - lastFadeUpdate >= fadeInterval) {
lastFadeUpdate = currentMicros;
fadeValue += 1;
if (fadeValue >= 2000) {
fadeValue = 2000;
}
pulseWidths[fadeLedIndex] = fadeValue;
}
}
// Handle software PWM timing and data bitmask
void handleBrightness(unsigned long currentMicros) {
static unsigned long previousMicros = 0;
if (currentMicros - previousMicros >= timerInterval) {
previousMicros = currentMicros;
data = 0;
// Turn LEDs ON based on pulse widths
for (int i = 0; i < numPots + 1; i++) {
if (pulseWidths[i] > 0) {
data |= (1 << i);
}
}
} else {
// Turn LEDs OFF when their pulse width expires
for (int i = 0; i < numPots + 1; i++) {
if (currentMicros - previousMicros >= pulseWidths[i]) {
data &= ~(1 << i);
}
}
}
}
// Shift out the LED data
void updateShiftRegister() {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, data << 1);
digitalWrite(latchPin, HIGH);
}