usar millis() junto con for() [SOLUCIONADO]

viendo algunos codigos donde usan el for() para crear una secuencia como de encendidos de led, y apagar la misma usan delay() no millis(), yo tampoco lo pude resolver, pongo como ejemplo el de la pagina de referencia de arduino, sacar delay y usar millis, alguien tiene idea como se hace??
ya que en una oportinida lo solucione con switch case, pero ahora no me sirve, preciso si se puede con for loop

//este es un ejemplo y asi encontre muchos for() con delay, pero millis() ninguno.

int PWMpin = 10; 

void setup()
{
  // no setup needed
}

void loop()
{
   for (int i=0; i <= 255; i++){
      analogWrite(PWMpin, i);
      delay(10);
   }
}

Respuesta corta: no se usa for con millis().

Respuesta larga: el uso del for est√° contraindicado o ha de ser ‚Äúmoderado‚ÄĚ si se quiere aprovechar el uso de millis(). El sentido de usar millis() en lugar de delay() es el evitar que el programa se quede ‚Äúmucho tiempo‚ÄĚ ‚Äúentretenido‚ÄĚ en hacer una √ļnica cosa. Y enti√©ndase como ‚Äúmucho tiempo‚ÄĚ todo aquello que supere el milisegundo (incluso menos tiempo puede ser mucho tiempo). Se trata de que haga muchas ‚Äúpeque√Īas cosas‚ÄĚ y que se entretenga muy poco tiempo en cada una de ellas, dando as√≠ la sensaci√≥n de ‚Äúmultitarea‚ÄĚ.

As√≠ que para hacer el ejemplo que has puesto, hay que hacerlo sin usar for. Se trata de que la ejecuci√≥n de la funci√≥n loop() tarde lo menos posible en completarse, para una vez finalizada se vuelva a ejecutar, una y otra vez, indefinidamente. Como la funci√≥n loop() ha de terminarse y volverse a ejecutar muchas veces antes de completar el ciclo de valores que ha de tomar la variable i, esta ha de ser global (tambi√©n se podr√≠a declarar como est√°tica dentro de la funci√≥n loop(), pero para esta ocasi√≥n veo m√°s pedag√≥gico el declararla global y as√≠ de paso no liar m√°s a la gente). Lo mismo ocurre con una de las variables auxiliares que vamos a necesitar, instanteAnterior, la cual ‚Äúrecordar√°‚ÄĚ en qu√© momento cambi√≥ el valor de i por √ļltima vez, para as√≠ poder calcular cuando ha de cambiar de nuevo.

La variable instanteActual puede ser declarada dentro de la funci√≥n loop(), ya que su valor no importa que se ‚Äúpierda‚ÄĚ cuando termine la funci√≥n ya que se inicializa siempre al principio de cada iteraci√≥n.

Calculando la diferencia entre instanteActual e instanteAnterior obtenemos el tiempo que ha transcurrido desde el √ļltimo cambio de la variable i. Si ya han pasado los 10 milisegundos entonces actualizamos la variable instanteAnterior para recordar cu√°ndo se ha hecho este cambio y cambiamos el valor de la variable i. Verificamos entonces si la variable i ya ha ‚Äúterminado el bucle‚ÄĚ viendo si supera el valor m√°ximo, y si es as√≠ la inicializamos a cero. Ya solo resta usar su valor en analogWrite(PWMpin, i) y a esperar a que vuelvan a pasar los siguientes 10 milisegundos.

El código de la adaptación usando millis() y sin usar for:

int PWMpin = 10;
int i = 0;
unsigned long instanteAnterior = 0;

void setup()
{
    // no setup needed
}

void loop()
{
    unsigned long instanteActual = millis();
 ¬† ¬†if ( (instanteActual - instanteAnterior) > 10 ) { // Verificamos si han transcurrido 10 milisegundos desde el √ļltimo cambio
        instanteAnterior = instanteActual; // Guardamos este momento para tomarlo como referencia para el siguiente periodo
        i++; // Pasamos al siguiente valor de i
        if (i > 255) { // Verificamos si se ha sobrepasado el valor final
            i = 0; // Volvemos al valor inicial
        }
        analogWrite(PWMpin, i);
    }
}

Gracias voy a ver si lo puedo implementar en este codigo

int pin;
int matriz[]{8,9,10,11,12};
int cont =5;
int tiempo=100;


void setup()
{
	for(int pin=0; pin<cont; pin++){
pinMode(matriz[pin], OUTPUT);

	}
}

void loop()
{
	for(int pin=0; pin<cont; pin++){

		digitalWrite(matriz[pin],LOW);
		delay(tiempo);
	    digitalWrite(matriz[pin], HIGH);
	    }
}

Adrian_E:
Gracias voy a ver si lo puedo implementar en este codigo…

¬ŅQuieres que te diga c√≥mo quedar√≠a o prefieres intentarlo por tu cuenta?

Te recomiendo intentarlo y que luego publiques el resultado. Si lo logras, estupendo. Y si hay algo que no te funciona, vemos qué es lo que falla. Yo aprendo más de los fallos que de los aciertos. Los aciertos sirven para verificar lo que ya sabes, mientras que los fallos te descubren las cosas que quedan por aprender.

1 Like

como quedaria, amigo??

int pin = 0; // Hay que inicializar el valor de la variable global pin para asegurarnos de que no tiene "basura"
int matriz[] = {8,9,10,11,12};
int cont = 5;
int tiempo = 100;

unsigned long instanteAnterior = 0;

void setup()
{
    // Este bucle no hay porqué cambiarlo, sólo se ejecuta una vez, al "arrancar" el Arduino
    for(int pin=0; pin < cont; pin++){ // Esta variable pin no es la misma que la variable global pin
        pinMode(matriz[pin], OUTPUT);
    }
}

void loop()
{
    unsigned long instanteActual = millis();
    if ( (instanteActual - instanteAnterior) > tiempo ) {
        instanteAnterior = instanteActual;
        digitalWrite(matriz[pin], HIGH); // Esto es lo que se hacía justo después del "delay(tiempo)"
        pin++;
        if (pin >= cont) { // Si pin es mayor o igual a cont es que ha de volver al cero
            pin = 0;
        }
        digitalWrite(matriz[pin], LOW); // Esto es lo que se hacía junsto antes del "delay(tiempo)"
    }
}

F√≠jate que digitalWrite(matriz[pin], LOW) y digitalWrite(matriz[pin], HIGH) ‚Äúparecen estar intercambiados‚ÄĚ. Antes se pon√≠a a nivel alto antes del delay(tiempo) y a nivel bajo justo despu√©s de la pausa. Ahora parecen intercambiados, pero no es as√≠, digamos que ahora la pausa es lo que ‚Äúse hace fuera‚ÄĚ del if, y dentro del if ponemos ‚Äúel anterior‚ÄĚ a nivel alto, pasamos ‚Äúal siguiente‚ÄĚ y lo ponemos a nivel bajo, para luego salir del if y continuar con el loop() hasta que se complete ‚Äúla pausa‚ÄĚ.

Antes ‚Äúel actual‚ÄĚ se pon√≠a a nivel bajo, se hac√≠a ‚Äúla pausa‚ÄĚ, bloqueando todo el loop() sin hacer otra cosa m√°s que esperar y esperar. Transcurrida ‚Äúla pausa‚ÄĚ se pon√≠a ‚Äúel actual‚ÄĚ a nivel alto y se continuaba con el for pasando ‚Äúal siguiente‚ÄĚ hasta que se completaba el bucle para los cinco. Finalmente, despu√©s de tanta espera, continuaba el loop(). Continuaba para volver a empezar todo una vez m√°s.

Espero que lo hayas entendido.

se parece al mio;yo llegue hasta ahi, pero no repite solo lo hace una vez. mirando el tuyo lo mio fueron errores muy de novato

int pin;
int matriz[]{8,9,10,11,12};
int cont =5;
unsigned long valoranterior=0;


void setup()
{
  for(int pin=0;pin<=cont;pin++){

    pinMode(matriz[pin], OUTPUT);

  }
}

void loop()
{
  unsigned long valoractual=millis();
  if(valoractual- valoranterior >100){
    valoranterior = valoractual;
    pin++;

    if ( pin>cont){
      pin=0;

        }
        digitalWrite(matriz[pin],HIGH);
      
  }
}

gracias IgnoranteAbsolut, tengo muchos errores conceptuales, por ahi coloco if(pin>cont) y me olvido de ponerle el = eso me hacia fallar parte del codigo, despues de corregir con el tuyo.

Si se quisiera ‚Äúsimular‚ÄĚ un bucle descendente, for (int pin = cont - 1; pin > 0; pin‚Äď), habr√≠a que inicializar la variable pin con el √≠ndice del √ļltimo elemento del array, que es uno menos que el tama√Īo del array porque el √≠ndice del primer elemento es cero. Y aunque en principio valdr√≠a con cambiar el incremento de pin y el if por:

        pin--;
        if (pin < 0) { // Si pin es de tipo unsigned (sin signo) nunca será menor que cero con lo que la condición nunca se cumplirá
            pin = cont - 1;
        }

Esta forma de hacerlo no funcionar√° si el pin se declara sin signo (unsigned) por que nunca ser√° menor que cero. Si a una variable entera sin signo que vale cero se le resta uno, el valor que da no es menos uno, sino que sufrir√° un desbordamiento ‚Äúpor debajo‚ÄĚ y pasar√° a tener su m√°ximo valor posible. Por ello hay que cambiar esa parte del c√≥digo para que verifique primero qu√© valor tiene y haga el cambio de la variable seg√ļn su valor: decrementar si no es cero o asignarle el valor inicial, cont - 1, si es cero. El c√≥digo completo quedar√≠a as√≠:

// "Simulando" el bucle for (int pin = cont - 1; pin > 0; pin--)
int matriz[] = {8,9,10,11,12};
int cont = 5;
int pin = cont - 1; // <--- Hay que inicializar el valor de la variable global pin con el √≠ndice del √ļltimo elemento del array (el primero es cero)
int tiempo = 100;

unsigned long instanteAnterior = 0;

void setup()
{
    // Este bucle no hay porqué cambiarlo, sólo se ejecuta una vez, al "arrancar" el Arduino
    for(int pin=0; pin < cont; pin++){ // Esta variable pin no es la misma que la variable global pin
        pinMode(matriz[pin], OUTPUT);
    }
}

void loop()
{
    unsigned long instanteActual = millis();
    if ( (instanteActual - instanteAnterior) > tiempo ) {
        instanteAnterior = instanteActual;
        digitalWrite(matriz[pin], HIGH); // Esto es lo que se hacía justo después del "delay(tiempo)"
        if (pin > 0) {      // Si pin es mayor al valor al que se quiere llegar...
            pin--;          // ... decrementamos
        }
        else {              // Si no...
            pin = cont - 1; // ... asignamos el valor del principio del bucle
        }
        digitalWrite(matriz[pin], LOW); // Esto es lo que se hacía justo antes del "delay(tiempo)"
    }
}

Nota: lo m√°s f√°cil, en este caso, habr√≠a sido cambiar el orden de los elementos el array en lugar de hacer tanto cambio. Pero lo uso de ejemplo para tratar de explicar c√≥mo hacer ‚Äúotras cosas‚ÄĚ.

Para completar ‚Äúel ejercicio‚ÄĚ, vamos a hacer algo por el estilo del ‚ÄúKnight Rider‚ÄĚ, en que el bucle va en un sentido y luego en el otro indefinidamente. Para ello necesitamos una nueva variable global que nos dir√° si se debe incrementar o decrementar el valor de pin. Esta nueva variable ser√° paso, y tendr√° el valor uno o menos uno, seg√ļn se tenga que incrementar o decrementar pin. Su valor cambiar√° de signo cuando nos encontremos en cada uno los ‚Äúextremos‚ÄĚ. Esto ocurre cuando pin vale 0 o (cont - 1), es decir, cuando pin est√° indicando el primer o √ļltimo elemento del array. Despu√©s de decidir si paso cambia de valor o no, se suma a pin para que ‚Äúpase al siguiente‚ÄĚ que le toca.

Cuando pin vale cero cambiar√° de signo paso y deber√° de pasar a ser positivo. Por ello, como inicialmente creamos la variable pin con el valor cero, creamos a su vez la variable paso con valor menos uno. As√≠, la primera vez que se eval√ļa el if, paso pasar√° a valer uno.

Se ha cambiado la inicializaci√≥n de cont (mal nombre para indicar que guarda el tama√Īo del array). Ahora, si agregamos o quitamos alg√ļn elemento al array matriz, se calcula autom√°ticamente el valor que ha de tener. Tambi√©n se ha indicado que sean constantes ambas variables, se ha puesto const en la declaraci√≥n de las dos, ya que no han de cambiar los valores de ninguna de ellas.

El programa ha quedado así:

// "Simulando" el bucle for (int pin = cont - 1; pin > 0; pin--)
const int matriz[] = {8, 9, 10, 11, 12};
const int cont = sizeof(matriz) / sizeof(matriz[0]); // De esta forma se calcula autom√°ticamente el n√ļmero de elementos de matriz 
int pin = 0;    // Si empezamos por el cero...
int paso = -1;  // ... asumimos que se ha llegado al cero porque estabamos decrementando.
int tiempo = 100;

unsigned long instanteAnterior = 0;

void setup()
{
    // Este bucle no hay porqué cambiarlo, sólo se ejecuta una vez, al "arrancar" el Arduino
    for(int pin=0; pin < cont; pin++){ // Esta variable pin no es la misma que la variable global pin
        pinMode(matriz[pin], OUTPUT);
    }
}

void loop()
{
    unsigned long instanteActual = millis();
    if ( (instanteActual - instanteAnterior) > tiempo ) {
        instanteAnterior = instanteActual;
        digitalWrite(matriz[pin], HIGH); // Esto es lo que se hacía justo después del "delay(tiempo)"
        if ( (pin <= 0) || (pin >= (cont - 1)) ) {  // Si pin está en uno de los extremos...
            paso = -paso;   // ... cambiamos de sentido
        }
        pin += paso;    // Pasamos al siguiente/anterior
        digitalWrite(matriz[pin], LOW); // Esto es lo que se hacía justo antes del "delay(tiempo)"
    }
}

Gracias voy a tener que practicar para tomarle la mano, te consulto eso lo aprendiste solo con Arduino o vos venís de C++

Vengo del C++

ok gracias por tu ayuda y tu tiempo, como te dije lo voy estudiar ya que me parecio muy interesante la manera de tomar algunas cosas como la opcion de como vos usas matriz ;calcula autom√°ticamente el n√ļmero de elementos de matriz. :slight_smile: :slight_smile:

es aplicable a un for(int i=0;i<=255;i++);

Lo que mas me cuesta entender ya que vengo del for loop es

if ( (pin <= 0) || (pin >= (cont - 1)) ) {  // Si pin está en uno de los extremos...
            paso = -paso;   // ... cambiamos de sentido
        }
        pin += paso;

es aplicable a un for(int i=0;i<=180;i++);

Lo que se pretende hacer es que pin tome los valores 0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2‚Ķ indefinidamente. Con lo cual he de sumar uno hasta que llegue a cuatro y luego restar uno hasta que llegue a cero, para luego sumar uno hasta que llegue nuevamente a cuatro para pasar a restar uno hasta que llegue a cero‚Ķ as√≠ indefinidamente. Aqu√≠ tienes un peque√Īo ejemplo que saca por pantalla lo que digo (tener en cuenta que el valor que se muestra de la variable paso es el que se sum√≥ por √ļltima vez a pin, no es necesariamente el mismo que se le va a sumar en el siguiente paso. Tambi√©n hay que tener claro que sumar -1 es lo mismo que restar uno):

void setup() {
    Serial.begin(9600);
}

int pin = 0;
int paso = -1;

void loop() {
    Serial.print(F("pin = "));
    Serial.print(pin);
    Serial.print(F("    paso = "));
    Serial.println(paso);
    delay(1000);
    if ( (pin == 0) || (pin == 4) ) {
        paso = -paso;
        Serial.println(F("Cambio de signo"));
        delay(1000);
    }
    pin += paso;
}

Si queremos hacer algo semejante con bucles for, lo más fácil sería hacerlo con dos bucles for, uno que incremente y otro que decremente. Sería algo así:

void setup() {
    Serial.begin(9600);
}

void loop() {
    Serial.println(F("Primer bucle"));
    delay(1000);
    for (int pin = 0; pin < 4; pin++) {
        Serial.print(F("pin = "));
        Serial.println(pin);
        delay(1000);
    }
    Serial.println(F("Segundo bucle"));
    delay(1000);
    for (int pin = 4; pin > 0; pin--) {
        Serial.print(F("pin = "));
        Serial.println(pin);
        delay(1000);
    }
}

Nota: el uso de los delay() y los dos programas son s√≥lo para ‚Äúvisualizar‚ÄĚ las dos diferentes soluciones.

donde tengo el error se mueve desparejo >:( >:(

#include <Servo.h>

int tiempo =25;
unsigned long actual;
int inicial=0;


Servo myservo;  

int pos = 0;    

void setup() {
  myservo.attach(9);  
  inicial=millis();
}

void loop() {
  
unsigned long actual=millis();

if(actual-inicial>=tiempo){
    
  

  for (pos = 0; pos <= 180; pos += 1) { 
    myservo.write(pos);              
  }
  for (pos = 180; pos >= 0; pos -= 1) { 
    myservo.write(pos);              
    inicial=actual;
  }
}
}

Creo que est√°s mezclando cosas. Se supone que si usas for es para usar delay(), pero si no quieres usar delay() has de usar millis() y si usas millis() no debes de usar for.

En los ejemplos de antes de ‚Äúsin for‚ÄĚ y ‚Äúcon for‚ÄĚ puse los delay() para que se vieran las salidas por el monitor serie poco a poco. Y eran s√≥lo unos ejercicios para ver un par de diferentes formas de implementar un bucle que podr√≠amos llamar ‚Äúde vaiv√©n‚ÄĚ.

Fíjate que cuando se cumple la condición del tiempo y ha pasado 10 milisegundos, lo que haces en pasouno()es un bucle que va de 0 a 180 diciéndole al servo que se posicione en esos grados, uno detrás de otro, sin pausa, de sopetón. Sin darle tiempo a que se posicione el servo.

 for(int motor=0;motor<=180; motor+=1){
 miservo.write(motor);
 derecha = tiempoactual;
 }

Pero para colmo, cuando han pasado los 10 milisegundos de ‚Äúla derecha‚ÄĚ tambi√©n han pasado los 10 milisegundos de ‚Äúla izquierda‚ÄĚ y en pasodos() pones el mismo servo de 180 a 0 grados con un bucle que no le da ni tiempo de respirar. Quedando finalmente en 0 grados.
Vamos, que se espera a que pasen 10 milisegundos y transcurridos los 10 milisegundos se manda al servo a ponerse de 0 a 180 y de 180 a 0, ‚Äúsin respirar‚ÄĚ, y queda finalmente puesto a 0. Se inicializan los dos contadores de tiempo a la vez, para que transcurridos otros 10 milisegundos vuelva a hacerse lo mismo.

¬ŅTu prop√≥sito es no usar delay(), no bloquear el loop() y que el servo se mueva en pasos de un grado cada 10 milisegundos, de 0 a 180 grados y de 180 a 0 grados continuamente?

Nota: lo que he tachado ya no tiene sentido porque el comentario anterior ha sido editado y el código modificado.

Adrian_E:
donde tengo el error se mueve desparejo >:( >:(

No edites el c√≥digo que ya te hayan comentado otros. Dejas los comentarios sin sentido. A√Īade un nuevo comentario al post con las nuevas modificaciones. El foro no est√° s√≥lo para solucionarte un problema √ļnicamente a ti. Es tambi√©n para ayudar a los que vengan despu√©s. Aparte que se complica el poder ayudarte. ¬ŅO es que voy a tener que revisar todos tus comentarios de este post por si has preguntado otra duda o hay otra modificaci√≥n que quieres que te revise?

si, me equivoque, ese era el del error, el otro fue el primero

Adrian_E:
si, me equivoque, ese era el del error, el otro fue el primero

A√ļn as√≠, en tu c√≥digo contin√ļas mezclando for con millis(). Si usas millis() porque no quieres que se bloquee el loop(), no uses un for para algo que no quieres que se haga lo m√°s r√°pido posible.

No has dicho qué quieres hacer exactamente. Suponiendo que quieras hacer lo que te pregunté, aquí tienes el programa:

#include <Servo.h>

const unsigned long TIEMPO_INCREMENTO = 10;
const int ANGULO_MINIMO = 0;
const int ANGULO_MAXIMO = 180;
const int PIN_SERVO = 9;

unsigned long instanteAnterior = 0;
int angulo = ANGULO_MINIMO;
int incremento = -1;

Servo miServo; 

void setup() {
    miServo.attach(PIN_SERVO); 
}

void loop() {
    unsigned long instanteActual = millis();
    if( (instanteActual - instanteAnterior) >= TIEMPO_INCREMENTO ) {
        instanteAnterior = instanteActual;
        if ( (angulo <= ANGULO_MINIMO) || (angulo >= ANGULO_MAXIMO) ) {
            incremento = -incremento;
        }
        angulo += incremento;
        miServo.write(angulo);             
    }
}

Como puedes ver, no hay ning√ļn for y ni se le espera.