Alternar dos leds usando una sola salida del microcontrolador

A quien no le ha pasado quedarse sin salidas del microcontrolador y necesitar alternar el encendido de dos led dependiendo del estado, es decir, cuando esté a HIGH la salida del microcontrolador se encienda, por ejemplo, un LED verde y cuando esté a LOW uno rojo.

Soluciones a este problema hay muchas y muy variadas, desde comunicar con otro microcontrolador (un desperdicio para tan poca cosa), usar transistores, o la que os propongo hoy:

Alternar dos leds usando una sola salida del microcontrolador con diodos 1N4007.

ledsalternos

Mediante este sencillo circuito podemos controlar 2 leds dependiendo del estado de salida de la patilla deseada del microcontrolador.

Os dejo código de prueba para Arduino:

int led = 3;

void setup() {

pinMode(led, OUTPUT);
}

void loop() {
digitalWrite(led, HIGH);
delay(500);
digitalWrite(led, LOW);
delay(500);
}

Me ofrezco para formación/colaboración en proyectos tecnológicos

Ofrezco toda mi experiencia profesional en programación y desarrollos tecnológicos para formación personalizada on-line y colaboración en proyetos.

Con mis más de 20 años de experiencia en el desarrollo de software y mi amplio conocimiento de lenguajes como:

  • Harbour / Xailer
  • Java
  • Android
  • PHP
  • Python
  • C++,C
  • POO

bases de datos:

  • MySQL
  • SQLite
  • MS SQL Server
  • Oracle

sistemas operativos:

  • Windows
  • Windows Server
  • Linux
  • Linux Server (Apache, MySQL, PHP, Python)

desarrollo web con:

  • Bootstrap
  • AngularJS
  • DJango
  • HTML5
  • CSS3

y creación de dispositivos con:

  • Arduino
  • Raspberry Pi

me da la oportunidad de porder ofrecer a la comunidad toda mi ayuda tanto en formación personalizada on-line como colaboración en proyectos tecnológicos de cualquier clase.

Si estás interesado, ponte en contacto conmigo por privado o deja un comentario en este mensaje.

IMPORTANTE: He impartido cursos de POO con Xailer a varias personas que han quedado muy satisfechos. También he impartido cursos de como empezar con Xailer y crear tu primera aplicación funcional. He creado procesos en Python de lado del servidor que realizan tareas de sincronizar una aplicación de gestión con Prestashop; o sistemas webservices en PHP para conectar controladoras basadas en Ardunino con un servidor remoto y obtener datos de una base de datos.

Programación PIC y uso (y no abuso) de delay(milisegundos)

Casi todos, cuando empezamos a programar PIC, tenemos la costumbre de usar la función delay(milisegundos) casi para todo. Hemos de tener en cuenta que esta función detiene la ejecución del programa el tiempo que le digamos.

Tomemos, por ejemplo, un programa que nos muestra la hora, no queremos que en cada iteración del programa nos la muestre, sería terriblemente pesado ver salir muchísimas veces el mismo segundo …. Así que lo que queremos es que nos muestre la hora cada vez que pase un segundo.

Casi todos hemos pensado lo mismo, muestro la hora, espero un segundo y la vuelvo a mostar; y para eso usamos delay():

void loop(){
  Serial.println(dimeFecha());
  delay(1000);
}

Si bien es una solución, no es la mejor. Al llegar a la función delay() el programa se detiene 1 segundo (una eternidad en tiempo de proceso del PIC). Supongamos que tenemos otra parte del programa donde necesitamos la hora para hacer alguna cosa, como el programa se ha detenido 1 segundo nada más poner la hora, el dato de la hora llegará con 1 segundo de retraso a resto del programa. Y eso nos puede dar mucho dolor de cabeza.

Para resolver este problema, voy a proponer dos soluciones: una basada en el uso de la función millis() y otra haciendo uso de la hora devuelta por el propio reloj (que para eso esta ¿no? 😉 ).

Usando millis() tendremos el siguiente código:

long tiempo=0;
void setup(){
}
void loop(){
  if(millis()-tiempo>1000){
    tiempo=millis();
    Serial.println(dimeFecha());
  }
}

¿Qué hace este programa?

  • Establece la variable global tiempo a 0.
  • En el bucle loop() comprueba si los milisegundos transcurridos (millis()) menos el tiempo guardado es mayor a 1000 milisegundos (1 s).
  • En caso que se cumpla la condición, se guarda el valor actual de millis() en la variable tiempo y se muestra la hora.
  • El programa continúa sin detenerse para nada.

Podemos comprobar que es una solución bastante elegante y simple; pero hay algo que debemos tener en cuenta: la función millis() cuenta el tiempo desde que empezó a ejecutarse el programa en ciclos de procesador, es decir, no va sincronizada con el reloj, por lo que al mostrarse la hora llevará un desfase con el tiempo real.

Para solucionar este último inconveniente propongo la solución de usar el propio reloj para mostrar la hora cada segundo, aquí está el código:

int segundos=0;
void setup(){
}
void loop(){
  DateTime ahora;
  ahora=RTC.now();
  if(ahora.second() != segundos){
    segundos=ahora.second();
    Serial.println(dimeFecha());
  }
}

Podemos comprobar que el funcionamiento de este programa es análogo al anterior, pero con la particularidad de que se usa el reloj para controlar cuando se va a imprimir la hora.

Como nota final, comentaros que es muy importante tener en cuenta el uso (o abuso) de la función delay() ya que en la mayoría de los casos un pic nos da la impresión de ir lento y no caemos en la cuenta de que somos nosotros los que estamos haciendo que se pare.

Por otro lado, la función dimeFecha() es esta:

/*
FUNCION PARA OBTENER LA FECHA EN MODO TEXTO
Devuelve: DD-MM-AAAA HH:MM:SS
*/
String dimeFecha(){
  
    char fecha[19];
    DateTime now = RTC.now(); //Obtener fecha y hora actual.

    int dia = now.day();
    int mes = now.month();
    int anio = now.year();
    int hora = now.hour();
    int minuto = now.minute();
    int segundo = now.second();

    sprintf( fecha, "%.2d/%.2d/%.4d %.2d:%.2d:%.2d", dia, mes, anio, hora, minuto, segundo);
    return String( fecha );
}

Hasta el próximo. Espero vuestros comentarios.

DS1307: solución de problemas.

Ayer publicaba el artículo “Tiny RTC y pérdida de la hora“, hoy voy a hablaros sobre como usar el RTC DS1307 y como implementarlo para que funcione bien. El integrado, muy conocido por todos, es muy fácil de instalar en cualquier pic que admita comunicación I2C (SDA/SCL) y lleva el siguiente partillaje:

  • Pines 1 y 2: oscilador de cuarzo de 32.768 KHz.
  • Pin 3: +Bat (positivo de la pila de respaldo CR2032)
  • Pin 4: GND
  • Pin 5: SDA
  • Pin 6: SCL
  • Pin 7: SQW/OUT
  • Pin 8: +5V

En todos los esquemas y montajes que he visto, dice que si no se va a usar una batería recargable, que se conecte tal y como se describe, pero en cuanto enchufamos nuestro reloj y queremos ver la hora recibimos cosas raras, como por ejemplo “165/165/165 165:165:65” ¿os suena, verdad?. Además el software del PIC nos dice que el reloj NO FUNCIONA.

¿Eh? ¿Qué pasa? Hemos conectado todo tal y como dice el esquema, revisamos una y mil veces y sigue fallando. De pronto ¿que pasa si le quito la pila CR2032? ¡¡¡FUNCIONA!!! Venga, estaría mal la pila, y probamos con una y otra y otra más….. Y el fallo sigue ahí.

¿Qué le pasa a esto? Ya estamos locos y mo sabemos que hacer. A buscar en la web a ver que hay. Nada. No hay nada. Solo gente quejándose de lo mismo y los mismos esquemas una y otra vez. ¿Será posible que no vamos a conseguir poner el reloj en marcha? ¿Será que es de los chinos y es muy malo? Desesperado lo dejamos sin la batería de respaldo y lo ponemos a funcionar, si nuestra instalación no es crítica con el tema de la hora, no pasa nada: apañamos unos botones para cambiar la hora y ya lo iremos ajustando cuando sea necesario.

Es una solución, sí; pero NO ES LA SOLUCIÓN. En la hoja de datos del fabricante indica que se le puede poner una pila de respaldo para que el reloj no pierda la hora ¿acaso el fabricante no sabe lo que dice? ¡¡¡Anda ya!!!

Personalmente no me dejo ganar por algo así, puede que aparque el problema a un lado y lo deje un tiempo (no es bueno obsesionarse) mietras hago otras cosas. De repente una noche, cansado y medio dormido, mientras ves una (patética) serie de TV antes de irte a dormir, se enciende un LED de alto brillo en el cerebro: ¿será la solución poner …..? ¡¡¡No tengo aquí componentes para probarlo, será lo primero que haga mañana!!!

Después de una noche inquieta dándole vueltas a la cabeza pensando si esa idea, simple y tonta idea, servirá para resolver el problema, te pones a hacerlo y ¡¡¡EUREKA!!! era eso ¡¡¡QUE TONTERÍA!!! A ver, a ver, ¿la hoja de datos dice algo de esto? ¿Nooooo? ¡¡¡Se les ha pasado una cosa tan tonta como esa!!! ¡¡¡Para darle un premio al que redactó el documento!!!

Y a estas alturas, ya hartos de leer este artículo, estaréis comiendoos las uñas y diciendo que vaya de una vez al asunto y diga cual es la solución a la que he llegado. Os pongo el esquema:

Esquema DS1307

Si observáis el esquema hay una resistencia de 560K entre el pin 3 (BAT+) y GND. Es una resistencia de PULL-DOWN, si la quitamos, aunque no tenga puesta la pila, y acercamos la mano o conectamos un cable, empieza a salir el famoso “165/165/165 165:165:65”, incluso si le pones la pila sola sale eso.

No se cual es el motivo, he leído y releído mil veces la hoja de datos, y no dice nada. Es posible que al estar tan cerca del oscilador de cuarzo (XTAL) se produzca algún tipo de interferencia electromgnética que afecta al funcionamiento interno del DS1307.

Podéis observar también, que aunque en la mayoría de los montajes se indica que se deje al aire, el PIN 7 (SQW/OUT) también tiene puesta una resistencia de PULL-UP de 3K3, esto hace que el reloj funcione de forma más fiable y sin atrasar (al menos en lo que llevo de mañana no me atrasa y ayer, sin ella, me atrasaba del orden de 30 segundos cada hora).

Espero vuestros comentarios.

Usando la EEPROM 24CL32 de Tiny RTC

Ya había usado la EEPROM de los ATMega de Arduino, la verdad es que es muy sencillo con la librería EEPROM que acompaña al producto. El problema se presentó cuando decidí usar EEPROM via SDA/SCL (I2C) como la que viene con el Tiny RTC, ahí empezó otro calvario de buscar como loco por internet y de probar-deshechar códigos y librerías de mucha gente que, con toda su buena intención, resolvieron el problema y lo compartieron con el resto.

Después de muchas, muchas vueltas y desesperaciones, encontré este artículo dentro de la web de Ardunio, donde sus autores se han basado en el desarrollo de otra persona para construir una librería de uso sencillo que hace más cómoda la programación de EEPROM I2C.

La librería I2C_eeprom se puede encontrar en esta dirección de github. Solo hay que descargar los archivos y meterlos en una carpeta llamada “I2C_eeprom” dentro de la carpeta “librarys” del IDE de Arduino.

Una vez que tenemos conectado y funcionando el Tiny RTC (ha de ser el que incluye la EEPROM), realizaremos el programa de prueba de la memoria (he puesto el código de un programa que uso para mostrar la hora, la temperatura, la humedad y el uso de la EEPROM; he marcado el código correspondiente a la prueba de la memoria):

//Muestra Hora, Temperatura y Humedad, y uso de la EEPROM del Tiny RTC.

#include <Wire.h>
#include <RTClib.h>
#include <DHT.h>

//Librería para controlar la EEPROM por I2C.
#include <I2C_eeprom.hZ>

// Tamaño máximo de la EEPROM (32K)
#define EE24LC32MAXBYTES 32000

// La dirección de la EEPROM (La del Tiny RTC esta en 0x50)
#define DEVICEADDRESS (0x50)

#define DHTTYPE DHT22   // DHT 22  (AM2302)
#define DHTPIN 2     // Indicamos el pin donde conectaremos la patilla data de nuestro sensor

DHT dht(DHTPIN, DHTTYPE);

RTC_DS1307 RTC;

//Crear el acceso a la Clase.
I2C_eeprom eeprom(DEVICEADDRESS, EE24LC32MAXBYTES);

void setup () {
   //Inicializamos el puerto serie, wire y el modulo RTC
   Serial.begin(9600);
   // Inicia el I2C.
   Wire.begin();

   // Inicia el RTC.
   RTC.begin();

   if ( RTC.isrunning()){
      Serial.println("Reloj funcinando correctamente.");
      Serial.println("Hora actual: "+ dimeFecha());
   }else{
      Serial.println("El reloj NO funciona.");
  }
  //RTC.adjust(DateTime(__DATE__, __TIME__)); //Pone el reloj en hora

  dht.begin();

  // Ponemos en marcha la clase para manejar la EEPROM
  eeprom.begin();

  //Cadena de pruebas para grabar en la EEPROM.
  String cad = "Cadena de pruebas";

  //Enviamos los datos a la EEPROM. Para ejecuciones sucesivas, comentar este trozo de código y

  // comprobamos que no se borra de la EEPROM aunque desconectemos la alimentación.
  for(int n=0;n<lt;cad.length();n++){

        //eeprom.write(posicion_memoria, byte_a_enviar);
        eeprom.writeByte(n,(byte)cad.charAt(n));
  }

}

void loop () {

  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();

  Serial.print(dimeFecha());

  Serial.print("\t");
  Serial.print(humidity, 1);
  Serial.print("%");
  Serial.print("\t\t");
  Serial.print(temperature, 1);
  Serial.print("ºC";);
  Serial.print("\t\t");

 //Leemos la EEPROM
    for(int n=0;n<=16;n++){

        //eeprom.readByte(posicion_memoria);
        Serial.print((char)eeprom.readByte(n));
    }
    Serial.println();

  delay(3000);
}

/*
FUNCION PARA OBTENER LA FECHA EN MODO TEXTO
Devuelve: DD-MM-AAAA HH:MM:SS
*/
String dimeFecha(){

  char fecha[19];
  DateTime now = RTC.now(); //Obtener fecha y hora actual.

  int dia = now.day();
  int mes = now.month();
  int anio = now.year();
  int hora = now.hour();
  int minuto = now.minute();
  int segundo = now.second();

  sprintf( fecha, "%.2d/%.2d/%.4d %.2d:%.2d:%.2d", dia, mes, anio, hora, minuto, segundo);
  return String( fecha );
}

 

Listas doblemente enlazadas en Arduino

Algunas veces nos encontramos con la necesidad de tener la información que leemos de una base de datos o que nos entrega cierto dispositivo en forma de lista. He visto algunas implementaciones de otros usuarios de Arduino y la verdad, a mi no me han llegado a convencer del todo, por lo que he desarrollado mi propia clase para usar listas doblemente enlazadas  (listas que se pueden recorrer en uno u otro sentido).

Aquí dejo un resumen de las características:

NewList.h — Versión 1.0

Librería para usar listas doblemente enlazadas en Arduino (1.0.5 o superior).
Creada por: José Alfonso Suárez Moreno (joseasuarez@gmail.com).
Fecha: 21.ABR.2014

Uso:

NewList<tipo> lista;

<tipo> es el tipo de dato a usar en la lista. Desde un tipo primitivo como int, char, long… hasta un objetoo una estructura. Los símbolos <> son necesarios.

Métodos:

  • ~NewList()> Destructor.
  • add() -> Añade un nuevo elemento al final de la lista.
  • insert() -> Inserta un nuevo elemento delante del actual.
  • goFirst() -> Se posiciona al principio de la lista.
  • goLast() -> Se posiciona al final de la lista.
  • goTo(int n) -> Se posiciona en la posición n. La primera posición es 0.Si el valor es mayor que el número de elementos-1 se posiciona en el último.
  • search(tipo v) -> Busca el valor v en la lista. Debe ser del mismo tipo que el declarado al crear el objeto. Devuelve el valor. Si no lo encuentra se posiciona en el último elemento.
  • goPrevious() -> Se posiciona en el elemento anterior al actual.
  • goNext() -> Se posiciona en el elemento siguiente al actual.
  • isFirst() -> Indica si está posicionado en el primer elemento. (true/false).
  • isLast() -> Indica si está posicionado en el último elemento. (true/false).
  • isEmpty() -> Indica si la lista está vacía. (true/false).
  • getCurrent() -> Devuelve el elemento actual.
  • get(int n) -> Devuelve el elemento n. La primera posición es 0. Si el valor es mayor que el número de elementos-1 se posiciona en el último.
  • hasPrevious() -> Indica si hay un elemento dealante del actual. (true/false).
  • hasNext() -> Indica si hay un elemento detrás del actual.

TO-DO:

  • erase(int n) -> Eliminar el elemento n.
  • eraseCurrent() -> Eliminar el elemento actual.
  • eraseValue(tipo v) -> Eliminar el elemento que tenga el valor v (del mismo tipo que el especificado al crear la lista).

 

Enlace de descarga: listas doblemente enlazadas en Arduino.

Regresando al mundo de la electrónica

La electrónica fue siempre una de mis pasiones, cuando niño y durante la adolescencia me pasaba la horas entre resistencias, condensadores, diodos, transistores …. Entretanto aparecieron los ordenadores personales y la puerta al mundo de la programación, que me fascinó y me absorbió hasta convertirse en mi profesión y mi afición. La electrónica quedó relegada a un segundo plano, pero siempre estuvo ahí. La aparición de los microPics me llevaron al mundo de poder unir las dos pasiones, pero nunca pasé de hace cosas sencillas.

Había oído hablar de Raspberry Pi y de Arduino, y al final me hice con ellos para ver que era eso y qué se podía hacer. Simplemente me cautivaron y me devolvieron aquella pasión que tanto sentía por la electrónica.

A día de hoy estoy a las puertas de conseguir entrar en una empresa para desarrollar un proyecto con microPics. Un proyecto donde se va a diseñar todo el sistema desde cero, desarrollo de una controladora basada en microPic, software de configuración y software de usuario.

Estoy luchando con todas mis fuerzas por conseguirlo, será como un sueño hecho realidad.