En este proyecto vamos a usar un LCD gráfico Nokia 5110 para mostrar la hora proporcionada por el RTC.
Para poder usar este LCD necesitamos dos librerías, ambas desarrolladas por Adafruit.
Una de las librerías es la del controlador integrado en el LCD, la PCD8544 Nokia 5110 LCD Library, la otra librería es para mostrar gráficos, podéis descargarla aquí: Adafruit GFX Library.
La conexión del LCD es muy sencilla, solo necesita cinco hilos.
Hay que tener cuidado de no conectar directamente el LCD al Arduino, ya que el LCD funciona con 3,3 voltios y Arduino proporciona 5 voltios en sus salidas digitales.
La conexión se puede hacer de dos formas, una más sencilla con resistencias y otra más profesional usando un circuito integrado CD4050, que es un buffer no inversor, es decir, un adaptador de tensiones de 5 a 3,3 voltios.
El consumo del LCD es muy bajo, menos de 20 mA con el backlight incluido, por lo que se puede alimentar directamente con la salida de 3,3 voltios de Arduino. Recordad que la salida de 3,3 voltios suministra un máximo de 50 mA.
Partiendo del código del Proyecto 21, he añadido las dos librerías mencionadas al principio y he modificado el código original para adaptarlo al display gráfico.
/*********************************************************************
This is an example sketch for our Monochrome Nokia 5110 LCD Displays
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/products/338
These displays use SPI to communicate, 4 or 5 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above, and the splash screen must be included in any redistribution
*********************************************************************/
/*
Real Time Clock con LCD grafico 84x48 pixeles
*/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <Wire.h>
#include "ds3231.h"
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
//Adafruit_PCD8544 display = Adafruit_PCD8544(CLK, DIN, DC, CS, RST);
#define BUFF_MAX 128
uint8_t time[8];
char recv[BUFF_MAX];
unsigned int recv_size = 0;
unsigned long prev, interval = 1000;
void setup() {
// Iniciamos comunicacion serie
Serial.begin(9600);
Wire.begin();
DS3231_init(DS3231_INTCN);
memset(recv, 0, BUFF_MAX);
// Iniciamos comunicacion con la pantalla
display.begin();
// Establecemos el contraste
display.setContrast(45);
// Mostramos la pantalla de inicio durante 2 segundos
display.display();
delay(2000);
// borramos la pantalla
display.clearDisplay();
}
void loop()
{
char in;
char tempF[6];
float temperature;
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);
// borramos la pantalla
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
printDay(t.wday);
display.setCursor(0, 10);
display.print(t.mday);
printMonth(t.mon);
display.println(t.year);
display.setCursor(0, 20);
display.print(t.hour);
display.print(":");
if(t.min<10)
{
display.print("0");
}
display.print(t.min);
display.print(":");
if(t.sec<10)
{
display.print("0");
}
display.print(t.sec);
display.println(' ');
display.setCursor(0, 30);
display.print("Temp:");
display.print(tempF);
display.print((char)222);
display.print("C");
prev = now;
display.display();
delay(500);
display.clearDisplay();
}
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);
}
}
void printMonth(int month)
{
switch(month)
{
case 1: display.print(" Ene ");break;
case 2: display.print(" Feb ");break;
case 3: display.print(" Mar ");break;
case 4: display.print(" Abr ");break;
case 5: display.print(" May ");break;
case 6: display.print(" Jun ");break;
case 7: display.print(" Jul ");break;
case 8: display.print(" Ago ");break;
case 9: display.print(" Sep ");break;
case 10: display.print(" Oct ");break;
case 11: display.print(" Nov ");break;
case 12: display.print(" Dic ");break;
default: display.print(" Error ");break;
}
}
void printDay(int wday)
{
switch(wday)
{
case 1: display.println("Lunes");break;
case 2: display.println("Martes");break;
case 3: display.println("Miercoles");break;
case 4: display.println("Jueves");break;
case 5: display.println("Viernes");break;
case 6: display.println("Sabado");break;
case 7: display.println("Domingo");break;
default: display.println("Error");break;
}
}
Al ser un display gráfico, podemos añadir figuras geométricas a la pantalla.
En la web de Ardumania hay un estupendo tutorial donde explica las funciones necesarias para mostrar figuras geométricas.
Partiendo del código anterior se puede añadir un simple marco alrededor de la pantalla o líneas separadoras.
Aquí dejo un par de fotos para que veáis un ejemplo.