Segunda parte de la serie dedicada al display DLO7135 de Siemens.
En el siguiente tutorial veremos tres ejemplos más de aplicación. En el primer ejemplo, explico cómo hacer scroll con un mensaje de texto y tres displays. En el segundo veremos cómo utilizar los displays para mostrar variables, haciendo un termómetro de precisión con el sensor LM35. Y en el tercer ejemplo haremos un reloj-termómetro con el RTC DS3231.
Para hacer scroll con un texto vamos a modificar ligeramente el esquema con tres registros de desplazamiento 74HC595 del Proyecto 37.1
La señal Serial Data Input la llevamos a IC3 y de ahí a IC2 y luego a IC1, de esa manera los datos van pasando de IC3 a IC2 y luego a IC1.
Colocamos los displays de izquierda a derecha comenzando por el Display 1, tal como se muestra en el esquema.
/*
Proyecto 37.2
Siemens DLO-7135 5x7 Dot Matrix Intelligent Display
Scrolling Text with Three Displays
Based on the original sketch by Carlyn Maw and Tom Igoe
https://www.arduino.cc/en/Tutorial/ShiftOut
Modified by Angel M.
https://sites.google.com/site/angmuz/home
*/
//Pin connected to ST_CP of 74HC595
int latchPin = 6;
//Pin connected to SH_CP of 74HC595
int clockPin = 7;
////Pin connected to DS of 74HC595
int dataPin = 8;
//holders for infromation you're going to pass to shifting function
byte data;
byte dataArray[11];
// To set the Brightness via Arduino
int BL0 = 12;
int BL1 = 13;
void setup() {
//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(BL0, OUTPUT);
pinMode(BL1, OUTPUT);
// Full Brightness
digitalWrite(BL0,HIGH);
digitalWrite(BL1,HIGH);
//Start Serial for debuging purposes
Serial.begin(9600);
dataArray[0] = 0x48; // H
dataArray[1] = 0x4F; // O
dataArray[2] = 0x4C; // L
dataArray[3] = 0x41; // A
dataArray[4] = 0x20; // BLANK
dataArray[5] = 0x4D; // M
dataArray[6] = 0x55; // U
dataArray[7] = 0x4E; // N
dataArray[8] = 0x44; // D
dataArray[9] = 0x4F; // O
dataArray[10] = 0x20; // BLANK
dataArray[11] = 0x20; // BLANK
}
void loop() {
for (int j = 0; j < 12; j++) {
//load the light sequence you want from array
data = dataArray[j];
//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, 0);
//move 'em out
shiftOut(dataPin, clockPin, data);
//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, 1);
delay(500);
}
}
// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low
//internal function setup
int i=0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);
//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);
//for each bit in the byte myDataOut�
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i=7; i>=0; i--) {
digitalWrite(myClockPin, 0);
//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.
if ( myDataOut & (1<<i) ) {
pinState= 1;
}
else {
pinState= 0;
}
//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
}
//stop shifting
digitalWrite(myClockPin, 0);
}
En este ejemplo he utilizado un Arduino NANO v3 en lugar del UNO R3 que suelo emplear habitualmente. Esto se debe a que el regulador interno del Arduino UNO se queda justo para suministrar corriente a los integrados y a los displays, provocando un funcionamiento irregular.
Con una fuente de alimentación de 5V alimentamos el Arduino NANO, los integrados y los displays.
Conectamos el sensor LM35 en el pin A1 del Arduino y lo alimentamos a +5V y GND.
El LM35 es un sensor de temperatura de precisión, con una exactitud de 0.5ºC, es lineal en la respuesta y tiene la ventaja de estar directamente calibrado en grados centígrados.
Recordad que el LM35 se conecta inversamente. Esto es porque a grandes rasgos el sensor es un diodo zener y si lo conectamos atendiendo al nombre de las patillas lo que estamos haciendo en polarizar directamente el diodo y provocando un cortocircuito en la alimentación, lo que puede dañar la fuente o el puerto USB de nuestro ordenador.
El trimmer de 100K es para ajustar la tensión de referencia del canal analógico a 1.0 voltios. Esto es porque el sensor LM35 proporciona una salida máxima de 1.0 voltios, por lo que si aRef son 5V estamos perdiendo exactitud en la medida.
Arduino tiene un conversor A/D en las entradas analógicas. Por defecto convierte los 0-5 voltios en la entrada analógica en un valor digital 0-1023. Como el LM35 varía entre 0 y 1V, estamos perdiendo mucha información, por eso modificamos el valor del pin Analog Reference a 1.0 voltios.
Puedes consultar una explicación más detallada aquí.
El led Dl1 es fijo y sirve para hacer de coma para los decimales.
Para evitar continuos cambios en la lectura de la temperatura, vamos a hacer 100 lecturas del valor del sensor LM35, en intervalos de 150 ms. Por lo tanto la temperatura se actualiza cada 15 segundos. Después calculamos la media de todas las lecturas y ese será el valor que mostraremos en los displays.
La temperatura es una variable float con dos decimales, por ejemplo tempC=24,35.
Multiplicando la temperatura x 100 quitamos los decimales y queda 2435, luego descomponemos ese entero en decenas, unidades y decimales y nos olvidamos del segundo decimal. El resultado es: decenas=2, unidades=4 y decimales=3
Cada display muestra una de las cifras que forman la temperatura de izquierda a derecha queda 2 4 . 3
/*
Proyecto 37.2 - Termómetro de precisión con sensor LM35
y tres displays Siemens DLO-7135 - 5x7 Dot Matrix Intelligent Display
Angel M. https://sites.google.com/site/angmuz/home
*/
//Pin connected to ST_CP of 74HC595
int latchPin = 6;
//Pin connected to SH_CP of 74HC595
int clockPin = 7;
////Pin connected to DS of 74HC595
int dataPin = 8;
//holders for infromation you're going to pass to shifting function
byte datauds;
byte datadec;
byte datadcm;
byte dataArray[10];
// To set the Brightness via Arduino
int BL0 = 12;
int BL1 = 13;
// parametros para LM35
float tempC;
int reading;
int tempPin = 1;
int media;
int cnt;
void setup()
{
analogReference(EXTERNAL); // set aRef to 1.0V
//set pins to output
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(BL0, OUTPUT);
pinMode(BL1, OUTPUT);
// Full Brightness
digitalWrite(BL0,HIGH);
digitalWrite(BL1,HIGH);
//Start Serial for debuging purposes
Serial.begin(9600);
dataArray[0] = 0x30; // 0
dataArray[1] = 0x31; // 1
dataArray[2] = 0x32; // 2
dataArray[3] = 0x33; // 3
dataArray[4] = 0x34; // 4
dataArray[5] = 0x35; // 5
dataArray[6] = 0x36; // 6
dataArray[7] = 0x37; // 7
dataArray[8] = 0x38; // 8
dataArray[9] = 0x39; // 9
}
void loop() {
// calculo de la temperatura. con LM35
media=0; // inicializamos el valor de la media
// medimos la temperatura 100 veces cada 150ms y la almacenamos en tmedia
// la temperatura se actualiza cada 15 segundos (150*100=15.000ms)
for ( cnt=0; cnt<100; cnt++)
{
reading = analogRead(tempPin);
media=media+reading;
delay(150);
}
// calculamos la media aritmética de las lecturas
media=media/cnt;
tempC = media / 10.24;
int t = tempC*100; // para quitar los decimales
int dec, uds, dcm; // decenas, unidades, decimales
// descomponer la temteratura en decenas, unidades y decimales
dec = t/1000;
uds = (t-(dec*1000))/100;
dcm = (t-((dec*1000)+(uds*100)))/10;
datauds = dataArray[dec];
datadec = dataArray[uds];
datadcm = dataArray[dcm];
//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, 0);
//move 'em out
shiftOut(dataPin, clockPin, datauds);
shiftOut(dataPin, clockPin, datadec);
shiftOut(dataPin, clockPin, datadcm);
//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, 1);
delay(500);
}
// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut)
{
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low
//internal function setup
int i=0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);
//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);
//for each bit in the byte myDataOut
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i=7; i>=0; i--) {
digitalWrite(myClockPin, 0);
//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.
if ( myDataOut & (1<<i) ) {
pinState= 1;
}
else {
pinState= 0;
}
//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
}
//stop shifting
digitalWrite(myClockPin, 0);
}
Termómetro de precisión con sensor LM35
Este tercer ejemplo lo he incluido a última hora. Desde el principio pensé que hacer un reloj con estos displays quedaría muy bien, pero el hecho de disponer de tres unidades me hizo descartar el proyecto. Hacen falta cuarto displays para mostrar la hora.
Luego se me ocurrió que podía mostrar la hora por partes; primero la hora acompañada de la letra H, luego los minutos con la letra M y por último la temperatura con un decimal, como en el ejemplo 2.
Para materializar el sketch he utilizado la misma técnica que en ejemplos anteriores.
Las variables t.hour y t.min son números enteros. Mediante tres funciones displayHour(t.hour) displayMin(t.min) y displayTemp(ta) los descomponemos en decenas y unidades y sacamos cada cifra por un display, y por el tercer display la letra H o M según corresponda. Y lo mismo para la temperatura.
/*
Proyecto 37.3 Clock-Thermometer with 3 x SIEMENS DLO7135 5x7 Dot Matrix Intelligent Display
& DS3231 RTC Module
Angel M.
https://sites.google.com/site/angmuz/home
*/
#include <Wire.h>
#include "ds3231.h"
#define BUFF_MAX 128
#define dot 3 // dot point
uint8_t time[8];
char recv[BUFF_MAX];
unsigned int recv_size = 0;
unsigned long prev, interval = 1000;
//Pin connected to ST_CP of 74HC595
int latchPin = 6;
//Pin connected to SH_CP of 74HC595
int clockPin = 7;
////Pin connected to DS of 74HC595
int dataPin = 8;
//holders for infromation you're going to pass to shifting function
byte dataDsp1;
byte dataDsp2;
byte dataDsp3;
byte dataArray[13];
// To set the Brightness via Arduino
int BL0 = 12;
int BL1 = 13;
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("T002323091052015",16);
//set pins to output
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(BL0, OUTPUT);
pinMode(BL1, OUTPUT);
pinMode(dot, OUTPUT);
// Half Brightness
digitalWrite(BL0,LOW);
digitalWrite(BL1,HIGH);
//Start Serial for debuging purposes
Serial.begin(9600);
dataArray[0] = 0x30; // 0
dataArray[1] = 0x31; // 1
dataArray[2] = 0x32; // 2
dataArray[3] = 0x33; // 3
dataArray[4] = 0x34; // 4
dataArray[5] = 0x35; // 5
dataArray[6] = 0x36; // 6
dataArray[7] = 0x37; // 7
dataArray[8] = 0x38; // 8
dataArray[9] = 0x39; // 9
dataArray[10] = 0x48; // H
dataArray[11] = 0x4D; // M
dataArray[12] = 0x20; // Blank
}
void loop()
{
char in;
char tempF[6];
float temperature;
int ta;
char buff[BUFF_MAX];
unsigned long now = millis();
struct ts t;
// show time once in a while
if ((now - prev > interval) && (Serial.available() <= 0)) {
DS3231_get(&t); //Get time
parse_cmd("C",1);
temperature = DS3231_get_treg(); //Get temperature
dtostrf(temperature, 5, 1, tempF);
displayHour(t.hour);
delay(3000);
displayMin(t.min);
delay(3000);
ta=temperature*10;
displayTemp(ta);
delay(3000);
digitalWrite(dot, LOW);
prev = now;
}
if (Serial.available() > 0) {
in = Serial.read();
if ((in == 10 || in == 13) && (recv_size > 0)) {
parse_cmd(recv, recv_size);
recv_size = 0;
recv[0] = 0;
} else if (in < 48 || in > 122) {; // ignore ~[0-9A-Za-z]
} else if (recv_size > BUFF_MAX - 2) { // drop lines that are too long
// drop
recv_size = 0;
recv[0] = 0;
} else if (recv_size < BUFF_MAX - 2) {
recv[recv_size] = in;
recv[recv_size + 1] = 0;
recv_size += 1;
}
}
}
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 mostrar la Hora
int displayHour(int h)
{
int dec, uds; // decenas, unidades
// descomponemos la teperatura en decenas y unidades
dec = h/10;
uds = (h-(dec*10));
if (dec == 0)
{
// Mostramos cada cifra en el display correspondiente
dataDsp1 = dataArray[12]; // No se muestra el cero a la derecha
dataDsp2 = dataArray[uds];
dataDsp3 = dataArray[10]; // Muestra la letra H
}
else
{
// Mostramos cada cifra en el display correspondiente
dataDsp1 = dataArray[dec];
dataDsp2 = dataArray[uds];
dataDsp3 = dataArray[10]; // Muestra la letra H
}
//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, 0);
//move 'em out
shiftOut(dataPin, clockPin, dataDsp1);
shiftOut(dataPin, clockPin, dataDsp2);
shiftOut(dataPin, clockPin, dataDsp3);
//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, 1);
delay(500);
}
// Función mostrar los Minutos
int displayMin(int m)
{
int dec, uds; // decenas, unidades
// descomponemos la teperatura en decenas y unidades
dec = m/10;
uds = (m-(dec*10));
// Mostramos cada cifra en el display correspondiente
dataDsp1 = dataArray[dec];
dataDsp2 = dataArray[uds];
dataDsp3 = dataArray[11]; // Muestra la letra M
//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, 0);
//move 'em out
shiftOut(dataPin, clockPin, dataDsp1);
shiftOut(dataPin, clockPin, dataDsp2);
shiftOut(dataPin, clockPin, dataDsp3);
//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, 1);
delay(500);
}
// Función mostrar Temperatura
int displayTemp(int t)
{
int dec, uds, dcm; // decenas, unidades, decimales
// descomponemos la teperatura en decenas, unidades y decimales
dec = t/100;
uds = (t-(dec*100))/10;
dcm = t-((dec*100)+(uds*10));
// Mostramos cada cifra en el display correspondiente
dataDsp1 = dataArray[dec];
dataDsp2 = dataArray[uds];
dataDsp3 = dataArray[dcm];
//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, 0);
//move 'em out
digitalWrite(dot, HIGH);
shiftOut(dataPin, clockPin, dataDsp1);
shiftOut(dataPin, clockPin, dataDsp2);
shiftOut(dataPin, clockPin, dataDsp3);
//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, 1);
delay(500);
}
// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut)
{
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low
//internal function setup
int i=0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);
//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);
//for each bit in the byte myDataOut
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i=7; i>=0; i--) {
digitalWrite(myClockPin, 0);
//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.
if ( myDataOut & (1<<i) ) {
pinState= 1;
}
else {
pinState= 0;
}
//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
}
//stop shifting
digitalWrite(myClockPin, 0);
}
Arduino Playground: LM35 High Resolution
Arduino Tutorials: Serial to Parallel Shifting-Out with a 74HC595
Petre Rodan: Arduino library for DS3231 RTC
Puedes descargar el proyecto en un .zip aquí abajo. Se incluyen los esquemas y los sketch.