#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ShiftRegister74HC595.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// ===== Configuración de 74HC595 =====
#define DATA_PIN 23
#define LATCH_PIN 5
#define CLOCK_PIN 18
#define NUM_SHIFT_REGS 4
#define NUM_LEDS (NUM_SHIFT_REGS * 8)
ShiftRegister74HC595<NUM_SHIFT_REGS> sr(DATA_PIN, CLOCK_PIN, LATCH_PIN);
// ===== Botones =====
#define BTN_PLAYPAUSE 32
#define BTN_START 33
#define BTN_SEQ1 25
#define BTN_SEQ2 26
// ===== Variables =====
bool isRunning = false;
int currentSequence = 0;
unsigned long lastUpdate = 0;
unsigned long interval = 150;
int stepIndex = 0;
int blockSize = 2;
int maxBlock = 6;
// ===== Nombres de secuencias =====
const char* sequenceNames[8] = {
"Barrido der",
"Barrido izq",
"Rebote",
"Relleno der",
"Relleno izq",
"Todos ON/OFF",
"Pares/Impares",
"Bloques 2-6"
};
// ===== Funciones de LEDs =====
void clearAll() {
for (int i = 0; i < NUM_LEDS; i++) sr.set(i, LOW);
}
void setLed(int index, bool state) {
if (index >= 0 && index < NUM_LEDS) sr.set(index, state);
}
// ===== Secuencias =====
void doSequence1() {
clearAll();
setLed(stepIndex, HIGH);
stepIndex++;
if (stepIndex >= NUM_LEDS) stepIndex = 0;
}
void doSequence2() {
clearAll();
setLed(NUM_LEDS - 1 - stepIndex, HIGH);
stepIndex++;
if (stepIndex >= NUM_LEDS) stepIndex = 0;
}
void doSequence3() {
clearAll();
setLed(stepIndex, HIGH);
setLed(NUM_LEDS - 1 - stepIndex, HIGH);
stepIndex++;
if (stepIndex >= NUM_LEDS / 2) stepIndex = 0;
}
void doSequence4() {
clearAll();
for (int i = 0; i <= stepIndex; i++) setLed(i, HIGH);
stepIndex++;
if (stepIndex >= NUM_LEDS) stepIndex = 0;
}
void doSequence5() {
clearAll();
for (int i = 0; i <= stepIndex; i++) setLed(NUM_LEDS - 1 - i, HIGH);
stepIndex++;
if (stepIndex >= NUM_LEDS) stepIndex = 0;
}
void doSequence6() {
clearAll();
for (int i = 0; i < NUM_LEDS; i++) setLed(i, (stepIndex % 2 == 0));
stepIndex++;
if (stepIndex >= 2) stepIndex = 0;
}
void doSequence7() {
clearAll();
for (int i = 0; i < NUM_LEDS; i++) {
if (i % 2 == stepIndex % 2) setLed(i, HIGH);
}
stepIndex++;
if (stepIndex >= 2) stepIndex = 0;
}
void doSequence8() {
clearAll();
for (int i = 0; i < blockSize; i++) {
int pos = (stepIndex + i) % NUM_LEDS;
setLed(pos, true);
}
stepIndex += blockSize;
if (stepIndex >= NUM_LEDS) {
stepIndex = 0;
blockSize++;
if (blockSize > maxBlock) blockSize = 2;
}
}
// ===== Mostrar en OLED =====
void updateOLED() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Secuencia: ");
display.println(currentSequence + 1);
display.setCursor(0, 12);
display.print(sequenceNames[currentSequence]);
display.setCursor(0, 28);
display.print("Estado: ");
display.println(isRunning ? "PLAY" : "PAUSE");
display.setCursor(0, 44);
display.print("Paso: ");
display.println(stepIndex);
// Mostrar tamaño de bloque solo en secuencia 8
if (currentSequence == 7) {
display.setCursor(70, 44);
display.print("Bloque: ");
display.println(blockSize);
}
display.display();
}
// ===== Control de secuencias =====
void runSequence() {
switch (currentSequence) {
case 0: doSequence1(); break;
case 1: doSequence2(); break;
case 2: doSequence3(); break;
case 3: doSequence4(); break;
case 4: doSequence5(); break;
case 5: doSequence6(); break;
case 6: doSequence7(); break;
case 7: doSequence8(); break;
}
}
void setup() {
Serial.begin(115200);
pinMode(BTN_PLAYPAUSE, INPUT_PULLUP);
pinMode(BTN_START, INPUT_PULLUP);
pinMode(BTN_SEQ1, INPUT_PULLUP);
pinMode(BTN_SEQ2, INPUT_PULLUP);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("No se encuentra OLED SSD1306");
for (;;);
}
display.display();
delay(1000);
clearAll();
updateOLED();
}
void loop() {
// Botón PLAY/PAUSE
if (digitalRead(BTN_PLAYPAUSE) == LOW) {
delay(200);
isRunning = !isRunning;
updateOLED();
}
// Botón START
if (digitalRead(BTN_START) == LOW) {
delay(200);
isRunning = true;
updateOLED();
}
// Botón SEQ1 (siguiente)
if (digitalRead(BTN_SEQ1) == LOW) {
delay(200);
currentSequence = (currentSequence + 1) % 8;
stepIndex = 0;
blockSize = 2;
updateOLED();
}
// Botón SEQ2 (anterior)
if (digitalRead(BTN_SEQ2) == LOW) {
delay(200);
currentSequence = (currentSequence - 1 + 8) % 8;
stepIndex = 0;
blockSize = 2;
updateOLED();
}
// Secuencias
if (isRunning && millis() - lastUpdate > interval) {
lastUpdate = millis();
runSequence();
updateOLED();
}
}