Questo post mostra come costruire un orologio in tempo reale usando Arduino, DS1307 RTC e SSD1306 OLED.
DS1307 RTC viene utilizzato come chip di orologio in tempo reale che mantiene il tempo in esecuzione anche se l'alimentazione principale è disattivata (con l'aiuto di una batteria), l'ora e la data vengono visualizzate sull'SSD1306 128 × 64 OLED.
Il display che utilizzeremo in questo articolo ha una risoluzione di 128×64 pixel ed è molto piccolo 0,96 pollici. Vuol dire uno schermo che misura circa 2.5 cm per 1.3 cm, ha un solo colore (bianco e nero). I display OLED ci permettono di visualizzare informazioni per i nostri progetti, come abbiamo visto in un precedente post la temperatura ecc...
Hardware occorrente:
Scheda Arduino
DS1307 RTC
SSD1306 OLED (modalità I2C)
breadboard
Cavi jumper
Il display OLED ed anche il modulo DS1307 utilizzato in questa progetto sono del tipo con interfaccia a due fili I2C, come si vede nella foto hanno solo 4 pin, positivo (VCC) e massa (GND), e due pin dell’interfaccia seriale SCL (serial clock) e SDA serial data.
Il driver che pilota il display è un SSD1306, tensione di alimentazione dai 3,3V ai 6V circa.
Occorre scaricare queste le librerie se non le avete già disponibili nella cartella librerie di Arduino.
Colleghiamo il display OLED e il DS1307 ad Arduino UNO come da immagine:
Adesso bisogna scoprire l’indirizzo I2C del display, per farlo ci viene in aiuto un piccolo schetch chiamato I2C scanner (https://playground.arduino.cc/Main/I2cScanner). Esso cercherà gli indirizzi I2C dei dispositivi connessi tramite I2C all’Arduino e li invierà tramite seriale. Caricatelo su Arduino IDE e aprite la finestra del monitor seriale, impostate 9600 baud e dovreste avere una cosa simile a questa: (possiamo caricarlo anche dalla cartella File/esempi/wire/scanner)
Una volta terminato apriamo il monitor seriale dove ci verrà visualizzato un risultato del genere:
Quello che ci interessa è il primo indirizzo, che fà riferimento al display OLED, gli altri sono del modulo DS1307 (non servono).
In questo caso, l’indirizzo del display è “0x3C”. Prendiamone nota e proseguiamo con il prossimo passo.
Ora sarà necessario impostare nella libreria Adafruit SSD1306 il tipo di display che stiamo utilizzando (con quale risoluzione), per assicurare il corretto funzionamento del display. Per farlo abbiamo bisogno di aprire la cartella in cui sono salvate le librerie di Arduino. In Windows: apriamo l’esplora file e andiamo nella cartella libraries di Arduino.
Una volta arrivati alla lista delle librerie troviamo e clicchiamo sulla cartella “Adafruit_SSD1306” e apriamo il file “Adafruit_SSD1306.h” con Notepad++. Raggiungiamo la riga, dove vedremo le seguenti righe:
// ONE of the following three lines must be #defined:
//#define SSD1306_128_64 ///< DEPRECTAED: old way to specify 128x64 screen
#define SSD1306_128_32 ///< DEPRECATED: old way to specify 128x32 screen
//#define SSD1306_96_16 ///< DEPRECATED: old way to specify 96x16 screen
Di default la risoluzione abilitata è quella di 128×32. Per modificarla in quella utilizzata dal display che stiamo usando cioè (128×64) sarà necessario modificare la riga “#define SSD1306_128_32” e rimuovere il commento alla riga “//#define SSD1306_128_64” in questo modo:
// ONE of the following three lines must be #defined:
#define SSD1306_128_64 ///< DEPRECTAED: old way to specify 128x64 screen
//#define SSD1306_128_32 ///< DEPRECATED: old way to specify 128x32 screen
//#define SSD1306_96_16 ///< DEPRECATED: old way to specify 96x16 screen
Salviamo il file e chiudiamo il tutto, ora apriamo l'IDE di arduino, dobbiamo fare un ultimo passo, settare la scheda DS1307 per impostare la prima volta l'orario e la data, altrimenti può dare errore.
Occorre caricare e installare lo schetch SetTime.ino che possiamo trovare inserito nella cartella DS1307RTC-master/examples sempre nelle librerie dove è installato Arduino.
Perfetto ora possiamo caricare e installare il seguente codice modificando l’indirizzo I2C annotato in precedenza se necessario.
//OLED TIME
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Time.h>
#include <DS1307RTC.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
void setup()
{
//Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //indirizzo I2C 0x3D (per il 128x64)
//display.display();
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.clearDisplay();
}
void loop()
{
display.clearDisplay();
tmElements_t tm;
if (RTC.read(tm)) {
display.clearDisplay();
display.setTextSize(3); //dimensione testo orario
display.setTextColor(WHITE);
display.setCursor(5, 8); //posizione orario
print2digits(tm.Hour);
display.write(':');
print2digits(tm.Minute);
display.setTextSize(2); //dimensione testo secondi
display.setCursor(100, 8); //posizione secondi
print2digits(tm.Second);
display.setCursor(10, 40); //posizione data
display.setTextSize(2); //dimensione testo data
display.print(tm.Day);
display.write('/');
display.print(tm.Month);
display.write('/');
display.print(tmYearToCalendar(tm.Year));
display.display();
}
else
{
if (RTC.chipPresent())
{
display.setTextSize(1);
display.setTextColor(WHITE);
display.print("DS1307 stopped,run set time");
display.display();
}
else
{
display.setTextSize(1);
display.setTextColor(WHITE);
display.print("DS1307 read error,check circuit");
display.display();
}
delay(9000);
}
delay(1000);
}
void print2digits(int number) {
if (number >= 0 && number < 10) {
display.write('0');
// display.display();
}
display.print(number);
//display.display();
//display.println();
}
Vediamo il risultato:
Vediamo ora una versione con orologio digitale e analogico, più eventualmente temperatura con sensore TM36, io non ho disponibile il sensore in questo momento perciò ho sostituito false alla riga boolean useTMP36 = true; .( se vi interessa sostituite false con true alla riga 44 dello script).
Scaricare e installare la libreria:
/***************************************************************
OLED Clock
display IIC 128x64 OLED with SSD1306 chip
RTC DS1307
sensore temperatura opzionale TMP 36
collegamenti RTC:
VCC +5v
GND GND
SDA Analog pin 4
SCL Analog pin 5
collegamenti OLED:
VCC +5v
GND GND
SDA Analog pin 4
SCL Analog pin 5
collegamenti TMP36:
VCC +3.3v
GND GND
Out Analog pin 1
***************************************************************/
// librerie
#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//
// setup OLED display
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
//
// Setup RTC
RTC_DS1307 RTC;
char monthString[37] = {"JanFebMarAprMayJunJulAugSepOctNovDec"};
int monthIndex[122] = {0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33};
//
//TMP36 Pin Variables
boolean useTMP36 = false; // impostare questo su true se si utilizza sensore TMP36
//boolean useTMP36 = true;
#define aref_voltage 3.3
int tempPin = 1; // il pin analogico a cui è collegato il pin Vout (sense) del TMP36
//la risoluzione è di 10 mV / grado centigrado con a
//Offset 500 mV per consentire temperature negative
int tempReading; // la lettura analogica dal sensore
//
void setup() {
Serial.begin(9600);
// Se si desidera impostare aref su qualcosa di diverso da 5v
analogReference(EXTERNAL);
Wire.begin();
RTC.begin();
if (! RTC.isrunning()) {
Serial.println("RTC is NOT running!");
// la riga seguente imposta l'RTC sulla data e l'ora in cui questo schizzo è stato compilato
RTC.adjust(DateTime(__DATE__, __TIME__));
}
// Usa I2C Scanner per controllare l'indirizzo, se necessario cambia lo 0x3C nella riga sotto
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // inizializza con l'add I2C 0x3C (per 128x64)
// imposta la dimensione del carattere
display.setTextSize(1); // font piccoli
display.setTextColor(WHITE);
display.clearDisplay();
}
void loop() {
//***** RTC **********
DateTime now = RTC.now();
display.setCursor(32, 57);
display.print(now.day(), DEC);
display.print('/');
for (int i = 0; i <= 2; i++) {
display.print(monthString[monthIndex[now.month() - 1] + i]);
}
display.print('/');
display.print(now.year(), DEC);
// *********************
// visualizzazione tempo in formato digitale
display.setCursor(2, 2);
display.print(now.hour(), DEC);
printDigits(now.minute());
printDigits(now.second());
//
// Now draw the clock face
display.drawCircle(display.width() / 2, display.height() / 2, 20, WHITE);
display.drawCircle(display.width() / 2, display.height() / 2, 2, WHITE);
for ( int z = 0; z < 360; z = z + 30 ) {
//Begin at 0° and stop at 360°
float angle = z ;
angle = (angle / 57.29577951) ; //Converti gradi in radianti
int x2 = (64 + (sin(angle) * 20));
int y2 = (32 - (cos(angle) * 20));
int x3 = (64 + (sin(angle) * (20 - 5)));
int y3 = (32 - (cos(angle) * (20 - 5)));
display.drawLine(x2, y2, x3, y3, WHITE);
}
// display second hand
float angle = now.second() * 6 ;
angle = (angle / 57.29577951) ; //Converti gradi in radianti
int x3 = (64 + (sin(angle) * (20)));
int y3 = (32 - (cos(angle) * (20)));
display.drawLine(64, 32, x3, y3, WHITE);
//
// display minute hand
angle = now.minute() * 6 ;
angle = (angle / 57.29577951) ; //Converti gradi in radianti
x3 = (64 + (sin(angle) * (20 - 3)));
y3 = (32 - (cos(angle) * (20 - 3)));
display.drawLine(64, 32, x3, y3, WHITE);
//
// display hour hand
angle = now.hour() * 30 + int((now.minute() / 12) * 6 ) ;
angle = (angle / 57.29577951) ; //Converti gradi in radianti
x3 = (64 + (sin(angle) * (20 - 11)));
y3 = (32 - (cos(angle) * (20 - 11)));
display.drawLine(64, 32, x3, y3, WHITE);
//
// ora aggiunge la temperatura se necessario
if (useTMP36 == true) {
// ottenere la lettura della tensione dal sensore di temperatura
tempReading = analogRead(tempPin);
// convert la lettura della tensione, per arduino 3.3v usare 3.3
float voltage = tempReading * aref_voltage;
voltage /= 1024.0;
// ora stampa la temperatura
int temperatureC = (voltage - 0.5) * 100 ; //conversione da 10 mv per grado con offset 500 mV
display.setCursor(100, 2);
display.print(temperatureC);
display.print("C");
}
// aggiorna il display con tutti i dati
display.display();
delay(100);
display.clearDisplay();
}
// **************** End Main Loop *****************
void printDigits(int digits) {
// funzione utility per la visualizzazione dell'orologio digitale: stampa i due punti precedenti e lo 0 iniziale
display.print(":");
if (digits < 10)
display.print('0');
display.print(digits);
}
Vediamo il risultato:
コメント