Diferencia entre revisiones de «millis()»
(→Ejemplo 2) |
|||
(No se muestran 25 ediciones intermedias del mismo usuario) | |||
Línea 12: | Línea 12: | ||
== Retornos == | == Retornos == | ||
Número de milisegundos desde que el programa se inició. Numero tipo [[unsigned long]]. | Número de milisegundos desde que el programa se inició. Numero tipo [[unsigned long]]. | ||
+ | |||
+ | == Comentario 1 == | ||
+ | Ya que una variable [[unsigned long]] almacena numero entre 0 y 4,294,967,295 (2^32-1), esta función se vuelve a 0 a los 49.71 días pero eso no representa ningún problema para los cálculos porque al no aceptar numero negativos la variable se da la vuelta por decirlo de alguna manera. | ||
+ | |||
+ | Para que te quede claro simplificaremos con un ejemplo: supongamos que nuestra variable solo soporte 0 a 99 osea 100 '''números'''. Ahora te pregunto cuanto es 0 - 1 ? en nuestro ejemplo la respuesta correcta es 99 porque es el numero que esta antes de 0. Exactamente por el otro extremo el numero que sigue de 99 es 0. A esto se le llama lógica boleana. | ||
+ | |||
+ | Ahora supongamos que quieres prende un foco por 10 '''números''' e inicias el proceso en 22, por lo que preguntas if ('''números''' - tiempo = 10), se apagaría cuando '''números''' llegue a 32 (32 - 22 = 10). Ahora supón que se prende en 95, cuando apagara ? la respuesta es cuando '''números''' llegue a 5 (5 - 95 = 10). | ||
+ | |||
+ | {{Tip|Este comando tarda 21 ciclos de CPU.}} | ||
+ | |||
+ | == Comentario 2 == | ||
+ | Se puede resetear el temporisador de millis() ? | ||
+ | |||
+ | <syntaxhighlight lang="c++"> | ||
+ | extern volatile unsigned long timer0_millis; | ||
+ | unsigned long nuevo_valor = 0; | ||
+ | |||
+ | void setup(){ | ||
+ | //Algo | ||
+ | } | ||
+ | |||
+ | void loop(){ | ||
+ | //Algo | ||
+ | //-------- | ||
+ | |||
+ | //Change Millis | ||
+ | setMillis(nuevo_valor); | ||
+ | } | ||
+ | |||
+ | void setMillis(unsigned long nuevo_valor){ | ||
+ | uint8_t oldSREG = SREG; | ||
+ | cli(); | ||
+ | timer0_millis = nuevo_valor; | ||
+ | SREG = oldSREG; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
== Advertencias == | == Advertencias == | ||
− | Tenga en cuenta el tipo de valor que retorno millis() es [[unsigned long]] y pueden producirse errores lógicos si hacer operaciones aritméticas con otros tipos de datos más pequeños como: [[byte]] o [[int]], incluso los [[long]] con signo pueden producir errores de calculo. | + | * Tenga en cuenta el tipo de valor que retorno '''millis()''' es [[unsigned long]] y pueden producirse errores lógicos si hacer operaciones aritméticas con otros tipos de datos más pequeños como: [[byte]] o [[int]], incluso los [[long]] con signo pueden producir errores de calculo. |
− | millis() funciona mediante una interrupción (la misma de [[micros()]]); por lo tanto, su valor dejará de incrementar durante una rutina de servicio de interrupción (ej.: posterior a [[attachInterrupt()]]), o mientras no se llame a [[interrupts()]] después de llamar a [[noInterrupts()]]. | + | * '''millis()''' funciona mediante una interrupción (la misma de [[micros()]]); por lo tanto, su valor dejará de incrementar durante una rutina de servicio de interrupción (ej.: posterior a [[attachInterrupt()]]), o mientras no se llame a [[interrupts()]] después de llamar a [[noInterrupts()]]. |
+ | |||
+ | == Ejemplo 1 == | ||
+ | Parpadeo del LED incorporado sin usar [[delay()]] | ||
+ | |||
+ | <syntaxhighlight lang="c++"> | ||
+ | unsigned long t; //Es muy importante respetar el tipo de dato | ||
− | == Ejemplo == | + | void setup() { |
− | < | + | pinMode(LED_BUILTIN, OUTPUT); |
− | unsigned long | + | } |
+ | |||
+ | void loop() { | ||
+ | if (milis() - t >= 500){ | ||
+ | t = millis(); //Guarda la hora de cada cambio. | ||
+ | digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //Invierte valor del pin. | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Ejemplo 2 == | ||
+ | Parpadeo cada segundo sin usar [[delay()]]. | ||
+ | |||
+ | <syntaxhighlight lang="c++"> | ||
+ | unsigned long t; //Es muy importante respetar el tipo de dato | ||
+ | const int d = 2000; //Duración en milisegundos del ciclo completo | ||
void setup() { | void setup() { | ||
pinMode(13, OUTPUT); | pinMode(13, OUTPUT); | ||
} | } | ||
void loop() { | void loop() { | ||
− | if ( | + | t = millis(); |
− | + | if (t%d > d/2){ | |
− | digitalWrite(13, | + | digitalWrite(13, HIGH); //Prende LED |
+ | }else{ | ||
+ | digitalWrite(13, LOW); //Apaga LED | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
+ | |||
+ | == Ejemplo 3 == | ||
+ | En este ejemplo simularemos las direcionales de un auto, para lo que tenemos 2 pulsadores y 2 LED. Cada vez que pulso un botón el LED correspondiente parpadea cada 250 ms durante 3 segundos. | ||
+ | |||
+ | <syntaxhighlight lang="c++"> | ||
+ | unsigned long izq,der,ti,td; | ||
+ | bool LEDi,LEDd,actual_i,actual_d,anterior_i,anterior_d; | ||
+ | |||
+ | void setup(){ | ||
+ | pinMode(2, INPUT); //Pulsador derecho | ||
+ | pinMode(3, INPUT); //Pulsador izquierdo | ||
+ | pinMode(8, OUTPUT); //LED izquierdo | ||
+ | pinMode(9, OUTPUT); //LED derecho | ||
+ | } | ||
+ | |||
+ | void loop(){ | ||
+ | //Prende | ||
+ | actual_i = digitalRead(3); | ||
+ | if (actual_i && !anterior_i){ | ||
+ | LEDi = true; | ||
+ | izq = millis(); | ||
+ | } | ||
+ | anterior_i = actual_i; | ||
+ | actual_d = digitalRead(2); | ||
+ | if (actual_d && !anterior_d){ | ||
+ | LEDd = true; | ||
+ | der = millis(); | ||
+ | } | ||
+ | anterior_d = actual_d; | ||
+ | //Parpadea | ||
+ | if (LEDi && (millis()-ti > 250)){ | ||
+ | digitalWrite(8, !digitalRead(8)); | ||
+ | ti = millis(); | ||
+ | } | ||
+ | if (LEDd && (millis()-td > 250)){ | ||
+ | digitalWrite(9, !digitalRead(9)); | ||
+ | td = millis(); | ||
+ | } | ||
+ | //Apaga | ||
+ | if (millis() - izq > 3000){ | ||
+ | LEDi = false; | ||
+ | digitalWrite(8, LOW); | ||
+ | } | ||
+ | if (millis() - der > 3000){ | ||
+ | LEDd = false; | ||
+ | digitalWrite(9, LOW); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | {{Nota|Hay 3 zonas en el código la primera llamada prende, aunque en realidad solo cambia el estado de una variable de tipo flag (LEDi o LEDd) e inicia el tiempo total de 3 seg (ti o td). Una 2da zona donde se hace parpadear los LED mientras la variable flag este en verdadero (LEDi o LEDd). Por ultimo esta la zona de apagado que es cuando se cumplan los 3 segundos.}} | ||
== Vea también == | == Vea también == | ||
− | + | <categorytree mode=all>Funciones tiempo</categorytree> | |
− | == Referencias == | + | == Referencias externa == |
* [https://www.arduino.cc/reference/es/language/functions/time/millis/ Guia de referencia de Arduino] | * [https://www.arduino.cc/reference/es/language/functions/time/millis/ Guia de referencia de Arduino] | ||
+ | * [https://tomblanch.wordpress.com/2013/07/27/resetting_millis/ Resetting the Arduino millis() count] - Tom Blanchard | ||
+ | * [https://www.gammon.com.au/millis millis() desbordamiento, es malo ?] - Nick Gammon | ||
+ | * [https://www.gammon.com.au/blink Como hacer varias cosas a la vez] - Nick Gammon | ||
+ | * [http://www.gammon.com.au/statemachine Maquina de estados] - Nick Gammon | ||
− | [[Category:Funciones]] | + | [[Category:Funciones tiempo]] |
Revisión actual del 00:38 25 jul 2019
Contenido
Descripción
Devuelve el número de milisegundos desde que la placa Arduino empezó a ejecutar el programa actual. Este número se desbordará (volverá a cero), después de aproximadamente 50 días.
Sintaxis
millis();
Parámetros
Nada.
Retornos
Número de milisegundos desde que el programa se inició. Numero tipo unsigned long.
Comentario 1
Ya que una variable unsigned long almacena numero entre 0 y 4,294,967,295 (2^32-1), esta función se vuelve a 0 a los 49.71 días pero eso no representa ningún problema para los cálculos porque al no aceptar numero negativos la variable se da la vuelta por decirlo de alguna manera.
Para que te quede claro simplificaremos con un ejemplo: supongamos que nuestra variable solo soporte 0 a 99 osea 100 números. Ahora te pregunto cuanto es 0 - 1 ? en nuestro ejemplo la respuesta correcta es 99 porque es el numero que esta antes de 0. Exactamente por el otro extremo el numero que sigue de 99 es 0. A esto se le llama lógica boleana.
Ahora supongamos que quieres prende un foco por 10 números e inicias el proceso en 22, por lo que preguntas if (números - tiempo = 10), se apagaría cuando números llegue a 32 (32 - 22 = 10). Ahora supón que se prende en 95, cuando apagara ? la respuesta es cuando números llegue a 5 (5 - 95 = 10).
Tip: Este comando tarda 21 ciclos de CPU.
Comentario 2
Se puede resetear el temporisador de millis() ?
extern volatile unsigned long timer0_millis;
unsigned long nuevo_valor = 0;
void setup(){
//Algo
}
void loop(){
//Algo
//--------
//Change Millis
setMillis(nuevo_valor);
}
void setMillis(unsigned long nuevo_valor){
uint8_t oldSREG = SREG;
cli();
timer0_millis = nuevo_valor;
SREG = oldSREG;
}
Advertencias
- Tenga en cuenta el tipo de valor que retorno millis() es unsigned long y pueden producirse errores lógicos si hacer operaciones aritméticas con otros tipos de datos más pequeños como: byte o int, incluso los long con signo pueden producir errores de calculo.
- millis() funciona mediante una interrupción (la misma de micros()); por lo tanto, su valor dejará de incrementar durante una rutina de servicio de interrupción (ej.: posterior a attachInterrupt()), o mientras no se llame a interrupts() después de llamar a noInterrupts().
Ejemplo 1
Parpadeo del LED incorporado sin usar delay()
unsigned long t; //Es muy importante respetar el tipo de dato
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
if (milis() - t >= 500){
t = millis(); //Guarda la hora de cada cambio.
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //Invierte valor del pin.
}
}
Ejemplo 2
Parpadeo cada segundo sin usar delay().
unsigned long t; //Es muy importante respetar el tipo de dato
const int d = 2000; //Duración en milisegundos del ciclo completo
void setup() {
pinMode(13, OUTPUT);
}
void loop() {
t = millis();
if (t%d > d/2){
digitalWrite(13, HIGH); //Prende LED
}else{
digitalWrite(13, LOW); //Apaga LED
}
}
Ejemplo 3
En este ejemplo simularemos las direcionales de un auto, para lo que tenemos 2 pulsadores y 2 LED. Cada vez que pulso un botón el LED correspondiente parpadea cada 250 ms durante 3 segundos.
unsigned long izq,der,ti,td;
bool LEDi,LEDd,actual_i,actual_d,anterior_i,anterior_d;
void setup(){
pinMode(2, INPUT); //Pulsador derecho
pinMode(3, INPUT); //Pulsador izquierdo
pinMode(8, OUTPUT); //LED izquierdo
pinMode(9, OUTPUT); //LED derecho
}
void loop(){
//Prende
actual_i = digitalRead(3);
if (actual_i && !anterior_i){
LEDi = true;
izq = millis();
}
anterior_i = actual_i;
actual_d = digitalRead(2);
if (actual_d && !anterior_d){
LEDd = true;
der = millis();
}
anterior_d = actual_d;
//Parpadea
if (LEDi && (millis()-ti > 250)){
digitalWrite(8, !digitalRead(8));
ti = millis();
}
if (LEDd && (millis()-td > 250)){
digitalWrite(9, !digitalRead(9));
td = millis();
}
//Apaga
if (millis() - izq > 3000){
LEDi = false;
digitalWrite(8, LOW);
}
if (millis() - der > 3000){
LEDd = false;
digitalWrite(9, LOW);
}
}
Nota: Hay 3 zonas en el código la primera llamada prende, aunque en realidad solo cambia el estado de una variable de tipo flag (LEDi o LEDd) e inicia el tiempo total de 3 seg (ti o td). Una 2da zona donde se hace parpadear los LED mientras la variable flag este en verdadero (LEDi o LEDd). Por ultimo esta la zona de apagado que es cuando se cumplan los 3 segundos.
Vea también
Referencias externa
- Guia de referencia de Arduino
- Resetting the Arduino millis() count - Tom Blanchard
- millis() desbordamiento, es malo ? - Nick Gammon
- Como hacer varias cosas a la vez - Nick Gammon
- Maquina de estados - Nick Gammon