Problema con función millis()

Muy estimados!
Cómo están?

Bueno, tengo aquí algo que no sé por qué actúa como actúa... vean el código.
Esto es en el Arduino UNO.

Código:
#define DistanciaSensores 1

unsigned long Tiempo1,Tiempo2,Tiempo;
float Velocidad;

Tiempo1=millis();
// Aquí hay más código que demora un tiempo en ejecutarse
Tiempo2=millis();

  Tiempo=(Tiempo2-Tiempo1);
  Velocidad=(DistanciaSensores/(Tiempo/1000))*3.6;         // V=d/t en [km/h]
  Serial.print("Velocidad: ");
  Serial.print(Velocidad);
  Serial.println(" [km/h]");
  Serial.print(Tiempo);
Lo que sale, son cosas que no entiendo:
La "velocidad" que aparece en el monitor serial siempre es 0.
El "Tiempo" que aparece en el monitor serial siempre es un número muy grande. Cuando han pasado como 3 segundos, el "Tiempo" que aparece es como 32568 (cualquier cosa en ese orden). Según tutorial de Arduino, eso serían como 32 segundos.

Es decir, a simple vista, la función millis() tira números tan grandes, que hace que la velocidad sea prácticamente cero. Pero... no ha pasado nunca tanto tiempo!

El código que está entremedio, solamente lee dos botones diferentes que yo mismo presiono, e insisto, típicamente dejo pasar 3 segundos aprox, y no tantos como me indica la millis().

Estaré usando mal la función millis() ?
Según la página de Arduino, no...

Alguien sabe lo que pasa aquí?
Muchas gracias!
 
Hola Amigo, bueno has declarado las variables tiempo como tipo long, es de esperarse que obtengas valores con longitud de hasta 16bits.
 
Si, pero en la página de Arduino dice que para guardar valores de millis(), se necesitan declarar variables "unsigned long"... aún así, esto solamente significaría, que estoy trabajando con números pesados (en términos de cantidad de memoria utilizada, o sea, de 32bit), pero eso no significa que los valores que contienen sean necesariamente grandes desde el inicio...

y a la variable "Velocidad" no sé si debo declararla como float o long. Cuando hago esto, sigue siendo cero, pero sin dígitos detrás de la coma, lo cual me parece aún más extraño...

Gracias en todo caso!
 
Bueno, seria conveniente que todas las variables que intervienen en una ecuacion tengan el mismo formato.
Ahora bien, tendras que hacer un seguimiento de los valores que toman las variables "distanciasensores" y "tiempo".
 
Bueno, dejé todas las variables como "unsigned long", lo cual a mi parecer está bien, porque nunca trabajo con signos negativos. Pero lo hice para dejar todas las variables en el mismo formato.

Ahora entonces, hice esto, para rutear los valores de las variables.

Código:
  Serial.println(Tiempo);
  Serial.println(Tiempo1);
  Serial.println(Tiempo2);
  Serial.println(DistanciaSensores);
y sale:

Código:
462
1980
2442
1
lo cual es completamente mentira (excepto el valor "DistanciaSensores" y "Tiempo").
Y es mentira, puesto que entre "Tiempo1" y "Tiempo2" generé mucho menos de 1 segundo, y no más de 1,5 como sale allí.

No sé qué pasa... no pensé que iba a perder tanto tiempo con algo tan simple...
 
Hola, amigos del Foro, gusto en saludarles.
Estoy recién conociendo la función millis de arduino y he tenido algunos problemas para usarla.
Necesito mantener un led intermitente cada un segundo y es posible hacerlo con un programa ejemplo que encontré, pero mi problema es cuando agrego un par de lineas de código para que simultáneamente me encienda un segundo led cada 100 ms y este último led no me funciona.
He intentado de todas forma y no lo logro.
¿Alguien puede ayudarme, por favor?
S
e agradece su voluntad.

D
ejo mi código.
C++:
int LED = 12;
int LED1 = 13;
int ledState = 0;           
unsigned long ComparaMillis = 0;
unsigned long DatoMillis = 0;
int t = 1000;
int boton = A2;

void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(LED1, OUTPUT);
  pinMode(boton, INPUT);
}

void loop()
  {
    DatoMillis = millis();

   if (DatoMillis - ComparaMillis >= t)
   { 
    ComparaMillis = DatoMillis;
       if (ledState == 0)
       {
          ledState = 255;
       }
    else
       {
         ledState = 0;
       }
}
    analogWrite(LED, ledState);

  if (boton == HIGH)
  {
    analogWrite(LED1, HIGH);
    delay(100);
    analogWrite(LED1, LOW);
    delay(100);
  }
}
Disculpen, amigos, también me pasa lo siguiente:
C++:
if (boton == HIGH)
{
analogWrite(LED, HIGH);
delay(1000);
analogWrite(LED, LOW);
delay(1000);
}

if (boton1 == HIGH)
{
analogWrite(LED1, HIGH);
delay(500);
analogWrite(LED1, LOW);
delay(500);
}

if (boton2 == HIGH)
{
analogWrite(LED2, HIGH);
delay(150);
analogWrite(LED2, LOW);
delay(150);
}
¿Cómo puedo reemplazar fácilmente el delay utilizado en el ejemplo por la función millis?
Entiendo que millis permite seguir ejecutando el programa sin desatender lo que está pasando con cada led LED, LED1 y LED2. ¿Verdad?
E
s decir, ¿visualmente cada led funcionaría simultáneamente?

Disculpen mi ignorancia, estoy aprendiendo cómo usar esta sentencia.
M
ejor aún si es posible insertarlo en el mismo ejemplo para poder analizarlo bien para aprender a usarlo, por favor.

M
uchas gracias, amigos, y estaré atento.
 
M

Miembro eliminado 356005

El error está en que no estás leyendo el estado del botón.

La variable boton vale A2, así que

if (boton == HIGH)

Es lo mismo que poner

if (A2 == 1)

Debes hacer una lectura del botón con digitalRead(boton) y luego hacer la comparación. Una forma de hacerlo:

if (digitalRead(boton) == HIGH)
 
Gracias, amigo. Toda la razón.

Disculpa. ¿Será posible apoyarme en alguna rutina que reemplace un delay por millis? Por favor.
Considerando que olvidé la lectura del botón en cada paso, por favor.
C++:
if (boton == HIGH)
{
analogWrite(LED, HIGH);
delay(1000);
analogWrite(LED, LOW);
delay(1000);
}

if (boton1 == HIGH)
{
analogWrite(LED1, HIGH);
delay(500);
analogWrite(LED1, LOW);
delay(500);
}

if (boton2 == HIGH)
{
analogWrite(LED2, HIGH);
delay(150);
analogWrite(LED2, LOW);
delay(150);
}
 
Hola. Lo más importante es que entiendas que pasa con los delay. Mientras esta pasando el tiempo contando el microcontrolador no hace NADA mas.
En internet y en el foro hay muchos ejemplos de cómo usar millis.
Puedes mirar este hilo:
 
Yo iría directo a usar interrupciones, mira las librerías flexitimer .

Milis y micros no deja de ser otra chapuza, menos bestia que delay pero chapuza igualmente, si se te olvida mirar deja de funcionar.

Símil humano: delay es que dejas de hacer TODO y te quedas mirando fijamente el reloj hasta que sea la hora de algo y no haces NADA de NADA mientras.
Usar milis o micros es que vas haciendo tus cosas y miras el reloj de tanto en tanto, si, haces cosas pero lo mismo llegas tarde si se te olvida mirar mientras haces algo.
Usar interrupciones es que actives la alarma del despertador y te olvides, haces tú vida hasta que suene el timbre, haces lo que sea y sigues a lo tuyo hasta que vuelva a sonar.
 
Gracias por los aportes, pero en el caso de las interrupciones arduino atiende la interrupción y vuelve al mismo lugar donde fue interrumpido, entonces creo que no me sirve....

Creo que tiene que ver con las multitareas y en ese caso se debe utilizar millis.... ¿Es lo que creo?
Disculpen insistir. ¿Podrá alguien comentarme cómo puedo reemplazar los delay por millis para atender todas las necesidades de funcionamiento del código?

Muchas gracias. Saludos.
 
M

Miembro eliminado 356005

Puedes hacer que en el bucle haya un único delay() al final de un valor igual al mínimo lapso de tiempo que necesitas en tu programa. Podría ser 100 ms. si todos los tiempos son múltiplos de ese valor.

Luego, por medio de variables controlar lo que debe ocurrir en cada vuelta (son las llamadas variables de estado).

Por ejemplo, si el botón está pulsado y queremos que luzca durante 1 s, ponemos una variable de estado a 10, y saltamos al delay(). Más tarde, preguntamos por el valor de esa variable de estado. Si es mayor que 0, seguimos con el LED encendido, y decrementamos la variable. Si llega a 0, apagamos el LED.

Más o menos así:

C:
unsigned char estado1 = 0;


void loop(void) {

    if (estado1 > 0) {
        estado1--;                    # decrementar

        # ver si hay que apagarlo
        if (estado1 == 0)  digitalWrite(ledPin1, LOW);
    }

    # ...

    if (digitalRead(boton1) == HIGH) {
        estado1 = 10;
        digitalWrite(ledPin1, HIGH);
    }


    # ...

    delay(100);
}
De esta manera puedes meter todos los botones y acciones que quieras. Solo habrá un delay() al final del bucle.
 
Última edición por un moderador:
Muchas gracias Joaquin Ferrero,

disculpe, pero creo no haber explicado bien mi problema y le solicito me tenga paciencia....agradezco mucho su ayuda.

explicare...

analogWrite(LED, HIGH);
delay(t1);
analogWrite(LED, LOW);
delay(t1);

analogWrite(LED1, HIGH);
delay(t2);
analogWrite(LED1, LOW);
delay(t2);

analogWrite(LED2, HIGH);
delay(t3);
analogWrite(LED2, LOW);
delay(t3);

tengo estas secuencias que son parte de un programa mas grande en donde con un teclado 4x4 asigno botones para subir y bajar cada tiempo t1 o t2 o t3 y logro hacerlo sin inconveniente....el problema es que necesito que la secuencia se mantengan funcionando mientras en forma paralela pueda modificar dichos tiempos en el teclado sin tener que esperar a que salga de los delay....creo que es un tema llamado multifuncion que no domino ni entiendo como hacerlo....espero ahora transmitir mi problema de forma correcta....ojala me pueda ayudar....con una solucion..

saludos cordiales y mil disculpas por tanto molestar.
 
Última edición:
Entonces pon el codigo completo para que se entienda, porque todo depende del resto de funciones, variables etc. Lo que vaya a usarse.
Asi que para sugerirte, pon el codigo completo
 
M

Miembro eliminado 356005

Se puede hacer con la solución que te he dado. Todo consiste en saber en qué estado está cada LED. Si encendido o apagado, y durante cuánto tiempo.

En el código que pones, mantienes encendido el LED "LED" durante un tiempo de t1 ms y apagado otro tanto. Y se supone que eso se repite indefinidamente. Bueno, todo consiste en cambiar la forma de pensar: en lugar de dedicarle un tiempo t1 a que un LED esté encendido (o apagado), lo cambiamos a t1/100 momentos que el LED debe estar encendido (o apagado).

De hecho, una parte de la programación multitarea se basa en esto: en vez de darle un tiempo completo a cada tarea, cada tarea solo estará funcionando durante un breve lapso de tiempo.

Algo así:
C:
unsigned int lapso = 100;         // mínimo tiempo de espera entre vueltas del bucle

unsigned char estado1 = 0;        // si estado1 > 0, LED encendido
                                  // si estado1 < 0, LED apagado
unsigned int t1 = 10 * lapso;     // tiempo inicial


void loop(void) {

    if (estado1 > 0) {                        // ¿Sigue encendido?
        estado1--;                            // Sí, decrementar

        if (estado1 <= 0)  {                  // ver si hay que apagarlo
            digitalWrite(ledPin1, LOW);       // lo apagamos
            estado1 = -int(t1/lapso);         // inicio de cuenta en modo apagado
        }
    }
    // Aquí entramos también en el caso estado1 == 0 (primera vuelta)
    else {                                    // Si no está encendido, estará apagado
        estado1++;                            // Sí, incrementar
        
        if (estado1 >= 0)  {                  // ver si hay que encenderlo
            digitalWrite(ledPin1, HIGH);      // lo encendemos
            estado1 = int(t1/lapso);          // inicio de cuenta en modo encendido
        }
    }

    # ... otras cosas ... otros LED ... lectura de la botonera...

    delay(lapso);
}
 
Si no te gustan las interrupciones para los temporizadores, úsalas para el teclado; que el teclado active una interrupción externa.
Así dejas tu código como está y las pulsaciones de las teclas activan las interrupciones que reasignan valores a los tiempos.
Las interrupciones por tiempos cambiantes se pueden hacer sin ningún problema; en cada interrupción se reprograma la siguiente con otro tiempo y listo. Ya tienes todo el tiempo del mundo para lo demás.

¿Es importante que sean precisos los tiempos o tiempos masomenos te valen? Lo digo porque el sistema de JoaquinFerrero acumula error, poco pero acumula.


Del ejemplo de flexitimer tal cual sin tocar:
Si quitas los comentarios verás que el código es mínimo

C++:
char dummyvar; // to get Arduinoi IDE to include core headers properly

/*
  FlexiTimer2:
  Arduino library to use timer 2 with a configurable resolution.
  Based on MsTimer2 by Javier Valencia. It is called FlexiTimer2 because it
  is based on MsTimer2, but offers more flexibility,
  since it has a configurable timer resolution.
  MsTimer2 library: http://www.arduino.cc/playground/Main/MsTimer2

For more details on FlexiTimer2 see:
http://www.arduino.cc/playground/Main/FlexiTimer2
https://github.com/wimleers/flexitimer2

*/

#include <FlexiTimer2.h>

// Switch on LED on and off each half second

#if defined(ARDUINO) && ARDUINO >= 100
const int led_pin = LED_BUILTIN;    // 1.0 built in LED pin var
#else
#if defined(CORE_LED0_PIN)
const int led_pin = CORE_LED0_PIN;    // 3rd party LED pin define
#else
const int led_pin = 13;            // default to pin 13
#endif
#endif

void flash()
{
static boolean output = HIGH;

  digitalWrite(led_pin, output);
  output = !output;
}

void setup()
{
  pinMode(led_pin, OUTPUT);

  FlexiTimer2::set(500, 1.0/1000, flash); // call every 500 1ms "ticks"
  // FlexiTimer2::set(500, flash); // MsTimer2 style is also supported
  FlexiTimer2::start();
}

void loop()
{
}
Tan solo tienes que añadir una línea en la que se reprograme el valor de recarga del timer al principio de la interrupción
C++:
char dummyvar; // to get Arduinoi IDE to include core headers properly

/*
  FlexiTimer2:
  Con tiempos cambiantes
*/

#include <FlexiTimer2.h>

//Enciende y apaga el lLED con tiempos variados

#if defined(ARDUINO) && ARDUINO >= 100
const int led_pin = LED_BUILTIN;    // 1.0 built in LED pin var
#else
#if defined(CORE_LED0_PIN)
const int led_pin = CORE_LED0_PIN;    // 3rd party LED pin define
#else
const int led_pin = 13;            // default to pin 13
#endif
#endif

void flash()
{
static boolean output = HIGH;
  FlexiTimer2::stop();          //No sé si hay que parar el timer para reprogramarlo, a lo mejor funciona sin esto
  FlexiTimer2::set(Aquí poner el tiempo que gustes cada vez , 1.0/1000, flash); // Reprograma el timer al gusto
  FlexiTimer2::start();         //Poner solo si se ha parado mas arriba, lo mismo funciona sin parar el timer
  digitalWrite(led_pin, output);
  output = !output;
}

void setup()
{
  pinMode(led_pin, OUTPUT);

  FlexiTimer2::set(aquí poner el primer tiempo, 1.0/1000, flash); // call every 500 1ms "ticks"
  // FlexiTimer2::set(500, flash); // MsTimer2 style is also supported
  FlexiTimer2::start();
}

void loop()
{
/*

Este es el main que stá completamente vacío para que hagas lo que creas conveniente, leer teclados o lo que te apetezca

*/
}
En este otro hilo se emplea un timmer para hacer un dimmer, y se cambian los valores según se toque un potenciometro.
El código es ínfimo y el gasto de máquina también, tienes todo el tiempo del mundo para hacer "tus cosas", que siempre hacen falta, leer teclados , escribir en displays, "todo lo demás"...
 
Última edición:
muchas gracias por los aportes amigos!!!!!!

quiero preguntar a Joaquin Ferrero.

debo repetir esta rutina segun tantos led quiera encender o apagar y con diferentes variables???....eso?? y al final poner el Delay?

if (estado1 > 0) { // ¿Sigue encendido?
estado1--; // Sí, decrementar

if (estado1 <= 0) { // ver si hay que apagarlo
digitalWrite(ledPin1, LOW); // lo apagamos
estado1 = -int(t1/lapso); // inicio de cuenta en modo apagado
}
}
// Aquí entramos también en el caso estado1 == 0 (primera vuelta)
else { // Si no está encendido, estará apagado
estado1++; // Sí, incrementar

if (estado1 >= 0) { // ver si hay que encenderlo
digitalWrite(ledPin1, HIGH); // lo encendemos
estado1 = int(t1/lapso); // inicio de cuenta en modo encendido
}
}
AQUI PONGO LA MISMA SECUENCIA PARA CONTROLAR OTRO LED???....CON LAS OTRA VARIABLESyy...ESO???

delay(lapso);
}

Muchas gracias y disculpas por mi ignorancia.
probe tal cual y no me funciona....porfa, si me ayudan

necesito poner cuatro secuencias de tiempos diferentes para encender en forma secuencial 4 led sin usar los delay, asi como lo comenta Joaquin Ferrero....es decir con un solo delay pequeño al final

por favor, una vez funcionando lo revisare muy bien para entender la logica utilizada...

gracias y estare atento

saludos
 
Última edición:
M

Miembro eliminado 356005

Sí, cada led debe estar controlado por un conjunto de variables distinto: ledPinX, estadoX, tX, con X variando entre 1 y 4.

Dentro de unas horas pruebo en un Arduino que tengo por aquí, a ver si es correcto lo que he escrito.
 
no me funciona....y lo que necesito es encender en forma secuencial uno tras otro 4 led sin uso de delay y tal como menciona la logica mi amigo Joaquin Ferrero con un solo delay pequeño al final de la logica.....si me ayudan por favor...

agradecido y estare atento....mil disculpas

saludos
gracias Joaquin y si al menos puedes agregar para dos led me ayudaria mucho...
saludos y mil gracias.
 

Temas similares


Arriba