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

domingo, 28 de diciembre de 2014

Dimmer con un potenciometro. analogRead()

Hola a todos.

Vamos explicar en esta entrada como hacer un dimmer más "clásico", esta vez con el uso de un potenciómetro.

Potenciómetro


Un potenciometro no es más que una resistencia cuyo valor es variable. ¿Así de sencillo?

Bueno, más o menos, después se pueden clasificar según su construcción, su aplicación, o su ley de variación. Pero no nos extenderemos aquí. Recomiendo la lectura de algún capítulo de electrónica básica, o la búsqueda en internet. La entrada de wikipedia, es muy generalista pero nos puede dar una idea básica de sus usos.
Para nuestra aplicación usaremos un potenciómetro rotatorio lineal de 10kohms. 

En este supuesto  lo usaremos como un divisor de tensión. Es decir, conectaremos un extremo a 5V (Vcc) y el otro a masa (GND). El cursor lo llevaremos a una entrada analógica del Arduino. 
Con este montaje lo que tendremos en la entrada del Arduino es una tensión que oscilará entre los 0 y los 5V.
Con este voltaje que variaremos a voluntad pilotaremos el led de salida. El esquema del montaje es el siguiente:



analogRead ()


Esta función será la que utilizaremos para hacer funcionar nuestro circuito. Como hemos explicado, hemos realizado un montaje que aplicará un voltaje variable a la entrada del Arduino. Ahora toca leerlo para actuar en consecuencia.
Nuestro Arduino , tiene 6 pins que pueden actuar como un convensor analógico-digital de 10 bits. Son los pins que van del A0..A5. Con una resolución de 10 bits, los valores enteros que obtendremos irán del 0 al 1023. 
La resolución en volts, sera 5V/1024 , o sea de 0,0049V o 4,9mV por unidad.
El Arduino necesita 100us para realizar una lectura , por lo que la frecuencia de muestro que obtendremos como máximo es de 10KHz. 
Existen maneras de configurar de manera diferente estas entradas , pero las veremos más adelante, en otras aplicaciones.
La función solo necesita un parámetro y es el pin de entrada, que en el caso del Arduino UNO, será un número entre 0 y 5.
Un curiosidad es que no hace falta configurar el pin como entrada para realizar lecturas, aunque lo más adecuado y siguiendo con el patrón de programación definido hasta ahora, declararemos siempre los pines en la cabecera del programa.

Si picais este programa, vereis en el IDLE , el valor entero del conversor. Cargar el programa, realizar el montaje expuesto, y dentro de herramientas buscar el monitor serial.

Vereis, como si actuais sobre el potenciometro obtenemos diferentes valores en el monitor serial. Han de estar coprendidos entre 0 y 1023. Es posible que por las tolerancias de los componentes no obtengamos los valores extremos.
El programa lo puedes descargar desde aquí.

//Conversor AD, lee la lectura de un potenciometro
// en el pin A0 y nos estrega la lectura
// En el serial monitor
int POT = 0;   //Cursor potenciometro en pin 0.  
int valor = 0; // variable que almacenara el valor

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

void loop()
{
  valor = analogRead(POT);  // leemos el potenciometro
  Serial.println(valor);    // lo visualizamos en el monitor serial
}

Muy bien, pero nuestro led no se enciende. Esto no debería ser una sorpresa, no hemos definido ningún puerto de salida, ni actuado sobre ningún pin.

Ahora que hemos visto como actua el  conversor AD y hemos obtenido el valor de la señal de entrada, hay que trasladarlo a nuestra salida, el led.

Aquí nos surge otra dificultad. Si recordáis la entrada donde explicábamos el funcionamiento de la modulación por ancho de pulsos ( PWM aquí). La función analogWrite, esperaba un valor entre 0 y 255. 
Resumiendo, tenemos un convensor AD en la entrada de 10bits, y en la salida de tan solo 8 bits, es decir, solo acepta valores entre 0 y 255. No podemos decir que la salida es "igual " a la entrada, hay que escalarla primero. 
Una de las soluciones más extendidas cuando queremos hacer que la salida sea proporcional a la entrada, como en este caso, es dividir la entrada entre 4 antes de la función analogWrite().

Muy bien, ahora con todo este rollo post-turrones y cava, como quedará el programa. Primero el algoritmo de lo que deseamos:


  1. Capturar la entrada analógica con el conversor AD de 10 bits,
  2. Escalarla dividiendo la entrada entre 4, para preparar la señal para el conversor de 8 bits,
  3. Generar la señal de salida, proporcional a la entrada
  4. Cambiar la salida cada vez que lo haga la entrada, indefinidamente.
Ahora sí, mi propuesta para realizar el ejercicio sería la siguiente:


// Ejemplo Dimmer con un potenciometro
// Conectamos el cursor de un potenciometro
// al pin A0, y sus extremos uno a VCC
// y el otro a GND o masa
// EL led de salida al pin 9 a traves de una
// resistencia de 220 ohmioa

const int LED = 9; // pin para el LED
const int POT = 0; // pin para el pulsador
int brillo = 0;
void setup() 
{
pinMode(LED, OUTPUT); // LED es una salida
pinMode(POT, INPUT); // Entrada analogica
}
void loop() {
 brillo =  analogRead(POT); // leemos la caida de tension en el pot
 brillo = brillo/4; // lo escalamos para el conversor DA
 analogWrite (LED,brillo); // escribimos la salida del PWM
}

Lo puedes descargar desde aquí.
En este ejemplo tenemos mayor control sobre la luminosidad del led que con el pulsador, sin embargo  
siempre existirá un consumo de corriente en el potenciómetro por lo que no es el más eficiente energéticamente.
Esta entrada es  más potente de lo que parece, porque ahora podemos leer cualquier entrada analógica, por tanto todo tipo de sensores que den una respuesta analógica, temperatura, humedad, luminosidad, etc, usan este tipo de procedimiento para leer sus señales. En las siguientes entradas experimentaremos con algunos de ellos.

Os dejo un vídeo con el montaje. Casi se me olvidada mis mejores deseos para el 2015.
¡Feliz año nuevo!



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.

sábado, 13 de diciembre de 2014

Otro ejemplo con PWM. Fade-in y fade-out en un led.

Veamos otro ejemplo con el uso de PWM.

El enunciado del ejemplo sería programar un bucle que encienda un led de manera progresiva hasta su máxima luminosidad y lo apague de la misma manera. Pretendemos simular algo parecido al comportamiento de un led en standby de un portátil.
Para ello, utilizaremos el bucle for que ya vimos en pasadas entradas y la función analogWrite().
Usaremos el mismo montaje de la entrada anterior.

El algoritmo del programa  sería algo como esto:
  • Inicializar entradas y salidas.
  • Hacer un bucle ascendente de 0 a 255 (valor máximo y mínimo) que incremente la salida analógica.
  • Hacer un bucle descendente que de 255 a 0 que vaya apagando el led.
  • Repetir indefinidamente...
El programa, perdón el sketch, quedaría:

//Ejemplo 1_5. Encendido y apagado progresivo de un led
// Modificaremos su luminosidad actuando sobre el ciclo de carga
// de la seña de salida

const int LED = 9; // Pin conectado al LED
int i = 0; // Variable que usaremos para el bucle for

void setup() 
{
  pinMode(LED, OUTPUT); // Configuramos el pin como salida
}
void loop()
{
  for (i = 0; i < 255; i++) // bucle de 0 a 254 (fade in).Vamos
                            // incrementando el ciclo de trabajo
  {                         //de 0 a 255     
  analogWrite(LED, i); // esta línea configura el brillo del LED
  delay(10); // Colocamos una espera de 10ms para poder apreciar
             // el efecto. De otro modo sería tan inmediato que
             //no lo veríamos
  }//fin del primer for.   
  for (i = 255; i > 0; i--) { // bucle de 255 a 1 (fade out)
  analogWrite(LED, i); // esta línea configura el brillo del LED
  delay(10); // Espera de 10ms
  }
}



Lo podéis encontrar para descargarlo aquí:

El código es bastante sencillo, así que vamos a añadir un mínimo de complejidad. Vamos a modificar el ejemplo para que sea la activación de un pulsador la que inicie el ciclo.

Cómo sería el algoritmo en esta ocasión:


  • Inicializar entradas y salidas.
  • Leer el estado del pulsador e iniciar el ciclo si se pone a “1”, (se pulsa)
  • Hacer un bucle ascendente de 0 a 255 (valor máximo y mínimo) que incremente la salida analógica.
  • Hacer un bucle descendente que de 255 a 0 que vaya apagando el led.
  • Repetir indefinidamente…

Ok, sencillo ¿no? Solo hemos añadido una línea  en el algoritmo, y ¿en el sketch? Dad le una vuelta antes de seguir leyendo…
…Una vuelta más…
… ¿Ya? Bien pues aquí mi propuesta:


//Ejemplo 1_5b. Encendido y apagado progresivo de un led
// modificando su luminosidad actuando sobre el ciclo de carga
// de la seña de salida. El ciclo lo inicia una pulsación

const int LED = 9; // Pin conectado al LED
const int pulsador = 2 ; //Pin conectado al pulsador
int i = 0; // Variable que usaremos para el bucle for

void setup() 
{
  pinMode(LED, OUTPUT); // Configuramos el pin como salida
  pinMode(pulsador, INPUT); //Configuramos el pin como entrada
}
void loop()
{
    digitalWrite (LED, LOW); //Fijamos la condición inicial del LED
if ( digitalRead(pulsador) == HIGH ) 
  {
    for (i = 0; i < 256; i++) // bucle de 0 a 255 (fade in).Vamos
                            // incrementando el ciclo de trabajo
    {                         //de 0 a 255     
    analogWrite(LED, i); // esta línea configura el brillo del LED
    delay(10); // Colocamos una espera de 10ms para poder apreciar
               // el efecto. De otro modo sería tan inmediato que
               //no lo veríamos
     }//fin del primer for.   
     for (i = 255; i > 0; i--) 
     { // bucle de 255 a 1 (fade out)
     analogWrite(LED, i); // esta línea configura el brillo del LED
     delay(10); // Espera de 10ms
     } // fin del segundo for
    }//Fin condición de la pulsación
    digitalWrite (LED, LOW); //Apagamos el LED en espera de otro pulso
}


¿En qué varía el código? Bien de entrada fijamos que cuando se ejecuta el bucle, el LED esté apagado en espera de recibir una pulsación.

       digitalWrite (LED, LOW);

Seguidamente ponemos una condición con un IF, (ya lo trabajamos aquí), para detectar un flanco positivo en la entrada, (vamos una pulsación):

        if ( digitalRead (pulsador == HIGH ))

Y pasamos a copiar el código anterior. Tan solo debemos recordar salir del bucle volviendo a apagar el LED en espera de otra pulsación.

         digitalWrite (LED, LOW);

El sketch para descarga lo puedes encontrar aquí.

Este montaje tiene muchas posibilidades. Podríamos intentar por que tras la pulsación repita el ciclo n número de veces y se apague.

Otra aún más interesante, que una pulsación comience el ciclo y otra lo apague (con un solo pulsador).  Os dejo con el vídeo del funcionamiento de los dos ejemplos, y en la próxima entrada la solución a estas dos propuestas. Nos vemos.


lunes, 8 de diciembre de 2014

Modulación por ancho de pulsos. PWM en Arduino

Hola de nuevo,

Bueno una semana sin ordenador, así que una semana casi en blanco. Vamos al lío.

Hoy vamos a explicar un nuevo concepto. Para realizar esta entrada necesitaremos:

- 1 x arduino UNO o compatible,
- 1  x Resistencia de 220ohms, si empezáis podéis comprar un lote de varios valores, por ejemplo como este lote de 400 resistencias, por poco más de 2 €
- 1 x Led, del color que más os guste. Os recomiendo un kit de varios colores si todavía estáis empezando,
- 1 x Protoboard, o placa de prototipos, para realizar los montajes de forma sencilla y sin soldaduras.

PWM, (pulse-width modulación), o modulación por ancho de pulsos.

Esta técnica modifica el ciclo de trabajo de una señal periódica, es decir la relación entre el tiempo que está en su parte positiva y el que está en su parte negativa. La fórmula que lo rige:

Donde:


D = \frac{\tau}{T}



D es el ciclo de trabajo
\tau es el tiempo en que la función es positiva (ancho del pulso)
T es el período de la función

Un gráfico de ejemplo:


¿Qué usos se le da a este tipo de señales? Algunos de ellos son:

- Generar señales de audio.
- Variar la velocidad de los motores
- Generar una señal analógica , si se filtra la salida digital
- Generar una señal modulada, para por ejemplo pilotar un LED infrarrojo de un control remoto,
- Variar la luminosidad de un led,

Hay muchas aplicaciones que se puede dar a este tipo de modulación de señales.

Para nuestro ejemplo vamos a diseñar un "dimmer" muy sencillo que ilumine el led al 10%, variando el ciclo de carga de la señal que haremos llegar al led. Lo que hará nuestro algoritmo es encender y apagar el LED, pero con una frecuencia tan alta, que nuestro ojo no percibe el parpadeo, sino una menor luminosidad. Variando el ancho del pulso incrementaríamos el ciclo de carga, pasaría mayor tiempo encendido y por tanto dará la sensación de mayor luminosidad.

El hardware del ejemplo, será nuestro archiconocido LED rojo, conectado al Arduino en su pin 9 a través de una resistencia de 220Ω. Por si hay alguna duda, algo como esto:


El algoritmo de lo que queremos hacer sería:

- programar el led 9 como salida
- Encender el led, ponerlo a "1"
- Esperar durante 100  μs,
- Apagar el led,
- Esperar durante 900 μs,
- Repetir indefinidamente,

Una propuesta para nuestro programa sería esta:


void setup()
{
  pinMode(9, OUTPUT); // Definimos el pin 9 como salida
}
void loop() {
  digitalWrite(9, HIGH); // Ponemos el pin a 1
  delayMicroseconds(100);// Aprox un ciclo de carga del 10% para un 1KHz
  digitalWrite(9, LOW);
  delayMicroseconds(900);
}


Puedes descargarlo aquí.

Ejemplo 1_4 dimmer con delays

El programa es muy sencillo, y podemos realizar pruebas con la luminosidad final del led, tan solo variando los tiempos de delay.


Así si queremos una luminosidad del 50%, generaríamos una onda cuadrada con un ciclo de carga del 50%, es decir colocando 500 y 500 en cada delay.  Para un 25%, 250 y 750 respectivamente , y así para cualquier combinación que queramos. Recuerda volver a cargar el programa después de cada cambio para hacerlo efectivo.

Pros y contras

Dejando de lado la incomodidad de cambiar el ciclo a mano y volver a cargar el programa, esta manera de trabajar generando la onda de esta manera, tiene varios inconvenientes:

- El ciclo de trabajo está calculado aproximadamente  y se vería afectado por cualquier interrupción en el programa, a no ser que las anulemos, y si las deshabitamos...

- El Arduino no podrá hacer otra cosa mientras se ocupe del tren de impulsos, por lo que no resulta excesivamente práctico.

Algo positivo que se me ocurre de esta manera de proceder, es que podemos implementarlo en cualquier salida digital del Arduino.

Veamos entonces otra forma de implementarlo.

analogWrite()

Esta función tiene la siguiente sintaxis:

analogWrite (pin,valor)

Donde los parámetros son:

pin: el pin que usaremos,
valor: ciclo de carga, entre 0 y 255. (0 siempre apagado, 255 siempre encendido, 127 al 50%, etc...)

Esta función genera en el pin especificado una señal cuadrada cuyo ciclo de carga variará entre entre 0 y el 100% (valores entre 0 y 255). En el Arduino UNO los pins que pueden ejecutar esta función son los pins 3, 5, 6, 9, 10 y 11. 

La frecuencia de la señal cuadrada es de aproximadamente 490 Hz, excepto en los pies 5 y 6 que será de aproximadamente 980 Hz.  

Como quedaría el programa entonces:

const int ledPin = 9;
const int DutyCicle = 255;/* Usaremos un valor de 25 para un 10%, 
67 para un 25%, 127 para un 50% y 255 para un 100% */

void setup()
{   
  pinMode(ledPin, OUTPUT); // Definimos el pin 9 como salida 
}
void loop()
{
  analogWrite(ledPin,DutyCicle);//asignamos pin 9 un ciclo carga del 10% aprox
                    //el valor de un 10% estaría entre un valor de 25
}


Puedes descargarlo aquí:

Ejemplo 1_4b dimmer con analogWrite

Ahora podemos variar nuestra luminosidad (ciclo de carga o duty cicle), tan solo variando un parámetro. Prueba los siguientes valores:

- 0, siempre apagado,
- 63, un 25% de luminosidad,
- 127, un 50%
- 255, un 100% siempre encendido,

Recuerda volver a cargar el programa tras el cambio de valor.

Un apunte más, este tipo de control sobre la luminosidad de un LED, (o cualquier tipo de carga) es mucho más eficiente que hacerlo intercalando un potenciómetro, puesto que aquí no hay perdida de potencia en forma de disipación de calor que si se daría en un potenciómetro o carga resistiva.

Un video de ejemplo: