Proyecto educativo - Problema al unir dos funciones

Buenas tardes, hace unos meses comencé un proyecto educativo infantil para la etapa de 2 a 3 años, que se trata de un cuento interactivo audiovisual.

La idea principal es simular un bosque de luciérnagas y una tormenta que las espanta. Para hacer pruebas he llevado las dos funciones por separado y las he probado en una tira led de 60 pixels (aunque la corté para que tuviese 8 y me fuese mas sencillo sin necesitar por el momento una fuente externa)

La idea es juntar las dos funciones en un mismo archivo y que se activen al pasar un tiempo en concreto. He intentado de mil maneras, mirando tutoriales pero siempre me da error o solo se activa una de ellas.

La idea sería la siguiente:

  • Al inicializar arduino se activan las luciérnagas (Code 1)
  • Pasados 2 minutos se activa la función tormenta (Code 2)
  • Pasados 2 minutos mas se vuelve a activar las luciérnagas y a los 3 minutos se apaga todo

Estos son los proyectos:
Código Luciérnagas

#include <Adafruit_NeoPixel.h>

#define PIN 6
#define Pixels 8

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(Pixels, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.


float redStates[Pixels];
float blueStates[Pixels];
float greenStates[Pixels];
float fadeRate = 0.70;

void setup() {
 
  strip.begin();
    strip.setBrightness(4);
  strip.show(); // Initialize all pixels to 'off'
  
  for(uint16_t l = 0; l < Pixels; l++) {
    redStates[l] = 0;
    greenStates[l] = 0;
    blueStates[l] = 0;
  }
}

void loop () {
   if (random(8) == 1) {
      uint16_t i = random(Pixels);
      if (redStates[i] < 1 && greenStates[i] < 1 && blueStates[i] < 1) {
        redStates[i] = (255);
        greenStates[i] = (255);
        blueStates[i] = (255);
      }
    }
    
    for(uint16_t l = 0; l < Pixels; l++) {
      if (redStates[l] > 1 || greenStates[l] > 1 || blueStates[l] > 1) {
        strip.setPixelColor(l, redStates[l], greenStates[l], blueStates[l]);
        
        if (redStates[l] > 1) {
          redStates[l] = redStates[l] * fadeRate;
        } else {
          redStates[l] = 0;
        }
        
        if (greenStates[l] > 1) {
          greenStates[l] = greenStates[l] * fadeRate;
        } else {
          greenStates[l] = 0;
        }
        
        if (blueStates[l] > 1) {
          blueStates[l] = blueStates[l] * fadeRate;
        } else {
          blueStates[l] = 0;
        }
        
      } else {
        strip.setPixelColor(l, 0, 0, 0);
      }
    }
    strip.show();
    delay(100);
  
}

Código Tormenta

#include <Adafruit_NeoPixel.h>

#define NEOPIXEL_PIN (6)    // data pin of neopixel strip
#define SECTION_LEN (2)     // number of LEDs to be grouped as one
#define NUM_SECTIONS (2)   // number of LED groups
#define NUM_PIXELS (8)    // total number of LEDS
#define HEARTBEAT_PIN (13)  // output pin for heartbeat LED

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_PIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);

void setup()
{
  pinMode(HEARTBEAT_PIN, OUTPUT);
  pixels.begin();
}

int loop_count = 0;
bool heartbeat = false;
void loop()
{
  // show heartbeat to indicate that we're running
  heartbeat = !heartbeat;
  digitalWrite(HEARTBEAT_PIN, heartbeat);
  loop_count++;

  // run lightning sequence, then delay for a while before repeating
  lightning();
  int delay_long = random(1000, 3000);
  delay(delay_long);
}


// turn off all LEDs
void all_off()
{
  for (int i = 0; i < NUM_PIXELS; i++)
  {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
  }
  pixels.show();
}


const int sec_count = 9;  // the maximum "width" of each lightning sequence
const int seq_count = 9;  // the maximum "duration" of each lightning sequence
// run lightning flash sequence once (call from main loop to repeat)
void lightning()
{
  // randomly select the color of the current lightning sequence
  int r = random(200, 255);
  int g = random(150, 255) - 100;
  int b = random(200, 255);

  // randomly select the order in which the LED sections will flash
  // for the current lightning sequence
  int seq_order[seq_count];
  int seq_max = 0;
  for (int i = 0; i < seq_count; i++)
  {
    seq_order[i] = random(0, sec_count);
    seq_max = max(seq_max, seq_order[i]);
  }
  
  // randomly select the "duration" of the current lightning sequence
  int sections = random(5, seq_count);
  
  // randomly select the starting location of the current lightning sequence
  int seq_start = random(0, NUM_SECTIONS - seq_max);
  
  // loop through each of the chosen sections
  for (int j = 0; j < sections; j++)
  {
    // loop through each LED of the current section
    for (int k = 0; k < SECTION_LEN; k++)
    {
      // turn on the current LED
      int pix_cur = ((seq_start + seq_order[j]) * SECTION_LEN) + k;
      pixels.setPixelColor(pix_cur, pixels.Color(r, g, b));

      // turn off the LEDs of the previous section
      if (j > 0)
      {
        int pix_prv = ((seq_start + seq_order[j - 1]) * SECTION_LEN) + k;
        pixels.setPixelColor(pix_prv, pixels.Color(0, 0, 0));
      }
    }

    // very short (random) delay so we actually see the lightning
    int delay_quick = random(15, 40);
    delay(delay_quick);
    pixels.show();
  }

  all_off();
}

En un principio las luciernagas seran de diferentes colores, pero de momento para simplificar las he dejado en blancas.

Muchísimas gracias de antemano, este proyecto es para un grupo de niños con necesidades especiales que os agradecerán mucho vuestra ayuda.

Un saludo.

Para hacer eso necesariamente tienes que usar la funciones millis() y no la funcion delay(). Considera este simple ejemplo:

void setup() {
   pinMode(12, OUTPUT);     //luciérnagas
   pinMode(13, OUTPUT);     //tormenta
}
void loop() {
   //Hasta 2 min
   if (millis() <= 120000){
      digitalWrite(12, HIGH);
   }
   //Entre 2 y 4 min
   if (millis() > 120000 && millis() <= 240000){
      digitalWrite(12, LOW);
      digitalWrite(13, HIGH);
   }
   //Entre 4 y 7 min
   if (millis() > 240000 && millis() <= 420000){
      digitalWrite(13, LOW);
      digitalWrite(12, HIGH);
   }
   //mas de 7 min
   if (millis() > 420000){
      digitalWrite(12, LOW);
   }
}

Buenos días, gracias por contestar, pero la idea es que todo funcione desde la misma tira de led y desde un solo conector (estoy haciendo una especie de malla con leds neopixels en una tabla de metracrilato ) para así evitar mucho cableado y poderlo transportar mejor y evitar riesgos en el jardín de infancia.

Igualmente lo tendré en cuenta, muchísimas gracias.

La idea es juntar esos dos proyectos en un mismo archivo y que se active un proyecto en el tiempo que comenté.

Un saludo y gracias!

JaviGr:
La idea es juntar esos dos proyectos en un mismo archivo y que se active un proyecto en el tiempo que comenté.

Si eso es lo que te propuse, el código de ejemplo propuesto es para que entiendas primero lo que estas haciendo. Luego de entendido podrías reemplazar:

digitalWrite(12, HIGH);

Por una función de usuario como:

luciernagas();

No he analizado a fondo tu código para saber si requerirás alguna modificación adicional pero en principio es que la sección loop() de cada proyecto la conviertas en función de usuario:

void luciernagas(){
   //Código del proyecto Luciérnagas
}

void tormenta(){
   //Código del proyecto Tormenta
}

Genial, muchísimas gracias! No lo había entendido bien. Un saludo!

Perdonad por la pesadez… al juntar los dos proyectos el void loop me manda un mensaje de error que es el siguiente:

(Resumido, pero es todo el void loop)

test_junto.ino: In function ‘void loop()’:

test_junto:163:26: error: too many arguments to function ‘void luciernagas()’

luciernagas(6, HIGH);

test_junto:168:23: error: too many arguments to function ‘void tormenta()’

tormenta(7, HIGH);

Este es el código que he juntado.

#include <Adafruit_NeoPixel.h>

#define NEOPIXEL_PIN (7)    // data pin of neopixel strip
#define SECTION_LEN (2)     // number of LEDs to be grouped as one
#define NUM_SECTIONS (2)   // number of LED groups
#define NUM_PIXELS (8)    // total number of LEDS
#define HEARTBEAT_PIN (13)  // output pin for heartbeat LED
#define PIN 6
#define Pixels 8

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_PIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(Pixels, PIN, NEO_GRB + NEO_KHZ800);

float redStates[Pixels];
float blueStates[Pixels];
float greenStates[Pixels];
float fadeRate = 0.70;
[b]
void setup() {[/b]

  {
  pinMode(HEARTBEAT_PIN, OUTPUT);
  pinMode(6, OUTPUT);     //luciérnagas
  pinMode(7, OUTPUT);     //tormenta
  pixels.begin();
}
  // put your setup code here, to run once:
  strip.begin();
    strip.setBrightness(4);
  strip.show(); // Initialize all pixels to 'off'
  
  for(uint16_t l = 0; l < Pixels; l++) {
    redStates[l] = 0;
    greenStates[l] = 0;
    blueStates[l] = 0;
  }
}

int loop_count = 0;
bool heartbeat = false;

[b]
void luciernagas(){[/b]

   if (random(8) == 1) {
      uint16_t i = random(Pixels);
      if (redStates[i] < 1 && greenStates[i] < 1 && blueStates[i] < 1) {
        redStates[i] = (255);
        greenStates[i] = (255);
        blueStates[i] = (255);
      }
    }
    
    for(uint16_t l = 0; l < Pixels; l++) {
      if (redStates[l] > 1 || greenStates[l] > 1 || blueStates[l] > 1) {
        strip.setPixelColor(l, redStates[l], greenStates[l], blueStates[l]);
        
        if (redStates[l] > 1) {
          redStates[l] = redStates[l] * fadeRate;
        } else {
          redStates[l] = 0;
        }
        
        if (greenStates[l] > 1) {
          greenStates[l] = greenStates[l] * fadeRate;
        } else {
          greenStates[l] = 0;
        }
        
        if (blueStates[l] > 1) {
          blueStates[l] = blueStates[l] * fadeRate;
        } else {
          blueStates[l] = 0;
        }
        
      } else {
        strip.setPixelColor(l, 0, 0, 0);
      }
    }
    strip.show();
    delay(100);
  
}
[b]
void tormenta()[/b]{

  // show heartbeat to indicate that we're running
  heartbeat = !heartbeat;
  digitalWrite(HEARTBEAT_PIN, heartbeat);
  loop_count++;

  // run lightning sequence, then delay for a while before repeating
  lightning();
  int delay_long = random(1000, 3000);
  delay(delay_long);
}


// turn off all LEDs
void all_off()
{
  for (int i = 0; i < NUM_PIXELS; i++)
  {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
  }
  pixels.show();
}


const int sec_count = 9;  // the maximum "width" of each lightning sequence
const int seq_count = 9;  // the maximum "duration" of each lightning sequence
// run lightning flash sequence once (call from main loop to repeat)

void lightning()
{
  // randomly select the color of the current lightning sequence
  int r = random(200, 255);
  int g = random(150, 255) - 100;
  int b = random(200, 255);

  // randomly select the order in which the LED sections will flash
  // for the current lightning sequence
  int seq_order[seq_count];
  int seq_max = 0;
  for (int i = 0; i < seq_count; i++)
  {
    seq_order[i] = random(0, sec_count);
    seq_max = max(seq_max, seq_order[i]);
  }
  
  // randomly select the "duration" of the current lightning sequence
  int sections = random(5, seq_count);
  
  // randomly select the starting location of the current lightning sequence
  int seq_start = random(0, NUM_SECTIONS - seq_max);
  
  // loop through each of the chosen sections
  for (int j = 0; j < sections; j++)
  {
    // loop through each LED of the current section
    for (int k = 0; k < SECTION_LEN; k++)
    {
      // turn on the current LED
      int pix_cur = ((seq_start + seq_order[j]) * SECTION_LEN) + k;
      pixels.setPixelColor(pix_cur, pixels.Color(r, g, b));

      // turn off the LEDs of the previous section
      if (j > 0)
      {
        int pix_prv = ((seq_start + seq_order[j - 1]) * SECTION_LEN) + k;
        pixels.setPixelColor(pix_prv, pixels.Color(0, 0, 0));
      }
    }

    // very short (random) delay so we actually see the lightning
    int delay_quick = random(15, 40);
    delay(delay_quick);
    pixels.show();
  }

  all_off();
}
[b]void loop(){[/b]

   if (millis() <= 120000){
      luciernagas(6, HIGH);
   }
   //Entre 2 y 4 min
   if (millis() > 120000 && millis() <= 240000){
      luciernagas(6, LOW);
      tormenta(7, HIGH);
   }
   //Entre 4 y 7 min
   if (millis() > 240000 && millis() <= 420000){
      tormenta(7, LOW);
      luciernagas(6, HIGH);
   }
   //mas de 7 min
   if (millis() > 420000){
      luciernagas(6, LOW);
   }
}

Seguramente habré cometido bastantes errores pero llevo algunos meses en esto solo y a veces me atasco un poco, estoy tirando de guias y tutoriales para entender funciones etc…

Siento mucho las molestias causadas, agradecería si es posible que me indicarais los pasos a seguir.

Un saludo.

Estas llamando con parametros a una funcion que has definido sin parametros.

Como te dice jose no debes enviar parámetros a tus funciones de usuario:

void loop(){
   if (millis() <= 120000){
      luciernagas();           //Quita parametros
   }
   //Entre 2 y 4 min
   if (millis() > 120000 && millis() <= 240000){
      tormenta();              //Quita parametros
   }
   //Entre 4 y 7 min
   if (millis() > 240000 && millis() <= 420000){
      luciernagas();           //Quita parametros
   }
}

Muchísimas gracias a todos!

Todo funciona correctamente, ahora solo me queda adaptar el código al cuento y listo.

Un saludo!