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.

Versión 1.2 de la CONTROLADORA para Acceso y Presencia

Controladora 2016_p

Nueva versión 1.2 de la Controladora para control de acceso y presencia basada en Arduino Mega, con 2 entradas Wiegand 26, dos salidas a relé, conexión LAN y alimentación de 12V.

Se comunica con el servidor a través de LAN. Funcionamiento en tiempo real. Puede conectarse con servidor remoto a través de ineternet.

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 );
}

 

Tiny RTC y perdida de la hora

Hola, Andaba ya cansado que el módulo Tiny RTC basado en el DS1307, reloj en tiempo real, no me guardase la hora. Navegando por la web encontré el siguiente esquema:

Esquema Tiny RTC

en la página de Instructables.

Armado de polímetro (téster o como le llame cada uno) y un poco de paciencia, me puse a comprobar las conexiones del Tiny RTC y cual fue mi sorpresa al descubrir que entre la unión de R4 y R6 no se conectaba con el PIN 3 del DS1307.

Apañé el invento con un puente, quedando así:

Apaño Tiny RTC

Apaño Tiny RTC

Y ya no pierde la hora al quitar la alimentación.