I3231C 経由で統合 DS2 の日付と温度をチェックするための Arduino ライブラリ
更新: 新しいページにもアクセスしてください DS3231 RTC モジュールと Arduino で日付と時刻を管理するライブラリ 季節限定時間などの改善が加えられました。
の操作 IC de リアルタイムクロック (RTC) を使用して制御される最も一般的なもの バスI2C 通常は非常によく似ています。さらに、 ワイヤーライブラリ de Arduinoの デバイスとの通信を大幅に簡素化します XNUMX 線式シリアル インターフェイス (TWI), I2C、 特定の。
大まかに言うと、このプロセスは次のとおりです。
-
関数を使用してスレーブまたはマスター (デフォルトで設定) として通信を開始します。 Wire.begin(アドレス)。 「アドレス」を省略した場合は、アドレスから通信が開始されます。 μC の先生 バスI2C.
-
コミュニケーションを活性化する I2C コマンドを使用して、デバイスが配置されているメモリアドレスを介してデバイスと接続します。 Wire.beginTransmission(アドレス).
-
に注文を書きます バスI2C を使用して、デバイスに実行させたい操作を伝えます。 Wire.write(コマンド)ここで、「order」は操作コードです。
-
通信を無効にして解除します。 バスI2C 機能付き Wire.endTransmission().
-
関数を使用して、要求された操作に対応する一定量のデータ (この場合は日付と時刻) の送信をデバイスに要求します。 Wire.requestFrom(アドレス,金額).
-
関数で要求されたデータが読み取り可能になるまで待ちます Wire.available()、すでに受信されており、読み取ることができるデータの数を返します。
-
デバイスから送信されたデータを読み取ります ( リアルタイムクロック、この場合) 関数を使用する Wire.read() 指定されたバイト数だけ Wire.available() 利用可能です。
-
通常、データは非常にコンパクトな形式で送信されるため、デバイスを使用するプログラムで作成されたデータの表現に対応する方法で受信したデータを解釈する必要がある可能性が非常に高くなります。
DS3231(および同シリーズの互換品、 DS3232)および統合された仕様に従ってデータの解釈が行われます。たとえば、時間を表すさまざまな桁の値は次のように表されます。 XNUMX進化XNUMX進数(BCD) これは XNUMX 進数値 (a バイト) で使用する Arduinoの
同じ行で、温度はバイトとして表されます。 XNUMXの補数 整数部分に XNUMX ビット、小数部分の XNUMX 分の XNUMX 度の分解能でステップに XNUMX ビット。クロック上のデータ表現のこれらおよびその他の側面については、以下のライブラリ コードで徹底的に説明されています。 DS3231
このライブラリで温度を確認するには、次のメソッドを使用するだけです 読み取り温度() オブジェクト DS3231 初めにインスタンス化されます。日付と時刻を読み取るには、まず日付と時刻がロードされ、次にさまざまな用途に使用できる形式 (コンパクト、ヒューマンなど) の XNUMX つで要求されます。これは、以下のコード ライブラリのヘッダー ドキュメントに記載されています。
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);
}
|
以下は、ライブラリの使用方法を示すサンプルコードです。前述したように、関数で温度を読み取るだけです。
クラスオブジェクトの ただし、読み取りエラーを無視するために、データシートに従ってデバイスの最高温度と最低温度をそれぞれ保存し、対応する関数で読み取られる XNUMX つの定数が使用されます。温度の読み取りは XNUMX 段階で実行されます。まず、日付または時刻のさまざまな使用が一貫するように値がロードされます (不利な場合にはより高い値が表示されなくなります)。次に、次の形式に従って使用されます。が必要です。サンプル プログラム (すべての可能性を説明していますが、あまり実用的ではありません) は、利用可能なすべての形式を示しています。
-
関数 チャリオット 時計の日付と時刻を表すXNUMXつの数値を含む(バイト) DS3231 XNUMX 進数に変換されます (それらは BCD デバイス上)
配列へのポインタを返します -
機能を使用する
日曜日から始まる曜日の番号に対応する値が取得されます。テキストとして表示するには、配列が使用され、インデックス XNUMX、つまり日曜日から始まるように XNUMX が減算されます。 -
「ローカル」(スペイン語)形式で日付を参照するには、関数を使用します。
は、日付が DD/MM/YYYY 形式で表される文字列へのポインタを返します。DD は 2 桁で表される日、MM は 2 桁で月、YYYY は 4 桁で年です。 -
関数
hh:mm:ss の形式で時刻を返します。hh は 24 桁で表される時 (2 形式)、mm は 2 桁の分、ss は 2 桁の秒です。 -
日付と時刻を簡単に使用するには ログファイル 機能はプログラムされています これは、日付と時刻の値を YYMMDDhhmmss の形式で返します。AA は最後の 2 桁で表される年、MM は 2 桁の月、DD は 2 桁の日、hh は 24 で表される時間 (2 形式) です。桁、mm は 2 桁の分、ss は 2 桁の秒です。この形式は、テキストではありますが、占有スペースがほとんどなく、非常に簡単なアルファベット順の順序が可能です。
-
関数 MySQL (または新しくてより自由な MariaDB) YYYY-MM-DD hh:mm:ss、YYYY は 4 桁で表される年、MM は 2 桁の月、DD は 2 桁の日、hh は 24 桁の時 (2 形式) , mmは2桁の分と2桁の秒です。
データベース管理者が使用する形式で日付と時刻を表示するために使用されます。
日付と時刻を表す形式は多数あり、必要な形式が存在しない可能性もありますが、既存の形式の XNUMX つに基づいてそれを例として使用すると、次のような新しいメソッドを簡単に追加できます。その他の仕様。新しい機能を追加した場合は、コードを共有 (リリースしてください) し、それがどのように機能するかを説明して、ライブラリを少しずつ改良してください。ありがとうございます!
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”);
}
}
}
|
上記のプログラム例の出力は、次の図に示すようなものになります。7 つの値 (秒、分、時、曜日、日、月、年) のリスト、日付、および(スペイン風に)「人間的」に表現された時刻 XNUMX 桁の時計形式の整数としての時刻、データベース形式の日付と時刻 MySQL、コンパクト形式の日付と時刻 ( ログ) と内部温度 DS3231.
コメントを投稿