Arduino-Bibliothek zur Überprüfung des Datums und der Temperatur des integrierten DS3231 über I2C
AKTUALISIERT: Besuchen Sie auch die neue Bibliothek zur Verwaltung von Datum und Uhrzeit mit dem DS3231 RTC-Modul und Arduino mit Verbesserungen wie der Saisonzeit.
Der Betrieb der IC de Echtzeituhren (RTC) am beliebtesten, die mit dem gesteuert werden Bus I2C Normalerweise ist es sehr ähnlich. Neben dem Wire-Bibliothek de Arduino Vereinfacht die Kommunikation mit Geräten erheblich Zweidrahtige serielle Schnittstelle (TWI), I2C, Spezifisch.
Im Großen und Ganzen besteht der Prozess aus
-
Initiieren Sie mit der Funktion die Kommunikation als Slave oder Master (standardmäßig eingestellt). Wire.begin(Adresse). Wenn „Adresse“ weggelassen wird, beginnt die Kommunikation mit dem μC der Lehrer von Bus I2C.
-
Kommunikation aktivieren I2C mit dem Gerät über die Speicheradresse, an der es sich befindet, mithilfe des Befehls Wire.beginTransmission(Adresse).
-
Schreiben Sie eine Bestellung in die Bus I2C um dem Gerät mitzuteilen, welchen Vorgang es ausführen soll Wire.write(Befehl), wobei „order“ der Operationscode ist.
-
Deaktivieren Sie die Kommunikation, um die freizugeben Bus I2C mit Funktion Wire.endTransmission ().
-
Fordern Sie das Gerät mit der Funktion auf, eine bestimmte Datenmenge zu senden, die dem angeforderten Vorgang entspricht (in diesem Fall Datum und Uhrzeit). Wire.requestFrom(Adresse,Betrag).
-
Warten Sie, bis die mit der Funktion angeforderten Daten zum Lesen verfügbar sind Wire.available (), der die Anzahl der bereits empfangenen und lesbaren Daten zurückgibt.
-
Lesen Sie die vom Gerät gesendeten Daten (die Echtzeituhr, in diesem Fall) mit der Funktion Wire.read() so oft wie in Bytes angegeben Wire.available () das sind verfügbar.
-
Normalerweise werden die Daten in sehr kompakten Formaten gesendet, daher ist es sehr wahrscheinlich, dass die empfangenen Daten so interpretiert werden müssen, dass sie der Darstellung der Daten im Programm entsprechen, das das Gerät verwendet.
Bezüglich des DS3231 (und kompatibler Modelle derselben Serie, z. B DS3232) und die Interpretation der Daten gemäß den Spezifikationen des Integrators, beispielsweise werden die Werte der verschiedenen Ziffern dargestellt, die die Zeit darstellen binär codierte Dezimalzahl (BCD) was sich bequemer als Dezimalwert ausdrücken lässt (a Byte) zur Verwendung in Arduino
In derselben Zeile wird die Temperatur als Byte ausgedrückt Zweierkomplement für den ganzzahligen Teil und zwei Bits für den Schritt mit einer Auflösung von einem Viertel Grad des Dezimalteils. Diese und andere Aspekte der Datendarstellung auf der Uhr wurden im folgenden Bibliothekscode ausführlich besprochen. DS3231
Um die Temperatur mit dieser Bibliothek zu überprüfen, verwenden Sie einfach die Methode read_temperature() Objekt DS3231 am Anfang instanziiert. Um Datum und Uhrzeit zu lesen, werden sie zunächst geladen und dann in einem der für verschiedene Zwecke verfügbaren Formate (kompakt, menschlich ...) angefordert, die im Header-Dokument der Codebibliothek unten dokumentiert sind.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | //DS3231.h #if defined(ARDUINO) && ARDUINO>=100 #include “Arduino.h” #else #include “WProgram.h” #endif #include <Wire.h> #define TEMPERATURA_MAXIMA_DS3231 85.0 // Máxima temperatura que se puede medir con un DS3231 (70 grados en la versión comercial / no-industrial) #define TEMPERATURA_MINIMA_DS3231 -40.0 // Mínima temperatura que se puede medir con un DS3231 (0 grados en la versión comercial / no-industrial) #define DIRECCION_DS3231 B1101000 // Según datasheet #define TIMEOUT_I2C_DS3231 200 // Máximo tiempo de espera del bus I2C del DS3231 #define NUMERO_ELEMENTOS_FECHA 7 // Número de elementos (un byte por elemento) que tiene la matriz con los datos de la fecha #define NUMERO_BYTES_TEMPERATURA 2 // Número de bytes con los que se representa la temperatura (uno para la parte entera y el signo y otro para la parte decimal representada con una resolución de 0.25 grados) #define RESOLUCION_DECIMALES_DS3231 0.25 // Grados de cada paso de la parte decimal #define ROTACION_DECIMALES 6 // Rotación necesaria hasta llegar a los bits que contienen la parte que representa los decimales de la temperatura (rotar 6 corresponde a atender a los bits 7 y 8) #define MASCARA_DECIMALES B11000000 // Máscara para eliminar con una operación and la parte no significativa. En el caso el DS3231 no hace nada ya que al rotar queda sólo la parte relevante. class DS3231 { private: char valor_fecha_hora_DS3231[7]; // Matriz de valores numéricos (7 char) de la fecha y la hora. El índice 0 representa los segundos, el 1 los minutos, el 2 las horas (en formato de 24), el 3 el día de la semana empezando en el domingo que es 1, el 4 el día del mes, el 5 el número del mes y el 6 los dos últimos dígitos del año char hora_humana_DS3231[11]; // Hora en el formato hh:mm:ss siendo hh la hora (en formato de 24) representada con 2 dígitos, mm los minutos con 2 dígitos y ss los segundos con 2 dígitos char fecha_humana_DS3231[11]; // Fecha en formato DD/MM/AAAA siendo DD el día representado con 2 dígitos, MM el mes con 2 dígitos y AAAA el año con 4 dígitos char fecha_hora_MySQL_DS3231[20]; // Fecha en formato AAAA-MM-DD hh:mm:ss (estilo MySQL) siendo AAAA el año representado con 4 dígitos, MM el mes con 2 dígitos, DD el día con 2 dígitos, hh la hora (en formato de 24) con 2 dígitos, mm los minutos con 2 dígitos y ss los segundos con 2 dígitos char fecha_hora_compacta_DS3231[13]; // Fecha en formato compacto (como la anterior pero sin adornos y dos dígitos para el año) para escribir en log y en bases de datos char bcd_a_decimal(char bcd); // Convertir de BCD a decimal char decimal_a_bcd(char decimal); // Convertir de decimal a BCD protected: public: DS3231(); ~DS3231(); void cargar_fecha_hora(); void grabar_fecha_hora(char *fecha); char *valor_fecha_hora(); char *hora_humana(); // Hora en el formato hh:mm:ss siendo hh la hora (en formato de 24) representada con 2 dígitos, mm los minutos con 2 dígitos y ss los segundos con 2 dígitos unsigned int reloj_4_digitos_7_segmentos(); // La hora tal como la esperan la mayoría de relojes de cuatro dígitos LED de 7 segmentos char *fecha_humana(); // Fecha en formato DD/MM/AAAA siendo DD el día representado con 2 dígitos, MM el mes con 2 dígitos y AAAA el año con 4 dígitos char numero_dia_semana(); // Eso y empezando en domingo que es el 1 char *fecha_hora_MySQL(); // Fecha en formato AAAA-MM-DD hh:mm:ss (estilo MySQL) siendo AAAA el año representado con 4 dígitos, MM el mes con 2 dígitos, DD el día con 2 dígitos, hh la hora (en formato de 24) con 2 dígitos, mm los minutos con 2 dígitos y ss los segundos con 2 dígitos char *fecha_hora_compacta(); // Fecha en formato compacto (como la anterior pero sin adornos y dos dígitos para el año) para escribir en log y en bases de datos double leer_temperatura(); double temperatura_minima(); double temperatura_maxima(); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | //DS3231.cpp #include “DS3231.h” DS3231::DS3231() { //Wire.begin(); // Dependiendo de la versión del IDE puede ser maestro por defecto o no y habrá que activar en la librería o en la aplicación que la use (en el ejemplo se activa desde la aplicación, lo que permite un uso más genérico) } DS3231::~DS3231() { } void DS3231::cargar_fecha_hora() { unsigned long timeout_i2c; byte contador; Wire.beginTransmission(DIRECCION_DS3231); // Comunicar con el DS3231 en la dirección correspondiente Wire.write(0x00); // pedir registros desde la primera dirección Wire.endTransmission(); // Liberar el bus I2C Wire.requestFrom(DIRECCION_DS3231,NUMERO_ELEMENTOS_FECHA); // esperar NUMERO_ELEMENTOS_FECHA bytes timeout_i2c=millis()+TIMEOUT_I2C_DS3231; while(Wire.available()<NUMERO_ELEMENTOS_FECHA&&millis()<timeout_i2c){} // Esperar a que lleguen los datos o a que pase el tiempo mínimo de espera // Para usar sin espera: if(Wire.available()) for(contador=0;contador<NUMERO_ELEMENTOS_FECHA;contador++) { valor_fecha_hora_DS3231[contador]= Wire.read(); // Leer todos los datos sin discriminar aunque luego tendrán distinto tratamiento } valor_fecha_hora_DS3231[0]=bcd_a_decimal(valor_fecha_hora_DS3231[0]); // segundos en BCD valor_fecha_hora_DS3231[1]=bcd_a_decimal(valor_fecha_hora_DS3231[1]); // minutos en BCD valor_fecha_hora_DS3231[2]=((valor_fecha_hora_DS3231[2]&B00110000)>>4)*10+(valor_fecha_hora_DS3231[2]&B00001111); // BCD en modo de 24 horas valor_fecha_hora_DS3231[3]=valor_fecha_hora_DS3231[3]&B00000111; // Número de día de la semana empezando en 1 que es domingo valor_fecha_hora_DS3231[4]=((valor_fecha_hora_DS3231[4]&B00110000)>>4)*10+(valor_fecha_hora_DS3231[4]&B00001111); // Número del día del mes valor_fecha_hora_DS3231[5]=((valor_fecha_hora_DS3231[5]&B00010000)>>4)*10+(valor_fecha_hora_DS3231[5]&B00001111); // Número de mes (sin MSB) valor_fecha_hora_DS3231[6]=bcd_a_decimal(valor_fecha_hora_DS3231[6]); // Año en BCD (dos últimos dígitos) } char *DS3231::valor_fecha_hora() { //cargar_fecha_hora(); return valor_fecha_hora_DS3231; } char *DS3231::hora_humana() { //cargar_fecha_hora(); sprintf ( hora_humana_DS3231, “%02d:%02d:%02d”, valor_fecha_hora_DS3231[2], valor_fecha_hora_DS3231[1], valor_fecha_hora_DS3231[0] ); return hora_humana_DS3231; } unsigned int DS3231::reloj_4_digitos_7_segmentos() { //cargar_fecha_hora(); return (int)valor_fecha_hora_DS3231[2]*100+(int)valor_fecha_hora_DS3231[1]; } char *DS3231::fecha_humana() { //cargar_fecha_hora(); sprintf ( fecha_humana_DS3231, “%02d/%02d/20%02d”, // Formato de fecha y hora estilo español ¡Olé! valor_fecha_hora_DS3231[4], valor_fecha_hora_DS3231[5], valor_fecha_hora_DS3231[6] ); return fecha_humana_DS3231; } char DS3231::numero_dia_semana() { //cargar_fecha_hora(); return valor_fecha_hora_DS3231[3]; } char *DS3231::fecha_hora_compacta() { //cargar_fecha_hora(); sprintf ( fecha_hora_compacta_DS3231, “%02d%02d%02d%02d%02d%02d”, // Formato de fecha y hora compacta para log y base de datos valor_fecha_hora_DS3231[6], valor_fecha_hora_DS3231[5], valor_fecha_hora_DS3231[4], valor_fecha_hora_DS3231[2], valor_fecha_hora_DS3231[1], valor_fecha_hora_DS3231[0] ); return fecha_hora_compacta_DS3231; } char *DS3231::fecha_hora_MySQL() { //cargar_fecha_hora(); sprintf ( fecha_hora_MySQL_DS3231, “20%02d-%02d-%02d %02d:%02d:%02d”, // Formato de fecha y hora estilo MySQL valor_fecha_hora_DS3231[6], valor_fecha_hora_DS3231[5], valor_fecha_hora_DS3231[4], valor_fecha_hora_DS3231[2], valor_fecha_hora_DS3231[1], valor_fecha_hora_DS3231[0] ); return fecha_hora_MySQL_DS3231; } void DS3231::grabar_fecha_hora(char *fecha) { byte contador; Wire.beginTransmission(DIRECCION_DS3231); // Comunicar con el DS3231 en la dirección correspondiente Wire.write(0x00); // Empezar el envío en la primera dirección for(contador=0;contador<NUMERO_ELEMENTOS_FECHA;contador++) { Wire.write(decimal_a_bcd(fecha[contador])); // Escribir cada valor expresándolo en BCD } Wire.endTransmission(); // Liberar el bus I2C } double DS3231::leer_temperatura() { byte msb; // El byte más significativo contiene la parte entera de la temperatura (en complemento a 2 para poder representar temperaturas bajo cero) byte lsb; // El byte menos significatico contiene la parte decimal con una resolución de un cuarto de grado float temperatura=TEMPERATURA_MAXIMA_DS3231+1.0; // Un número mayor que el máximo como aviso de que algo va mal boolean negativo=false; // Inicialmente se considera postivo unsigned long timeout_i2c; Wire.beginTransmission(DIRECCION_DS3231); // Preparar el dispositivo Wire.write(0x11); // Solicitar temperatura (empieza en 11h y termina en 12h) Wire.endTransmission(); Wire.requestFrom(DIRECCION_DS3231,NUMERO_BYTES_TEMPERATURA); // Esperar temperatura: pedir dos bytes en la dirección del integrado timeout_i2c=millis()+TIMEOUT_I2C_DS3231; while(Wire.available()<NUMERO_BYTES_TEMPERATURA&&millis()<timeout_i2c){}// Esperar a que lleguen los datos o pase el tiempo de espera máximo // Para usar sin espera: if(Wire.available()) msb=Wire.read(); // parte entera con signo en complemento a dos lsb=Wire.read(); // parte fraccional con resolución de 0.25 grados negativo=msb>B01111111; // Es negativo si el primer dígito es uno temperatura=msb&B01111111; // revertir complemento a dos temperatura+=((lsb&MASCARA_DECIMALES)>>ROTACION_DECIMALES)*RESOLUCION_DECIMALES_DS3231; // atender sólo a los bits que contienen la parte decimal (7 y 8), multiplicar por el paso de la resolución y sumar a la parte entera de la temperatura if(negativo) { temperatura*=–1; // Cambiar el signo } return temperatura; } double DS3231::temperatura_minima() { return TEMPERATURA_MINIMA_DS3231; } double DS3231::temperatura_maxima() { return TEMPERATURA_MAXIMA_DS3231; } char DS3231::bcd_a_decimal(char bcd) // Convertir de BCD a decimal { return ((bcd&B11110000)>>4)*10+(bcd&B00001111); } char DS3231::decimal_a_bcd(char decimal) // Convertir de decimal a BCD { return decimal/10*16+(decimal%10); } |
Im Folgenden finden Sie Beispielcode, der die Verwendung der Bibliothek zeigt. Wie oben erwähnt, wird mit der Funktion einfach die Temperatur abgelesen
des Klassenobjekts Um jedoch Fehler beim Ablesen zu ignorieren, werden zwei Konstanten verwendet, die jeweils die maximale und minimale Temperatur des Geräts gemäß Datenblatt speichern und mit den entsprechenden Funktionen gelesen werden.Die Temperaturablesung erfolgt in zwei Schritten: Erstens wird der Wert geladen, damit unterschiedliche Verwendungen des Datums oder der Uhrzeit konsistent sind (in ungünstigen Fällen wird kein höherer Wert angezeigt) und zweitens wird er entsprechend dem Format verwendet, das wird gebraucht. Das Beispielprogramm (das nicht sehr praktisch ist, obwohl es alle Möglichkeiten erklärt) zeigt alle verfügbaren Formate
-
Die Funktion verkohlen (Bytes) mit den sieben numerischen Werten, die Datum und Uhrzeit einer Uhr darstellen DS3231 in Dezimalzahlen umgewandelt (sie sind in BCD auf dem Gerät)
was einen Zeiger auf ein Array zurückgibt -
Verwendung der Funktion
Man erhält einen Wert, der der Nummer des Wochentags entspricht, der am Sonntag beginnt. Um es als Text anzuzeigen, wird ein Array verwendet und eins subtrahiert, um bei Index Null, Sonntag, zu beginnen. -
Um das Datum in einem „lokalen“ (spanischen) Format abzufragen, verwenden Sie die Funktion
, der einen Zeiger auf eine Zeichenfolge zurückgibt, in der das Datum im Format TT/MM/JJJJ dargestellt wird, wobei TT der Tag mit zwei Ziffern, MM der Monat mit zwei Ziffern und JJJJ das Jahr mit vier Ziffern ist. -
Die Funktion
gibt die Zeit im Format hh:mm:ss zurück, wobei hh die Stunde (im 24-Format) mit zwei Ziffern, mm die Minuten mit zwei Ziffern und ss die Sekunden mit zwei Ziffern ist. -
Zur einfachen Nutzung von Datum und Uhrzeit Protokolldateien Die Funktion wurde programmiert , das den Wert von Datum und Uhrzeit im Format YYMMDDhhmmss liefert, wobei AA das Jahr mit den letzten 2 Ziffern ist, MM der Monat mit 2 Ziffern, DD der Tag mit 2 Ziffern, hh die Stunde (im 24-Format) mit 2 Ziffern, mm die Minuten mit 2 Ziffern und ss die Sekunden mit 2 Ziffern. Obwohl es sich um Text handelt, nimmt dieses Format wenig Platz ein und ermöglicht eine sehr einfache alphabetische Sortierung.
-
Die Funktion MySQL (oder das Neue und Freiere MariaDB) YYYY-MM-DD hh:mm:ss, wobei YYYY das Jahr mit 4 Ziffern ist, MM der Monat mit 2 Ziffern, DD der Tag mit 2 Ziffern und hh die Stunde (im 24-Format) mit 2 Ziffern , mm ist die Minute mit 2 Ziffern und die Sekunde mit 2 Ziffern.
dient der Darstellung von Datum und Uhrzeit in dem vom Datenbankmanager verwendeten Format
Obwohl es viele Formate gibt, mit denen Datum und Uhrzeit dargestellt werden können, ist das von Ihnen benötigte möglicherweise nicht vorhanden, aber wenn Sie auf einem der vorhandenen Formate basieren und es als Beispiel verwenden, ist es sicherlich einfach, eine neue Methode hinzuzufügen andere Spezifikationen. Wenn Sie neue Funktionen hinzufügen, teilen Sie uns bitte den Code mit (veröffentlichen Sie ihn!) und erklären Sie uns, wie er funktioniert, damit wir die Bibliothek nach und nach verbessern können. Vielen Dank!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #define INTERVALO_MEDICION 100000 // Medir temperatura cada 100 segundos (se renueva internamente en el DS3231 cada 64 segundos) #define ESPERA_ERROR 1000 // Tiempo de espera antes de volver a medir si se ha producido un error #define ELEMENTOS_MATRIZ_FECHA 7 #include “DS3231.h” #include <Wire.h> char buffer_fecha[ELEMENTOS_MATRIZ_FECHA]; char *puntero_fecha; float temperatura; unsigned long cronometro; byte contador; String dia_semana[]={“lunes”,“martes”,“miércoles”,“jueves”,“viernes”,“sábado”,“domingo”}; DS3231 reloj; void setup() { Serial.begin(9600); Wire.begin(); // Inicializar Wire sólo si no se hace dentro del constructor (de la librería) Este método, hacerlo en la aplicación, supone que se usa Wire para comunicar con otros dispositivos, no sólo con el DS3231 cronometro=0; // para que empiece inmediatamente } void loop() { if(millis()>cronometro) { temperatura=reloj.leer_temperatura(); if(temperatura>reloj.temperatura_maxima()||temperatura<reloj.temperatura_minima()) { cronometro=millis()+ESPERA_ERROR; } else { cronometro=millis()+INTERVALO_MEDICION; reloj.cargar_fecha_hora(); puntero_fecha=reloj.valor_fecha_hora(); for(contador=0;contador<ELEMENTOS_MATRIZ_FECHA;contador++) { buffer_fecha[contador]=*(puntero_fecha+contador); Serial.println(“Contenido de la posición “+String(contador,DEC)+” del buffer de la fecha -> “+String(int(buffer_fecha[contador]),DEC)); } Serial.print(“El día “); Serial.print(reloj.fecha_humana()); Serial.print(“, “); Serial.print(dia_semana[reloj.numero_dia_semana()–1]); Serial.print(“, a las “); Serial.println(reloj.hora_humana()); Serial.print(“(“); Serial.print(reloj.reloj_4_digitos_7_segmentos()); Serial.print(” en un reloj de 4 dígitos y “); Serial.print(reloj.fecha_hora_MySQL()); Serial.print(” según MySQL o “); Serial.print(reloj.fecha_hora_compacta()); Serial.println(” abreviadamente)”); Serial.print(“la temperatura era de “); Serial.print(temperatura); // Mostrar la temperatura Serial.println(” grados centígrados”); } } } |
Die Ausgabe des obigen Beispielprogramms könnte etwa so aussehen, wie im folgenden Bild dargestellt: eine Liste mit 7 Werten (Sekunden, Minuten, Stunde, Wochentag, Tag des Monats, Monat und Jahr), dem Datum und die auf „menschliche“ Weise ausgedrückte Zeit (nach spanischem Stil), die Zeit als ganze Zahl im vierstelligen Uhrenformat, das Datum und die Uhrzeit im Datenbankformat MySQL, Datum und Uhrzeit im Kompaktformat (z Protokolle) und die Innentemperatur des DS3231.
Geben Sie Anmerkung