Proyecto 36.4 - Reloj- Termómetro con Display DVD

13 de noviembre de 2016

En el tutorial 36.2 vimos cómo conectar un pequeño display de DVD al Arduino para hacer un reloj-termómetro. En dicho proyecto la corriente para iluminar los 7 segmentos de cada dígito es suministrada por los pines del Arduino, lo que supone una limitación.

Para solucionar este problema, en el siguiente tutorial vamos a utilizar transistores para alimentar los dígitos del display, de forma que la corriente máxima viene impuesta por la corriente del led que forma cada segmento.

Esquema

El siguiente esquema representa los dos tipos de conexión del display. En el circuito con transistor, las resistencias de los segmentos pueden ser de pequeño valor 100 ó 120 Ohm para que los ledes se iluminen con mayor intensidad. En el datasheet del display que se vaya a utilizar, hay que ver la corriente máxima de cada segmento y así calcular la resistencia que corresponda.

También hay que tener en cuenta la corriente máxima de colector del transistor que se va a utilizar. Si por ejemplo, la corriente de cada segmento es de 20mA, cuando se iluminen los 7 segmentos, la corriente en el colector del transistor es de 7x20=140mA. Con este dato escogemos el transistor más adecuado. Además debe ser un transistor con tiempos de conmutación muy rápidos, del tipo switching transistor.

Nota importante:  Dado que la corriente de cada dígito puede alcanzar 140mA multiplicado por 10 dígitos que tiene el display son 1,4A. Para alimentar el circuito no vale el puerto USB de un ordenador. Tampoco el regulador interno de +5V del Arduino. Hay que utilizar una fuente de alimentación.

Después de este rollo a modo de introducción, vamos con el proyecto.

El display utilizado en este tutorial es un display de un reproductor DVD del fabricante MxOnda, aunque también se puede encontrar en reproductores DVD de otras marcas.

01 Arduino DVD Display.PNG

Es un display de 10 dígitos y 7 segmentos de ánodo común. Utiliza el controlador PT6961 de Princeton Technology Corp. De los 10 dígitos hay 7 para mostrar números y 3 para caracteres especiales.

Googleando un poco se pueden encontrar en Internet varias librerías sobre el PT6961, pero no he conseguido que funcione correctamente, en parte supongo porque el display no está conectado de la forma correcta -de acuerdo a la librería- con el controlador.

Así que toca desoldar el display y conectarlo al Arduino por nuestros propios medios.

Antes de continuar necesitamos saber que es cada pin del display. Para ello necesitamos una resistencia de 1K, una fuente de 5V y un poco de paciencia e ir recorriendo todos los pines, en todas las combinaciones posibles, hasta sacar el pinout.

Como decía más arriba, es un display de 10 dígitos, de los cuales 7 son para representar números y los otros 3 para caracteres especiales.

Al disponer de 7 dígitos para los números, con este display podemos mostrar a la vez la temperatura y la hora. Con los otros dígitos se puede programar algún juego de luces para hacer el display más llamativo. Por ejemplo, con el disco se puede hacer un segundero.

Esquema

El transistor utilizado es el BC337 de Philips. Es un transistor NPN de propósito general, con alta corriente de colector (500mA) para aplicaciones de conmutación y amplificación.

BC337 SWITCHING TRANSISTOR.PNG

También se puede utilizar cualquier otro transistor que cumpla con los requisitos del circuito, por ejemplo el 2N2222 es un modelo típico en los proyectos con Arduino.

Aunque en el esquema están conectados los diez dígitos del display, para simplificar cada uno puede conectar sólo los dígitos que vaya a utilizar.

Una vez conectado el display, lo primero que hay que hacer es verificar que funciona correctamente. En este paso no es necesario conectar el RTC.

Para ello cargamos el siguiente sketch de prueba. Veremos cómo se iluminan los siete segmentos del display uno tras otro y a continuación se muestran los números del 0 al 9 y las letras A, b, C, d, E y F.

Sketch

/*

* Proyecto 36.4

* Testing 10-Digit 7-Segment MxOnda DVD Player Display with 74HC595

*

* Este sketch ilumina de uno en uno todos los segmentos de todos los dígitos a la vez

* Angel M. https://sites.google.com/site/angmuz

* Public domain

*/

int digitPins[10] = {2,3,4,5,6,7,8,9,10,11};

int latchPin = 14; // Arduino Pin 14(A0) to 74HC595 Pin 12 (Latch)

int dataPin  = 13; // Arduino Pin 13 to 74HC595 Pin 14 (Data)

int clockPin = 12; // Arduino Pin 12 to 74HC595 Pin 11 (Clock)

// Cada segmento se enciende con LOW por ser de ánodo común                 

const byte digit[24] = {

               0b11111111, // BLANK

               0b11111110, // seg a

               0b11111101, // seg b

               0b11111011, // seg c

               0b11110111, // seg d

               0b11101111, // seg e

               0b01011111, // seg f

               0b10111111, // seg g

               0b01000000, // 0

               0b11111001, // 1

               0b10100100, // 2

               0b10110000, // 3

               0b00011001, // 4

               0b00010010, // 5

               0b00000010, // 6

               0b11111000, // 7

               0b00000000, // 8

               0b00010000, // 9

               0b00001000, // A

               0b00000011, // b

               0b01000110, // C

               0b10100001, // d

               0b00000110, // E

               0b00001110};// F

                     

void setup() {

 //Serial.begin(9600);

 pinMode(latchPin, OUTPUT);

 pinMode(clockPin, OUTPUT);

 pinMode(dataPin, OUTPUT);

 pinMode(2, OUTPUT);

 pinMode(3, OUTPUT);

 pinMode(4, OUTPUT);

 pinMode(5, OUTPUT);

 pinMode(6, OUTPUT);

 pinMode(7, OUTPUT);

 pinMode(8, OUTPUT);

 pinMode(9, OUTPUT);

 pinMode(10, OUTPUT);

 pinMode(11, OUTPUT);

   for(int j=0; j<10; j++) //number of digits

 {

   digitalWrite(digitPins[j], HIGH);

 }

 

}

void loop(){

 

 for (int i=0; i<24 ;i++)

 {

 digitalWrite(latchPin, LOW);  

 shiftOut(dataPin, clockPin, MSBFIRST, digit[i]);

 digitalWrite(latchPin, HIGH);

 delay(1000);

 } 

 

}


Reloj-Termómetro

En el reloj-termómetro que presento a continuación no he utilizado el dígito 1 (CA1) así que podemos prescindir del transistor T10 conectado en el pin 11 del Arduino.

De los tres dígitos de la izquierda, dos son para mostrar la temperatura y el tercero para el símbolo º. Los cuatro dígitos de la derecha son para mostrar la hora. Y el disco lo utilizaré para hacer un segundero, de manera que los segmentos se iluminan uno tras otro, durante un segundo.

Sketch

La función void displayHT es la encargada de descomponer en decenas y unidades las variables hora, minutos y temperatura. Cada uno de los dígitos simples se almacena en digitBuffer[i] y se muestra en el display mediante la función updateDisp.

La función Millis() es para iluminar durante un segundo los segmentos del disco y de ese modo implementar un segundero en el display.

Para que todo se muestre correctamente en el display hay que colocar en orden los pines utilizados en int digitPins[9] = {5,6,7,8,9,10,4,3,2} al principio del sketch.

La siguiente tabla nos ayuda a obtener el orden correcto.

A continuación el sketch.


/*

* Proyecto 36.4

* Clock-Thermometer with 7-Segment 10-Digit Large DVD Player Display

* DS3231 RTC Module & 74HC595 Shift Register

* Reloj-Termometro con funcion segundero en disco OK

* Angel M. https://sites.google.com/site/angmuz

* Public domain

*/

#include <Wire.h>

#include "ds3231.h"

#define BUFF_MAX 128

uint8_t time[8];

char recv[BUFF_MAX];

unsigned int recv_size = 0;

   //digitBuffer[]=0,1,2,3,4, 5,6,7,8

int digitPins[9] = {5,6,7,8,9,10,4,3,2};

int latchPin = 14; // Arduino Pin 14(A0) to 74HC595 Pin 12 (Latch)

int dataPin  = 13; // Arduino Pin 13 to 74HC595 Pin 14 (Data)

int clockPin = 12; // Arduino Pin 12 to 74HC595 Pin 11 (Clock)

int i =0;

int digitScan = 0;

int digitBuffer[10] = {0};

unsigned long previousMillis = 0;

const long interval = 1000;

int dB7 = 12;

int dB8 = 19;

int cnt = 0;

// Cada segmento se enciende con LOW por ser de ánodo común                 

const byte digit[20] = {

               0b11000000, // 0

               0b11111001, // 1

               0b10100100, // 2

               0b10110000, // 3

               0b10011001, // 4

               0b10010010, // 5

               0b10000010, // 6

               0b11111000, // 7

               0b10000000, // 8

               0b10010000, // 9

               0b10011100, // º

               0b11000110, // C

               0b11111110, // seg a

               0b11111101, // seg b

               0b11011111, // seg f

               0b10111111, // seg g

               0b11110111, // seg d

               0b11111011, // seg c                

               0b11101111, // seg e               

               0b11111111};// BLANK

               

               

                     

void setup() {

 //Serial.begin(9600);

 Wire.begin();

 DS3231_init(DS3231_INTCN);

 memset(recv, 0, BUFF_MAX);

 //Serial.println("GET time");

       

 // the first day of the week is monday=1

 // (seconds,minutes,hour,week day,date,month,year)

 //  parse_cmd("T003922420102016",16);

 

 pinMode(latchPin, OUTPUT);

 pinMode(clockPin, OUTPUT);

 pinMode(dataPin, OUTPUT);

 

 pinMode(3, OUTPUT);

 pinMode(4, OUTPUT);

 pinMode(5, OUTPUT);

 pinMode(6, OUTPUT);

 pinMode(7, OUTPUT);

 pinMode(8, OUTPUT);

 pinMode(9, OUTPUT);

 pinMode(10, OUTPUT);

 pinMode(11, OUTPUT);

 

}

void loop(){

 

 char in;

 char tempF[6];

 float temperature;

 char buff[BUFF_MAX];

 unsigned long now = millis();

 struct ts t;

 

 DS3231_get(&t); //Get time

 parse_cmd("C",1);

 temperature = DS3231_get_treg(); //Get temperature

 dtostrf(temperature, 5, 1, tempF);

 displayHT(t.hour, t.min, temperature);

 

}

void parse_cmd(char *cmd, int cmdsize)

{

   uint8_t i;

   uint8_t reg_val;

   char buff[BUFF_MAX];

   struct ts t;

   //snprintf(buff, BUFF_MAX, "cmd was '%s' %d\n", cmd, cmdsize);

   //Serial.print(buff);

   // TssmmhhWDDMMYYYY aka set time

   if (cmd[0] == 84 && cmdsize == 16) {

       //T355720619112011

       t.sec = inp2toi(cmd, 1);

       t.min = inp2toi(cmd, 3);

       t.hour = inp2toi(cmd, 5);

       t.wday = inp2toi(cmd, 6);

       t.mday = inp2toi(cmd, 8);

       t.mon = inp2toi(cmd, 10);

       t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);

       DS3231_set(t);

       //Serial.println("OK");

   } else if (cmd[0] == 49 && cmdsize == 1) {  // "1" get alarm 1

       DS3231_get_a1(&buff[0], 59);

       //Serial.println(buff);

   } else if (cmd[0] == 50 && cmdsize == 1) {  // "2" get alarm 1

       DS3231_get_a2(&buff[0], 59);

       //Serial.println(buff);

   } else if (cmd[0] == 51 && cmdsize == 1) {  // "3" get aging register

       //Serial.print("aging reg is ");

       //Serial.println(DS3231_get_aging(), DEC);

   } else if (cmd[0] == 65 && cmdsize == 9) {  // "A" set alarm 1

       DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);

       //ASSMMHHDD

       for (i = 0; i < 4; i++) {

           time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // ss, mm, hh, dd

       }

       byte flags[5] = { 0, 0, 0, 0, 0 };

       DS3231_set_a1(time[0], time[1], time[2], time[3], flags);

       DS3231_get_a1(&buff[0], 59);

       //Serial.println(buff);

   } else if (cmd[0] == 66 && cmdsize == 7) {  // "B" Set Alarm 2

       DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);

       //BMMHHDD

       for (i = 0; i < 4; i++) {

           time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // mm, hh, dd

       }

       byte flags[5] = { 0, 0, 0, 0 };

       DS3231_set_a2(time[0], time[1], time[2], flags);

       DS3231_get_a2(&buff[0], 59);

       //Serial.println(buff);

   } else if (cmd[0] == 67 && cmdsize == 1) {  // "C" - get temperature register

       //Serial.print("temperature reg is ");

       //Serial.println(DS3231_get_treg(), DEC);

   } else if (cmd[0] == 68 && cmdsize == 1) {  // "D" - reset status register alarm flags

       reg_val = DS3231_get_sreg();

       reg_val &= B11111100;

       DS3231_set_sreg(reg_val);

   } else if (cmd[0] == 70 && cmdsize == 1) {  // "F" - custom fct

       reg_val = DS3231_get_addr(0x5);

       //Serial.print("orig ");

       //Serial.print(reg_val,DEC);

       //Serial.print("month is ");

      // Serial.println(bcdtodec(reg_val & 0x1F),DEC);

   } else if (cmd[0] == 71 && cmdsize == 1) {  // "G" - set aging status register

       DS3231_set_aging(0);

   } else if (cmd[0] == 83 && cmdsize == 1) {  // "S" - get status register

       //Serial.print("status reg is ");

       //Serial.println(DS3231_get_sreg(), DEC);

   } else {

       //Serial.print("unknown command prefix ");

       //Serial.println(cmd[0]);

       //Serial.println(cmd[0], DEC);

   }

   

}

// función para mostrar la hora y la temperatura

void displayHT(int hora, int minutos, int temp)

{

 int decHora, udsHora, decMins, udsMins, decTemp, udsTemp;

 

 // descomponemos la hora decenas y unidades

 decHora = hora/10;

 udsHora = hora-(decHora*10);

 

 // Para que no se muestre el pimer 0 de la hora

 if (decHora==0){

  decHora=19; //BLANK

 }

 // descomponemos los minutos decenas y unidades

 decMins = minutos/10;

 udsMins = minutos-(decMins*10);

 

 // descomponemos la temperatura decenas y unidades

 decTemp = temp/10;

 udsTemp = temp-(decTemp*10);

 // hacemos un segundero con los leds del "disco"

 unsigned long currentMillis = millis();

 if (currentMillis - previousMillis >= interval) {

   // save the last time you blinked the LED

   previousMillis = currentMillis;

   cnt++;

   dB7++;

   if (cnt>6)

   {

     dB7 = 19; //BLANK

     dB8 = 15; //seg g digito 10

   }

   else

   {

     dB8=19;

   }

   if (cnt>7)

   {

     cnt=0;

     dB7=12;

     dB8=19;

   }

 }

  

 //digitBuffer[i] es la posición que ocupa

 //el dígito en el array digitPins[9]

 digitBuffer[8] = dB8;      //seg g digito 10

 digitBuffer[7] = dB7;      //disco

 digitBuffer[6] = 10;       //simbolo º

 digitBuffer[5] = udsMins;  //unidades de minuto

 digitBuffer[4] = decMins;  //decenas de minuto

 digitBuffer[3] = udsHora;  //unidades de hora

 digitBuffer[2] = decHora;  //decenas de hora

 digitBuffer[1] = udsTemp;  //unidades de temp.

 digitBuffer[0] = decTemp;  //decenas de temp.

 updateDisp();

 

}

void updateDisp(){

 

 for(int j=0; j<9; j++) //number of digits

 {

   digitalWrite(digitPins[j], LOW);

 }

 

 digitalWrite(latchPin, LOW);  

 shiftOut(dataPin, clockPin, MSBFIRST, B11111111);

 digitalWrite(latchPin, HIGH);   

 

 delayMicroseconds(100);  

 digitalWrite(digitPins[digitScan], HIGH);


 digitalWrite(latchPin, LOW);  

 shiftOut(dataPin, clockPin, MSBFIRST, digit[digitBuffer[digitScan]]);

 digitalWrite(latchPin, HIGH);


 digitScan++;

 if(digitScan>8) digitScan=0; //number of digits - 1

 

}