Arduino millis reloj desde el principio. Arduino multitarea con la función millis. Usando la función de retardo de arduino

Hola Andrei. Su enfoque para transferir el bagaje de conocimiento y experiencia que ha acumulado es muy interesante. Ayuda mucho a empezar. Bueno, yo, empezando a dominar arduino, tengo ganas de progresar. Además, con ayuda externa, puedo hacerlo más rápido. Entonces: al principio, mi tarea era hacer que un robot se moviera a lo largo de la línea. Lo hice, todo está bien. Pero además, brindándole opciones adicionales, no entendía por qué dejaba de responder correctamente a la línea. Encontré este artículo y entendí por qué.

Ahora tengo una pregunta para usted: en el esquema a continuación y listo, dados los problemas con la demora, ¿debo cambiar a milis donde esté presente esta función? Si es así, ¿entonces entiendo que habrá que rehacer casi todo el boceto? ¿Y no está del todo claro cómo usar milisegundos para medir distancias? Gracias.

//Robot con función de seguimiento de línea blanca

// ********************* Establecer cables de motor ********************* *

int MotorLeftSpeed ​​= 5; // Izquierda (A) VELOCIDAD Motor - ENA

int MotorIzquierdaAdelante = 4; // Motor izquierdo (A) ADELANTE - IN1

int MotorLeftBack = 3; // Izquierda (A) Motor ATRÁS - IN2

int MotorDerechaAdelante = 8; // Derecho (B) Motor ADELANTE - IN3

int MotorDerechaAtrás = 7; // Derecho (B) Motor ATRÁS - IN4

int MotorDerechaVelocidad = 9; // Derecho (B) motor VELOCIDAD - ENB

// ********************Instalar las salidas de los sensores ultrasónicos********************* **** *

inttrigPinL = 14; // configurando el número de salida del sensor ultrasónico activador izquierdo

int echoPinL = 15; // configurando el número de salida del sensor ultrasónico de eco izquierdo

inttrigPinC = 10; // configurando el número de salida del sensor ultrasónico trig central

int echoPinC = 11; // configurar el número de salida del sensor ultrasónico de eco central

inttrigPinR = 12; // configurando el número de salida del sensor ultrasónico activador derecho

int echoPinR = 13; // configurando el número de salida del sensor ultrasónico de eco derecho

// ********************* Configuración de las salidas de los sensores de línea *******************

const int LineSensorLeft = 19; // entrada del sensor de línea izquierda

const int LineSensorRight = 18; // entrada del sensor de línea derecho

intSL; // estado del sensor izquierdo

intSR; // estado del sensor derecho

// ********************* Configuración de la salida de alarmas de luz y sonido ****************

luz int = 2; // configurar el número de salida de la señal de luz

int Zumm = 6; // establece el número de salida del zumbador

int ledState = BAJO; // establecer el estado del LED en esta variable

largo anteriorMillis = 0; // almacenar la hora del último encendido del LED

intervalo largo = 300; // intervalo entre encender/apagar el LED (0.3 segundos)

// ******************** Medición de distancia variable por sensores***************

unsigned int impulseTimeL=0;

unsigned int impulseTimeC=0;

unsigned int impulseTimeR=0;

larga distL=0; // distancia medida por el sensor ultrasónico izquierdo

distancia largaC=0; // distancia medida por el sensor ultrasónico central

larga distR=0; // distancia medida por el sensor Uz derecho

// ******************************* CONFIGURACIÓN *********** ***** ***************

Serial.begin(9600); // iniciar puerto serie (velocidad 9600)

//*************** Ajustar contactos del motor********************

pinMode(MotorDerechaAtrás, SALIDA); // Derecho (B) Motor VOLVER

pinMode(MotorDerechoAdelante, SALIDA); // Derecho (B) Motor ADELANTE

pinMode(MotorLeftBack, SALIDA); // Motor Izquierdo (A) ATRÁS

pinMode(MotorIzquierdaAdelante, SALIDA); // Motor izquierdo (A) ADELANTE

retraso (duración);

//*************** Establecer los contactos del sensor de tiras*******************

pinMode(LineSensorLeft, ENTRADA); // definiendo el pin del sensor de linea izquierda

pinMode(LineSensorRight, ENTRADA); // definiendo el pin del sensor de linea derecho

// ***************Configuración de los modos de salida de los sensores ultrasónicos*************************

pinMode(trigPinL, SALIDA); // configurar el modo de funcionamiento de la salida del sensor ultrasónico activador izquierdo

pinMode(echoPinL, ENTRADA); // configurar el modo de funcionamiento de la salida del sensor ultrasónico de eco izquierdo

pinMode(trigPinC, SALIDA); // configurar el modo de funcionamiento de la salida del sensor ultrasónico trig central

pinMode(echoPinC, ENTRADA); // configurar el modo de funcionamiento de la salida del sensor ultrasónico de eco central

pinMode(trigPinR, SALIDA); // configurando el modo de operación de la salida del sensor ultrasónico trig derecho

pinMode(echoPinR, ENTRADA); // configurando el modo de salida de la salida del sensor ultrasónico de eco derecho

// *************** Establecer contactos para alarmas de luz y sonido*************************** *********

pinMode(Zumm, SALIDA); // configurando el modo de operación de la salida del zumbador

pinMode(Luz, SALIDA); // configurar el modo de funcionamiento de la salida de señalización luminosa

// ******************** Comandos básicos de movimiento ******************

void adelante (int a, int sa) // ADELANTE

analogWrite(MotorRightSpeed, sa);

analogWrite(MotorLeftSpeed, sa);

void right (int b, int sb) // GIRA A LA DERECHA (un lado)

digitalWrite(MotorDerechoAtrás, BAJO);

digitalWrite(MotorLeftBack, BAJO);

digitalWrite(MotorIzquierdoAdelante, ALTO);

analogWrite(MotorLeftSpeed, sb);

void left (int k, int sk) // GIRO A LA IZQUIERDA (un lado)

digitalWrite(MotorDerechoAtrás, BAJO);

digitalWrite(MotorDerechoAdelante, ALTO);

analogWrite(MotorRightSpeed, sk);

digitalWrite(MotorLeftBack, BAJO);

void detener(int f) // DETENER

digitalWrite(MotorDerechoAtrás, BAJO);

digitalWrite(MotorDerechoAdelante, BAJO);

digitalWrite(MotorLeftBack, BAJO);

digitalWrite(MotorIzquierdoAdelante, BAJO);

// ************************** Medida de distancia******************** *

void izmdistL () // medición de distancia por el sensor ultrasónico izquierdo

digitalWrite(trigPinL, ALTO);

digitalWrite(trigPinL, BAJO); // Pulso de 10mS a la salida de activación del sensor ultrasónico para la medición de distancia

impulsoTiempoL = pulsoEn(echoPinL, ALTO); // leer la distancia desde el sensor ultrasónico

distL=impulsoTiempoL/58; // Convertir a centímetros

void izmdistC () // medición de distancia por el sensor ultrasónico central

digitalWrite(trigPinC, ALTO);

digitalWrite(trigPinC, BAJO); // Pulso de 10mS a la salida de activación del sensor ultrasónico para la medición de distancia

impulsoTiempoC = pulsoEn(echoPinC, ALTO); // leer la distancia desde el sensor ultrasónico

distC=TiempoImpulsoC/58; // Convertir a centímetros

void izmdistR () // medición de distancia por el sensor ultrasónico central

digitalWrite(trigPinR, ALTO);

digitalWrite(trigPinR, BAJO); // Pulso de 10mS a la salida de activación del sensor ultrasónico para la medición de distancia

impulsoTiempoR = pulsoEn(echoPinR, ALTO); // leer la distancia desde el sensor ultrasónico

distR=impulsoTiempoR/58; // Convertir a centímetros

// ******************************* BUCLE *********** ***** ****************

// ********************* Modo de seguimiento de LÍNEA ********************* ***

// ********************señalización luminosa y sonora*******************

tono (Zumm, 900); // enciende el sonido a 900 Hz

tono (Zumm, 900); // enciende el sonido a 800 Hz

currentMillis largo sin firmar = millis();

if (millis actual - Millis anterior > intervalo) // comprobar si ha pasado el intervalo requerido, si ha pasado entonces

anteriorMillis = actualMillis; // almacenar la hora del último cambio

if (ledState == LOW) // si el LED está apagado, entonces lo encendemos, y viceversa

ledState = ALTO;

escritura digital (luz, estado de led); // establecer estados de salida para encender o apagar el LED

// ************************** Medida de distancia******************** **** **

Serial.println(distL);

Serial.println(distC);

Serial.println(distR);

if (distL>50 && distC>50 && distR>50) // si la distancia medida es más de 50 centímetros - ir

SL=lectura digital(LineSensorLeft); // lee la señal del sensor del carril izquierdo

SR=lectura digital(LíneaSensorDerecha); // lee la señal del sensor del carril derecho

// ************************ Siguiendo la línea negra ******************* ****

// ROBOT en el carril - vamos recto

if (SL == BAJO & SR == BAJO) // BLANCO - BLANCO - ir RECTO

adelante (10, 100); // ADELANTE (tiempo, velocidad)

// ROBOT comienza a cambiar de carril - rodamos

si no (SL == BAJO & SR == ALTO) // NEGRO - BLANCO - girar a la IZQUIERDA

izquierda (10, 100);// girar a la IZQUIERDA (tiempo, velocidad)

si no (SL == ALTO & SR == BAJO) // BLANCO - NEGRO - gire a la DERECHA

derecha (10, 100); // girar a la DERECHA (tiempo, velocidad)

// TERMINAR - ROBOT ve un carril con ambos sensores

si no (SL == ALTO & SR == ALTO) // NEGRO - NEGRO - STOP

detener(50); // DETENER

else // si la distancia medida es menor o igual al mínimo, detener

La función millis() le permite contar el tiempo transcurrido desde que se inició el programa actual. La función devuelve un valor en el formato "largo sin firmar" y le permite contar valores hasta 50 días desde el momento en que se lanzó el programa. Pasado este tiempo, la cuenta atrás comenzará de nuevo. El siguiente es un ejemplo del uso de la función millis():

mucho tiempo sin firmar; void setup()( Serial.begin(9600); ) void loop()( Serial.print("Tiempo de encendido: "); tiempo = milis(); // almacenar valor de tiempo Serial.println(tiempo); // enviar información a través del retraso del puerto serie (1000); )

En el ejemplo anterior, cada segundo se enviará al monitor de puerto información sobre el tiempo transcurrido desde que se inició el programa. Dado que el tiempo se mide en milisegundos, cada valor subsiguiente diferirá en 1000. La precisión de la lectura depende de la estabilidad del resonador de cuarzo Arduino.

función micros()

La función micros() es similar a la función millis(), la diferencia radica en la precisión de la medición. Usando la función micros(), obtenemos el tiempo transcurrido desde el inicio del programa actual en microsegundos. El contador de microsegundos contados se reiniciará después de 70 minutos. El siguiente es un ejemplo del uso de la función micros():

mucho tiempo sin firmar; void setup()( Serial.begin(9600); ) void loop()( Serial.print("Tiempo desde el inicio: "); tiempo = micros(); Serial.print(tiempo); Serial.println(" ms " ); retraso (1000); )

Al igual que en el ejemplo con la función millis(), aquí cada segundo se enviará información sobre el tiempo medido al monitor del puerto, la única diferencia es que en este caso el tiempo se mide en microsegundos.

función de retraso ()

La función delay() le permite suspender la ejecución del programa actual durante el tiempo especificado en el parámetro. La sintaxis del comando es la siguiente:

//comando retardo(500); //retraso por 0.5 seg //retraso(1000); //retraso por 1s

El tiempo se especifica en milisegundos (1 seg = 1000 ms). Este parámetro puede ser del tipo "unsigned long", que va de 0 a 4294967295. A continuación se muestra un ejemplo del uso del comando delay():

#define ledPin 13 void setup() ( pinMode(ledPin,13); ) void loop() ( digitalWrite(ledPin,HIGH); //encende el retraso del LED(500); //espera 500ms (0.5 seg) digitalWrite( ledPin ,LOW); // apaga el retraso del LED (1000); // espera 1000 ms (1 seg))

En el ejemplo anterior, el LED se enciende durante 0,5 segundos, luego se apaga durante 1 segundo y así sucesivamente hasta que el Arduino se apaga.

Función de retraso de microsegundos ()

La función delayMicroseconds() es una variación de la función delay(). La diferencia radica en el número y la precisión de la sincronización. La función delay() te permite contar el tiempo con una precisión de 1 milisegundo, mientras que delayMicroseconds() te permite contar el tiempo con una precisión de 1 microsegundo.

El valor que se puede especificar en el parámetro varía de 0 a 16383. Para intervalos de tiempo más largos, use la función de retraso() o use delayMicroseconds() varias veces.

#define outPin 8 void setup() ( pinMode(outPin, OUTPUT); // pin 8 como salida ) void loop() ( digitalWrite(outPin, HIGH); // pin 8 high delayMicroseconds(50); // pausa 50 microsegundos digitalWrite(outPin, LOW); // pin 8 low delayMicroseconds(50); // pausa 50 microsegundos)

Este ejemplo genera una onda cuadrada con un período de 100 microsegundos y un 50 % de relleno.

La latencia en Arduino juega un papel muy importante. Sin ellos, incluso el ejemplo más simple de Blink, que parpadea un LED después de un período de tiempo específico, no puede funcionar. Pero la mayoría de los programadores novatos saben poco sobre los retrasos de tiempo y solo usan el retraso de Arduino sin conocer los efectos secundarios de este comando. En este artículo, hablaré en detalle sobre las funciones temporales y las características de su uso en el entorno de desarrollo Arduino IDE.

El Arduino tiene varios comandos diferentes que se encargan de trabajar con el tiempo y las pausas:

  • demora()
  • retrasoMicrosegundos()
  • milisegundos()
  • micros()

Difieren en precisión y tienen sus propias características que deben tenerse en cuenta al escribir código.

Usando la función de retardo de arduino

Sintaxis

El retardo de Arduino es el comando más simple y el más utilizado por los principiantes. De hecho, es un retardo que pausa el programa por la cantidad de milisegundos indicados entre paréntesis. (Hay 1000 milisegundos en un segundo). El valor máximo puede ser 4294967295 ms, que es aproximadamente igual a 50 días. Veamos un ejemplo simple que ilustra cómo funciona este comando.

Configuración vacía() ( pinMode(13, OUTPUT); ) void loop() ( digitalWrite(13, HIGH); // señal pin 13 high delay(10000); // pausa 10000ms o 10 segundos digitalWrite13, LOW); // envía una señal baja al pin 13 delay(10000); // pausa 10000ms o 10 segundos)

en método configuración prescribimos que el pin 13 se utilizará como salida. En la parte principal del programa, primero se aplica una señal alta al pin, luego hacemos un retraso de 10 segundos. En este momento, el programa parece estar suspendido. Luego se da una señal baja y nuevamente un retraso y todo comienza de nuevo. Como resultado, obtenemos que el pin se alimenta alternativamente, luego 5 V, luego 0.

Debe comprender claramente que durante la pausa con el retraso, el programa se suspende, la aplicación no recibirá ningún dato de los sensores. Esta es la mayor desventaja de usar la función de retardo de Arduino. Puede evitar esta limitación utilizando interrupciones, pero hablaremos de esto en un artículo separado.

Ejemplo de retardo con LED parpadeante

Un diagrama de ejemplo para ilustrar cómo funciona la función de retardo.
Puedes construir un circuito con un LED y una resistencia. Luego obtenemos un ejemplo estándar: parpadear un LED. Para hacer esto, en el pin, que designamos como salida, debe conectar el LED con un contacto positivo. Conectamos la pata libre del LED a través de una resistencia de aproximadamente 220 ohmios (un poco más puede ser) a tierra. Puedes determinar la polaridad si miras su interior. La copa grande en el interior está conectada al menos, y la pata pequeña está conectada al más. Si su LED es nuevo, entonces puede determinar la polaridad por la longitud de los cables: una pata larga es una ventaja, una pata corta es una desventaja.

Función de retraso de microsegundos.

Esta función es un análogo completo de retardo, excepto que sus unidades no son milisegundos, sino microsegundos (1000000 microsegundos en 1 segundo). El valor máximo será 16383, que equivale a 16 milisegundos. La resolución es 4, lo que significa que el número siempre será un múltiplo de cuatro. Un fragmento de ejemplo se vería así:

Escritura digital (2, ALTO); // enviar pin 2 high delayMicroseconds(16383); // pausa 16383µs digitalWrite(2, BAJO); // envía una señal baja al pin 2 delayMicroseconds(16383); // pausa 16383µs

El problema con delayMicroseconds es exactamente el mismo que con delay: estas funciones "cuelan" completamente el programa y literalmente se congela por un tiempo. En este momento, es imposible trabajar con puertos, leer información de sensores y realizar operaciones matemáticas. Para los intermitentes, esta opción está bien, pero los usuarios experimentados no la usan para proyectos grandes, ya que tales fallas no son necesarias allí. Por lo tanto, es mucho mejor utilizar las funciones que se describen a continuación.

función de milis en lugar de retraso

La función millis() le permitirá realizar una demora sin demora en el arduino, evitando así las deficiencias de los métodos anteriores. El valor máximo del parámetro millis es el mismo que para la función de retardo (4294967295ms o 50 días).

Usando millis, no detenemos la ejecución de todo el boceto, sino que simplemente indicamos cuánto tiempo el arduino debe simplemente "pasar por alto" exactamente el bloque de código que queremos pausar. A diferencia de delay millis por sí mismo no detiene nada. Este comando simplemente nos devuelve desde el temporizador incorporado del microcontrolador la cantidad de milisegundos que han pasado desde el inicio. Con cada llamada a loop nosotros mismos medimos el tiempo transcurrido desde la última llamada a nuestro código, y si la diferencia de tiempo es menor a la pausa deseada, entonces ignoramos el código. Tan pronto como la diferencia sea mayor que la pausa deseada, ejecutamos el código, obtenemos la hora actual usando los mismos milisegundos y la recordamos: esta hora será el nuevo punto de referencia. En el próximo ciclo, la cuenta atrás ya será desde el nuevo punto y volveremos a ignorar el código hasta que la nueva diferencia entre milis y nuestro valor previamente almacenado alcance de nuevo la pausa deseada.

Retrasar sin demora con millis requiere más código, pero puede hacer parpadear el LED y pausar el boceto sin detener el sistema.

Aquí hay un ejemplo que ilustra claramente el trabajo del comando:

tiempo largo sin firmar; // Variable para almacenar el punto de referencia void setup() ( Serial.begin(9600); ) void loop() ( /* Aquí es donde comienza la ejecución de delay() analog. Calcula la diferencia entre el momento actual y el anterior punto de referencia guardado. Si la diferencia es mayor que Si no, no haga nada */ if (millis() - timing > 10000)( // En lugar de 10000, sustituya el valor de pausa que necesita timing = millis(); Serial. println ( "10 segundos") ; ) )

Primero, introducimos una variable de tiempo, que almacenará el número de milisegundos. De forma predeterminada, el valor de la variable es 0. En la parte principal del programa, verificamos la condición: si el número de milisegundos desde el inicio del microcontrolador menos el número escrito en la variable de tiempo es mayor que 10000, entonces un se realiza una acción para enviar un mensaje al monitor de puerto y el valor de tiempo actual se escribe en la variable. Como resultado de la operación del programa, el mensaje 10 segundos se mostrará en el monitor del puerto cada 10 segundos. Este método le permite hacer parpadear el LED sin demora.

función de micros en lugar de retardo

Esta función también puede retrasar sin usar el comando de retraso. Funciona exactamente igual que millis, pero no cuenta milisegundos, sino microsegundos con una resolución de 4 µs. Su valor máximo es 4294967295 microsegundos o 70 minutos. En caso de desbordamiento, el valor simplemente se restablece a 0, no lo olvide.

Resumen

La plataforma Arduino nos proporciona varias formas de implementar el retraso en nuestro proyecto. Con retraso, puede pausar rápidamente la ejecución del boceto, pero al mismo tiempo bloquear el funcionamiento del microcontrolador. Usar el comando millis te permite deshacerte del retraso en Arduino, pero esto requiere un poco más de programación. Elija el mejor método dependiendo de la complejidad de su proyecto. Por regla general, en bocetos simples y con un retraso de menos de 10 segundos, se utiliza el retraso. Si la lógica de operación es más complicada y se requiere un gran retraso, entonces es mejor usar milis en lugar de retraso.

Si desea "pausar" el microcontrolador, solo necesita ingresar la instrucción de retraso en el lugar correcto en el programa. Pero se convierte en un verdadero obstáculo cuando intentas hacer otras cosas, como rastrear el clic de un botón. En este caso, es necesario implementar una especie de multitarea.



Sí, agregará algunas líneas de código a sus programas, pero esto a su vez lo convertirá en un programador más experimentado y aumentará el potencial de su Arduino. Para hacer esto, solo necesita aprender a usar la función millis.


Debe entenderse que la función de retardo detiene la ejecución de su programa Arduino, por lo que no puede hacer nada más durante este período de tiempo. En lugar de pausar todo nuestro programa durante una cierta cantidad de tiempo, aprenderemos a contar cuánto tiempo ha pasado antes de que se complete la acción. Esto, por supuesto, se hace con la función millis() y algunas variables amigas para almacenar nuestros datos. Para facilitar la comprensión, comenzaremos con el primer boceto del tutorial llamado "Parpadeo", pero en este caso parpadearemos el LED sin demora.


El comienzo de este programa es el mismo que cualquier otro programa estándar de Arduino. Primero viene la declaración de todas las variables necesarias y las líneas de E/S (por ejemplo, la línea 13 para el LED). Aquí también necesitamos una variable entera para almacenar el estado actual del LED. Se establecerá en BAJO porque el estado inicial del LED está apagado. Luego declaramos la variable "previousMillis" de tipo "unsigned long". A diferencia de "int", las variables largas sin signo son de 32 bits, esto es para variables cuyo valor puede volverse muy grande; como tiempo potencial, podemos esperar hasta que se realice una acción. La variable anteriorMillis se utilizará para almacenar la hora en que el LED parpadeó por última vez. También hay de tipo "const long", también es de 32 bits, pero no cambia el valor, es decir, es para constantes (en este caso, para la constante de intervalo). Lo estableceremos en 1000 y lo usaremos como el tiempo de pausa, medido en milisegundos.


const int ledPin = 13; // define la salida del LED // Las variables cambiarán: int ledState = LOW; // ledState se usa para determinar el estado del LED unsigned long beforeMillis = 0; // almacena la hora en que se actualizó por última vez el LED // las constantes no cambiarán: const long interval = 1000; // intervalo de parpadeo en milisegundos void setup() ( // configuración de la línea de salida 13 pinMode(ledPin, OUTPUT); )

Entonces entramos en un bucle infinito. Recuerda que en lugar de un retraso, queremos contar cuánto tiempo ha pasado desde nuestro último parpadeo, en nuestro caso 1000ms. Si ha pasado el tiempo especificado, es hora de cambiar el estado de nuestro LED.


Primero, estableceremos el largo sin firmar "currentMillis" en "millis()", que especifica la hora actual en milisegundos. Esto nos ayudará a saber si la diferencia entre la hora actual y la hora anterior ha superado los 1000ms. Para hacer esto, decimos: "Si el tiempo actual menos el tiempo anterior que parpadeó nuestro LED es mayor o igual a nuestro valor asignado de 1000 ms, almacene el último tiempo de parpadeo como el anterior". Esto nos ayudará a recordar cuánto tiempo ha pasado desde el último parpadeo en la siguiente iteración del bucle. Luego, si el estado del LED es BAJO, hágalo ALTO, de lo contrario, hágalo BAJO. Luego use el comando digitalWrite para imprimir el estado actual en el LED.


void loop() ( unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) ( // almacena la hora del último cambio de estado del LED anteriorMillis = currentMillis; // si el LED está apagado, enciéndalo, y viceversa if (ledState == LOW) ( ledState = HIGH; ) else ( ledState = LOW; ) // Salida LED digitalWrite(ledPin, ledState); ) )

Lo primero que encuentra un principiante que domina Arduino es la propiedad desagradable de la función de retraso (), que bloquea la ejecución del programa. Muchos ejemplos en Internet usan esta función, pero la aplicación práctica de alguna manera sugiere que es mejor prescindir de ella.

Como corresponde a un principiante, inventé una bicicleta e hice mi propia implementación de un retraso sin bloqueo. La tarea era así:

  • Proporcione pseudo multitarea para que los diferentes eventos ocurran en su propio tiempo, en sus propios intervalos y no se bloqueen entre sí.
  • Era conveniente usarlo.
  • Podría diseñarse como una biblioteca e incluirse fácilmente en otros proyectos sin copiar y pegar.
Al ver que la mayoría de las bibliotecas de Arduino están hechas usando OOP, también decidí no presumir y escribí la clase SmartDelay, que se puede obtener de github como un zip para agregar al IDE de Arduino o hacer un clon de git en ~/Arduino/ bibliotecas/

El resultado es este.

#incluir Foo SmartDelay(1000000UL); // en microsegundos void loop () ( if (foo.Now()) ( // El código aquí se ejecuta cada intervalo en microsegundos especificado en el constructor anterior. ) // Otro código )
El método Now() devuelve verdadero si el intervalo ha pasado. En este caso, la cuenta regresiva comienza de nuevo en el mismo intervalo. Es decir, Ahora () cada vez que "recarga" automáticamente.

El clásico parpadeo del LED puede complicarse inmediatamente a dos parpadeos. Por ejemplo, las luces conectadas a los pines 12 y 11 deberían parpadear a intervalos de 1 y 777 ms respectivamente.

#incluir SmartDelay led12 (1000000UL); SmartDelay led11 (777000UL); configuración () ( pinMode(12,SALIDA); pinMode(11,SALIDA); ) byte led12state=0; byte led11estado=0; bucle vacío () ( if (led12.Now()) ( digitalWrite(12,led12state); led12state=!led12state; ) if (led11.Now()) ( digitalWrite(11,led11state); led11state=!led11state; ) )
Puede hacer algo más en el ciclo, el parpadeo de los LED no bloqueará la ejecución de este código.

Está claro que esto no es un reemplazo completo para delay (), que detiene el hilo por un tiempo determinado, siempre debe escribir el programa como un MFA (mecanismo de autómata finito). Es decir, almacene el estado y, dependiendo de él, vaya al lugar correcto en el código.

Versión antigua:

Acción1(); retraso (1000); acción2(); retraso (500); acción3(); ...
Nueva opción:

estado del byte=0; SmartDelayd(); ... cambiar (estado) (caso 0: acción1(); d.Establecer(1000000UL); estado=1; romper; caso 1: si (d.Ahora()) (acción2(); d.Establecer(500000UL) ; state=2; ) break; case 2: if (d.Now()) ( action3(); d.Stop(); state=0; ) break; ) ...
El método Set(interval) establece un nuevo intervalo y devuelve el anterior. Puedes mirar el intervalo usando el método Get();

Stop() detiene el procesamiento y Now() siempre devuelve falso.

Start() se reanuda y Now() comienza a funcionar como de costumbre.

Si necesita ralentizar el conteo del tiempo, pero no detenerlo por completo, existe el método Wait (). Por ejemplo, si el LED 12 está parpadeando, y cuando se presiona el botón, no parpadea, simplemente agregue el siguiente código a loop() en el ejemplo con dos diodos arriba:

Si (digitalRead(9)) led12.Wait(); ...
Entonces, con un nivel de señal alto en la pata 9, el diodo en 12 no parpadeará y continuará cuando aparezca 0 allí.

Cuando una pantalla es dibujada por un "temporizador" de este tipo, por ejemplo, y los botones se procesan en paralelo, entonces puede ser necesario volver a dibujar la pantalla o parte inmediatamente después de presionar el botón, y no esperar a que termine el intervalo. El método Reset() se usa para esto, después de lo cual la siguiente llamada a Now() devolverá verdadero. Por ejemplo:

Pantalla SmartDelay (1000000UL); void loop() ( if (btClick()) display.Reset(); // se hizo clic en el botón, necesitamos dibujar la pantalla. if (display.Now()) screenRedraw(); // dibujar la pantalla. )
De los errores, solo veo que el desbordamiento del contador de microsegundos no se tiene en cuenta, pero por lo demás, sí, necesitamos limpiar el código. No me gusta la forma en que se hace Reset() mientras se piensa.