Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
KC868-A128 Arduino Demo: 128-Channel Billie Jean Light Show
#1
Code:
/*
  Made by KinCony IoT: https://www.kincony.com

  KC868-A128 - 128-channel light show for YouTube Shorts.

  Effects:
  1. Meteor chase with an 8-channel tail.
  2. Two lights collide and move apart.
  3. Four synchronized chase groups.
  4. Fill and empty all 128 channels.
  5. Odd/even alternation and a flashing finale.

  Required library:
  PCF8575 by Renzo Mischianti (xreef).

  I2C SDA: GPIO5
  I2C SCL: GPIO16

  Outputs are active LOW.
  Use the onboard LEDs or suitable demonstration lights.
  The sequence includes stages with all outputs ON.
*/

#include <Arduino.h>
#include <Wire.h>
#include <PCF8575.h>

constexpr int I2C_SDA = 5;
constexpr int I2C_SCL = 16;

constexpr uint8_t CHIP_COUNT = 8;
constexpr uint8_t PINS_PER_CHIP = 16;
constexpr int CHANNEL_COUNT = 128;

// Increase this value to slow down every effect.
// Example: 150 means 1.5 times the original duration.
constexpr uint16_t SPEED_PERCENT = 100;

PCF8575 pcf1(0x24, I2C_SDA, I2C_SCL);
PCF8575 pcf2(0x25, I2C_SDA, I2C_SCL);
PCF8575 pcf3(0x21, I2C_SDA, I2C_SCL);
PCF8575 pcf4(0x22, I2C_SDA, I2C_SCL);
PCF8575 pcf5(0x26, I2C_SDA, I2C_SCL);
PCF8575 pcf6(0x27, I2C_SDA, I2C_SCL);
PCF8575 pcf7(0x20, I2C_SDA, I2C_SCL);
PCF8575 pcf8(0x23, I2C_SDA, I2C_SCL);

PCF8575* const outputs[] = {
  &pcf1, &pcf2, &pcf3, &pcf4,
  &pcf5, &pcf6, &pcf7, &pcf8
};

// Store current and requested states to avoid redundant writes.
bool currentState[CHANNEL_COUNT] = {};
bool frame[CHANNEL_COUNT] = {};

void pauseMs(uint32_t duration) {
  delay(duration * SPEED_PERCENT / 100);
}

// Channel indexes are 0-127.
void setChannel(int channel, bool on) {
  if (channel < 0 || channel >= CHANNEL_COUNT) {
    return;
  }

  if (currentState[channel] == on) {
    return;
  }

  outputs[channel / PINS_PER_CHIP]->digitalWrite(
    channel % PINS_PER_CHIP,
    on ? LOW : HIGH
  );

  currentState[channel] = on;
}

void setAll(bool on) {
  for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
    setChannel(channel, on);
  }
}

void clearFrame() {
  for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
    frame[channel] = false;
  }
}

void addLight(int channel) {
  if (channel >= 0 && channel < CHANNEL_COUNT) {
    frame[channel] = true;
  }
}

void showFrame(uint32_t duration) {
  for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
    setChannel(channel, frame[channel]);
  }

  pauseMs(duration);
}

// Move an 8-channel tail in both directions.
void meteorShow() {
  constexpr int TAIL_LENGTH = 8;

  for (int head = 0;
       head < CHANNEL_COUNT + TAIL_LENGTH;
       head++) {
    clearFrame();

    for (int tail = 0; tail < TAIL_LENGTH; tail++) {
      addLight(head - tail);
    }

    showFrame(18);
  }

  for (int head = CHANNEL_COUNT - 1;
       head >= -TAIL_LENGTH;
       head--) {
    clearFrame();

    for (int tail = 0; tail < TAIL_LENGTH; tail++) {
      addLight(head + tail);
    }

    showFrame(14);
  }
}

// Move two 4-channel beams toward the center and back.
void collisionShow() {
  for (int repeat = 0; repeat < 2; repeat++) {
    for (int position = 0; position < 64; position++) {
      clearFrame();

      for (int tail = 0; tail < 4; tail++) {
        addLight(position - tail);
        addLight(CHANNEL_COUNT - 1 - position + tail);
      }

      showFrame(18);
    }

    for (int position = 63; position >= 0; position--) {
      clearFrame();

      for (int tail = 0; tail < 4; tail++) {
        addLight(position - tail);
        addLight(CHANNEL_COUNT - 1 - position + tail);
      }

      showFrame(14);
    }
  }

  setAll(false);
}

// Run four independent 32-channel chase groups.
void fourGroupShow() {
  constexpr int GROUP_SIZE = 32;
  constexpr int TAIL_LENGTH = 4;

  for (int repeat = 0; repeat < 3; repeat++) {
    for (int step = 0; step < GROUP_SIZE; step++) {
      clearFrame();

      for (int group = 0; group < 4; group++) {
        for (int tail = 0; tail < TAIL_LENGTH; tail++) {
          int local = (step - tail + GROUP_SIZE) % GROUP_SIZE;

          // Adjacent groups move in opposite directions.
          if (group % 2 == 1) {
            local = GROUP_SIZE - 1 - local;
          }

          addLight(group * GROUP_SIZE + local);
        }
      }

      showFrame(35);
    }
  }

  setAll(false);
}

// Gradually fill the board, then empty it in the same order.
void fillShow() {
  setAll(false);

  for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
    setChannel(channel, true);
    pauseMs(12);
  }

  pauseMs(350);

  for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
    setChannel(channel, false);
    pauseMs(9);
  }

  pauseMs(150);
}

// Alternate physical channels 1/3/5... and 2/4/6...
void finaleShow() {
  for (int step = 0; step < 8; step++) {
    clearFrame();

    for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
      if ((channel % 2) == (step % 2)) {
        addLight(channel);
      }
    }

    showFrame(120);
  }

  setAll(false);
  pauseMs(150);

  for (int repeat = 0; repeat < 2; repeat++) {
    setAll(true);
    pauseMs(180);

    setAll(false);
    pauseMs(180);
  }
}

void setup() {
  Serial.begin(115200);

  // Configure every output HIGH before initializing the chips.
  for (uint8_t chip = 0; chip < CHIP_COUNT; chip++) {
    for (uint8_t pin = 0; pin < PINS_PER_CHIP; pin++) {
      outputs[chip]->pinMode(pin, OUTPUT, HIGH);
    }
  }

  for (uint8_t chip = 0; chip < CHIP_COUNT; chip++) {
    if (!outputs[chip]->begin()) {
      Serial.printf("PCF8575 group %u initialization failed.\n",
                    chip + 1);

      while (true) {
        delay(1000);
      }
    }
  }

  Serial.println("KC868-A128 light show ready.");
  pauseMs(500);
}

void loop() {
  meteorShow();
  collisionShow();
  fourGroupShow();
  fillShow();
  finaleShow();

  setAll(false);
  pauseMs(500);
}
arduino ino file download:

.zip   Billie-Jean.zip (Size: 1.96 KB / Downloads: 1)
BIN file (you can use esp32 download tool download to ESP32-S3 with address 0x0 then directly to use) download:

.zip   Billie-Jean.ino.merged.zip (Size: 186.24 KB / Downloads: 1)
Reply


Forum Jump:


Users browsing this thread:
1 Guest(s)