Mostrando entradas con la etiqueta boolean. Mostrar todas las entradas
Mostrando entradas con la etiqueta boolean. Mostrar todas las entradas

domingo, 21 de diciembre de 2014

Programando un dimmer con un pulsador

Hola de nuevo. Espero que no hayáis desmontado el circuito del pulsador usado hasta ahora, porque le vamos a dar una vuelta de tuerca más.
Por si caso el montaje es este:


En el ejemplo de hoy vamos a programar un dimmer que regula la luminosidad de un led. Para ello vamos a aplicar lo que hemos aprendido hasta ahora sobre pulsadores y sobre PWM.
El funcionamiento exacto que queremos conseguir del dimmer es el siguiente:
  • Que una pulsación encienda el led.
  •  Una pulsación prolongada comience a incrementar la luminosidad mientras el pulsador esté pulsado. El incremento se detiene cuando se deja de pulsar.
  • Si se alcanza la máxima luminosidad y se continúa pulsando, la luminosidad se reinicia desde cero y continuaría incrementandose, en forma de bucle.
  • Una pulsación corta apaga el led.

De acuerdo, pues una vez definido el funcionamiento de nuestro circuito, vamos a explicar una de las funciones que nos hará falta para completar el ejercicio.

La función milis ()


Es una función que nos devuelve el tiempo que ha pasado desde que el sketch en curso ha comenzado. Se ha de usar una variable de tipo unsigned long para almacenarlo. El contador se resetea aproximadamente después de 50 días.
Para la aplicación que diseñaremos deberemos medir el  tiempo que ha pasado entre dos pulsaciones. Es decir, no nos interesa el acumulado desde el principio sino el tiempo pasado entre dos intervalos, en concreto, queremos medir lo que dura la pulsación.
Un ejemplo de aplicación:

 duracion = millis() – ultimavez; // Tiempo que ha pasado desde la última vez que se leyó

El algoritmo del programa sería:

- Esperar una pulsación ,
- Cuando recibimos esa pulsación medir el tiempo que permanece pulsado, 
  1. si es menor a 500 ms invertir la salida,
  2. si es mayor y el LED estaba en ON incrementar su luminosidad
- Repetir indefinidamente,

Fácil, ¿no? El programa sería casi un "copy-paste" de lo visto hasta ahora, con la inclusión de la función milis() para medir los intervalos.

Mi propuesta para resolver este ejercicio, es la siguiente:

// Ejemplo 1.7: Dimmer con un pulsador
// El LED se activa con una pulsación corta
// y se apaga con otra pulsación corta
// Si permanece pulsado se incrementa el brillo

const int LED = 9; // pin para el LED
const int PULSADOR = 2; // pin para el pulsador

int valor = 0; // variable para almacenar el pulsador
int old_valor = 0; // estado anterior del pulsador
boolean estado = false; // FLASE = LED apagado TRUE = LED encendido
int brillo = 128; // Variable para el brillo. Inicial a media carga
unsigned long inicio_pulso = 0; // medirá la duracion de la pulsación

void setup() {
pinMode(LED, OUTPUT); // LED es una salida
pinMode(PULSADOR, INPUT); // y PULSADOR es una salida
}
void loop() {
valor = digitalRead(PULSADOR); // Leemos el estado del pulsador
if ((valor == HIGH) && (old_valor == LOW)) // si hay una pulsación
{ 
estado = !estado; // cambiamos el estado del LED,
// ante cualquier pulsacion apagamos si estaba encendido o al reves
inicio_pulso = millis(); //esta funcion cuenta el tiempo pasado
// desde que se inició el sketch. Nos servirá para medir
//la duración de la pulsación
delay(10);// Este delay evita los rebotes del pulsador.
}


// Comprobemos ahora si el interruptor sigue pulsado
if ((valor == HIGH) && (old_valor == HIGH)) {
// Y ahora la condicion que esté pulsado más de 500 ms 
if (estado == 1 && (millis() - inicio_pulso) > 500) {
brillo++;  // esta función es equivalente a brillo=brillo + 1;
delay(10); // "entretenemos" al Arduino para que el brillo
// no se incremente demasiado rapido
if (brillo > 255) // 255 es el maximo de la salida PWM
{ 
brillo = 0; // y si la superamos lo reseteamos a 0
}
}
}
old_valor = valor; // machacamos el valor anterior con el nuevo
if (estado == true) {// Si estado TRUE, encendemos el LED
analogWrite(LED, brillo); // Enciende el LEDelse {
analogWrite(LED, 0); // Apaga el LED
}
}

El programa lo podéis descargar desde aquí.

La particularidas de este sketch respecto al ejercicio con PWM, radica en la parte que mide la longitud de la pulsación. Es esta:

     if ((valor == HIGH) && (old_valor == HIGH)) {

En esta línea le decimos que evalue si estamos todavía pulsando el pulsador,  es decir si el valor anterior y el actual sique siendo 1, estamos todavía pulsando.

if (estado == 1 && (millis() - inicio_pulso) > 500)


Aquí medimos la duración de la pulsación. Si es superior a medio segundo (500ms), comenzamos a subir la luminosidad incrementando la variable que usamos para la señal PWM, Es esta línea,
brillo++;  // esta función es equivalente a brillo=brillo + 1;
Después de esto, simplemente machacamos el valor anterior del pulsador, escribimos la salida, y comenzamos de nuevo el bucle.
Un par de apuntes más sobre el funcionamiento:
  • En condiciones iniciales, la primera vez que se enciende el LED lo hará a mitad de brillo. (brillo 128). Si queremos variar este valor recordad que como máximo puede ser de 255.
  • Mientras no se desconecte el Arduino de la tensión, recordará el último valor que tenía antes de apagar el LED la próxima vez que lo encienda.
  • Si os fijáis en los últimos segundos del video, incluso con el retraso para evitar rebotes, el Arduino recibe una falsa señal y cambia sus estado. En aplicaciones críticas es muy recomendable colocar un condensador en la resistencia de pull-down, tal y como vimos en su día. Podéis repasarlo aquí.
Os dejo el enlace con una muestra del funcionamiento. Nos vemos.

miércoles, 17 de diciembre de 2014

Trabajando con pulsadores II.

Hola de nuevo.

Quedó pendiente de la anterior entrada dos ejercicios propuestos. Vamos a trabajar el segundo de ellos, pulsar para activar el ciclo y pararlo con otra pulsación sobre el mismo interruptor, que es donde reside la gracia.

Para poder activar y desactivar el led, necesitaremos recordar en qué estado se encontraba la salida, de manera que el Arduino cambie su valor en función de cual fuese su estado anterior.

Para almacenar este estado haremos uso de una variable. Las variables,se almacenan en la memoria del Arduino y pueden contener diferentes tipos de datos. Una variable puede ser del tipo número, texto, booleana, un array, etc. El tipo de contenido que quieres almacenar tienes que decidirlo antes de empezarla a usar, y es importante no sobredimensionarla, puesto que en el momento de declararla, reservará ese espacio en la memoria lo uses o no, y como ya hemos comentado nuestro Arduino tiene una memoria RAM realmente limitada.

Las variables de tipo numérico que se pueden utilizar son:

  • byte: almacena un número natural entre 0 y 255 (1 byte).
  • int: almacena un número entero entre -32768 y 32767 (2 bytes).
  • unsigned int: almacena un número natural entre 0 y 65536 (2 bytes).
  • long: almacena un número entero entre -2147483648 y 2147483647 (4 bytes).
  • unsigned long: almacena un número entero entre 0 y 4294967295 (4 bytes).
  • float: almacena un número decimal con un rango entre -3.4028235·1038 y 3.4028235·1038 (4 bytes).
  • const: especifica que la variable definida no podrá ser cambiada durante el programa, siendo siempre un valor constante:
                                      const float pi=3.1415;

Para este ejemplo también usaremos otro tipo de constante de tipo boolean. La variable de tipo booleana solo puede contener dos estados TRUE o FALSE (verdadero o falso), en función de si se cumple o no la condición. La explicaremos más adelante.

Volviendo al ejemplo, debemos definir en este punto cual queremos que sea el comportamiento. Hemos decidido que ,
  • El montaje empiece con el led apagado,
  • El Arduino "vigila" la entrada en espera de una pulsación. Cuando se produce pone                  el LED a "1".
  • A partir de aquí cambiará el estado del led en cada pulsación que se aplique sobre el pulsador.
Para conseguir este comportamiento, el Arduino debe recordar varias cosas. Una es el estado actual del pulsador. Necesitará comparar con el estado anterior, y comprobar si ha habido una pulsación( o si todavía durase la misma).
Y el estado del led, puesto que deberá apagarlo o encenderlo en función de cómo estaba anteriormente.
Por tanto las variables de nuestro montaje podrían ser las siguientes:

  • valor_actual: leerá y almacenará el estado del pulsador
  • valor_anterior: almacenará cada cambio de estado el estado previo
  • estado_led: almacenará el estado del led, encendido o apagado
El sketch quedaría de la siguiente manera:

// Ejemplo 1_6 _Uso de un pulsador para ON-OFF
// Una pulsación activa el LED, que quedará enecendido
// hasta recibir otra pulsación

const int LED = 9; // pin de salida
const int PULSADOR = 2; //pin para el pulsador

int valor = 0; // variable que almacenará la lectura del pulsador
int old_valor = 0; //variable que almacenará la lectura anterior
// del pulsador. Comparandolas sabremos si ha cambiado
int estado_led = 0; // Variable que almacena el estado del LED
// de salida
void setup() 
{
pinMode(LED, OUTPUT); // Programamas el LED como salida
pinMode(PULSADOR, INPUT); // el PULSADOR como entrada
}
void loop()
{
valor = digitalRead(PULSADOR); // leemos el pulsador
// y comprobamos si ha habido un cambio de estado
// comparandolo con el valor anterior

if ((valor == HIGH) && (old_valor == LOW)){
estado_led = 1 - estado_led;
delay(10);
}
old_valor = valor; // El valor leído ahora ya es el "viejo"
// así que lo almacenamos para la siguiente pulsación

if (estado_led == 1)
{
digitalWrite(LED, HIGH); // Encendemos el led si el estado_led es "1"else {
digitalWrite(LED, LOW);
}
}

 Puedes descargar el sketch aquí.

El montaje es el habitual hasta ahora, pero lo recuerdo por si acaso:




La parte que tiene la"chicha" del programa es esta:

if ((valor == HIGH) && (old_valor == LOW)){
estado_led = 1 - estado_led;

Que estamos haciendo, comparamos la lectura del pulsador con la anterior lectura realizada. Si la lectura actual es "1", y la anterior "0", hay una transición o flanco de subida, por lo tanto una pulsación.
Cómo queremos que a cada pulsación conmute el estado de nuestra salida  usamos un truco de programación para  invertir esa variable. Es la línea:

estado_led = 1 - estado_led;

¿Cómo actuaría si sustituyes estado_led por 0 o por 1?,¿o viceversa? Verás que la fórmula invierte, el valor en los dos casos.

¿Funciona? Sí, este programa lo puedes encontrar muy parecido en algún libro sobre el Arduino. Pero hay una forma más "elegante" de hacerlo. Para ello explicaremos las variables Booleanas.

Variables tipo boolean


Este tipo de variable, que ocupa un byte, sólo puede tomar dos valores TRUE o FALSE, (verdadero o falso). Como en nuestro caso  el led solo puede estar encendido o apagado , podríamos definir la variable estado_led como boolena y reescribir el código de la siguiente manera:


// Ejemplo 1_6boolean _Uso de un pulsador para ON-OFF
// Una pulsación activa el LED, que quedará encendido
// hasta recibir otra pulsación

const int LED = 9; // pin de salida
const int PULSADOR = 2; //Entrada para el pulsador

int valor = 0; // variable que almacenará la lectura del pulsador

int old_valor = 0; //variable que almacenará la lectura anterior
// del pulsador. Comparandolas sabremos si ha cambiado
boolean estado_led = false;//En este caso cambiamos la variable int por
// una del tipo boolean. Es la que almacena el estado del LED.La ponemos
// =, o FALSE

void setup() 
{
pinMode(LED, OUTPUT); // Programamas el LED como salida
pinMode(PULSADOR, INPUT); // el PULSADOR como entrada
}
void loop()
{
valor = digitalRead (PULSADOR); // leemos el pulsador
// y comprobamos si ha habido un cambio de estado
// comparandolo con el valor anterior

if ((valor == HIGH) && (old_valor == LOW)){
estado_led = !estado_led;// El símbolo ! invierte el estado
//de la bariable de tipo boolean
delay(20);
}
old_valor = valor; // El valor leído ahora ya es el "viejo"
// así que lo almacenamos para la siguiente pulsación

if ( estado_led == true)//El otro cambio, ahora verificamos si el 
//estado es TRUE que equivale a "1" o HIGH
{
digitalWrite(LED, HIGH); // Enecendemos el led si estado_led TRUE
else {
digitalWrite(LED, LOW);
}
}

Lo puedes descargar desde aquí.

¿Donde están las diferencias?
1.- En la definición de las variables, ahora estado_led es boolean.
      boolean estado_led = false;
2.- En como se invierte la variable estado_led, ahora sé usa el simbolo !.
      estado_led = !estado_led;
3.- Cuando se analiza la condición, ahora se comprueba si es TRUE or FALSE. en lugar de "1" o "0".
      if ( estado == true)

Una nota más antes de dejaros con el video.

Veréis que hay un delay por ahí en medio. Este delay hace las veces de condensador en el montaje de las resistencias PULL-DOWN. Es decir, si lo montáis sin condensador, y no ponéis este delay, notaréis que tiene un funcionamiento errático, puesto que el Arduino es tan rápido en la ejecución del programa que puede leer los rebotes del pulsador. Por tanto lo "entretenemos" con un delay para que pase el rebote del pulsador antes de la siguiente lectura. Si queréis comprobarlo, anular el delay o bajar el tiempo y lo podréis valorar.

Yo he tenido rebotes con valores de delay por debajo de 10ms.

Ahora sí, hasta la siguiente entrada. Nos vemos.