Forum: Projekte & Code DS1307 Lib für Fleury's I2C


von Mos K. (moscito)


Angehängte Dateien:

Lesenswert?

Mahlzeit zusammen,

war in den letzten Tagen vergeblich auf der Suche nach einer DS1307 RTC 
Lib für Peter Fleury's I2C Library.

Also habe ich die Lib von Peteg42 auf "Fleury" umgeschrieben und noch 
ein kleines Schmankerl eingebaut: Man kann nun den RTC auch mit Strings 
auslesen und stellen. Besonders praktisch für LCD und Uart Anwendungen.

Bei mir funzt die Lib einwandfrei.
Da ich kein professioneller Programmierer bin und es sicherlich noch 
genug Platz für Verbesserungen gibt, gibt es die Lib nur "as is".

Verbesserungen sind willkommen, sollten aber bitte vom User selbst 
vorgenommen werden - hab zu wenig Zeit zur Pflege.

Mein kleiner Beitrag zu diesem wundervollen Forum.

Mos Kito
1
/*
2
 * DS1307 RTC driver for an ATMEGA328 (really any AVR with TWI hardware).
3
 *
4
 * (C)opyright 2010, 2011 Peter Gammie, peteg42 at gmail dot com. All rights reserved.
5
 * Commenced September 2010.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *i2c_rep_start
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 *
14
 * 2. Redistributions in binary form must reproduce the above
15
 *    copyright notice, this list of conditions and the following
16
 *    disclaimer in the documentation and/or other materials provided
17
 *    with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
20
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
23
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
 *
31
 * Changed to work with Peter Fleury's I2C Library
32
 * Added string functions for date and time for easy LCD and UART handling
33
 * (C)opyright 2011 Mosci.to
34
 */
35
36
#ifndef _ds1307_H_
37
#define _ds1307_H_
38
39
#include <stdbool.h>
40
41
#include "i2cmaster.h"
42
#include <string.h>
43
44
/* **************************************** */
45
46
/* DS1307-specifics: twi address 0b1101000. Note: shifted left 1. */
47
#define DS1307_ADDR  0xD0
48
49
/* reg0: Turns the clock oscillator on/off. */
50
#define CLOCK_HALT   7
51
52
/* reg7: Square-wave output. */
53
#define SQW_CONTROL_REG 0x07
54
55
#define SQW_OUT         7
56
#define SQW_SQWE        4
57
#define SQW_RS1_RS0_1Hz 0x0
58
59
/* reg2: if TWELVE_HOUR
60
 *         then 12hr mode with AMPM indictor,
61
 *         otherwise 24hr mode. */
62
#define AMPM         _BV(5)
63
#define TWELVE_HOUR  _BV(6)
64
65
/* Unsigned 8-bit BCD operations. */
66
#define fromBCD(x) (((x) >> 4) * 10 + ((x) & 0xF))
67
#define toBCD(x)   ((((x) / 10) << 4) | ((x) % 10))
68
69
/* FIXME add bit widths */
70
struct ds1307_time_t {
71
  uint8_t seconds;
72
  uint8_t minutes;
73
  uint8_t hours;
74
  uint8_t day;
75
  uint8_t date;
76
  uint8_t month;
77
  uint8_t year;
78
};
79
80
/* **************************************** */
81
82
static inline bool ds1307_read(struct ds1307_time_t *time_data)
83
{
84
  uint8_t data;
85
86
  /* Tell the DS1307 we want to read starting at address 0. */
87
  i2c_start_wait(DS1307_ADDR+I2C_WRITE);
88
  i2c_write(0x00);
89
  /* Commence the read. */
90
  i2c_rep_start(DS1307_ADDR+I2C_READ);
91
92
  data=i2c_readAck();
93
  time_data->seconds =  fromBCD(data & ~_BV(CLOCK_HALT));
94
95
  data=i2c_readAck();
96
  time_data->minutes = fromBCD(data);
97
98
  /* Read the hours register. */
99
  data=i2c_readAck();
100
  if(data & TWELVE_HOUR) {
101
    uint8_t hours = fromBCD(data & 0x1F);
102
    if(data & AMPM) {
103
      hours += 12;
104
    }
105
    time_data->hours = hours;
106
  } else {
107
    time_data->hours = fromBCD(data);
108
  }
109
110
  data=i2c_readAck();
111
  time_data->day = fromBCD(data);
112
113
  data=i2c_readAck();
114
  time_data->date = fromBCD(data);
115
116
  data=i2c_readAck();
117
  time_data->month = fromBCD(data);
118
119
  /* Last read, send NACK. */
120
  data=i2c_readNak();
121
  time_data->year = fromBCD(data);
122
123
  i2c_stop();
124
  return true;
125
126
}
127
128
/* FIXME Assumes the time is sane and is a bit hardwired. */
129
static inline bool ds1307_write(struct ds1307_time_t *time_data)
130
{
131
132
  /* Tell the DS1307 we want to start writing at address 0. */
133
  i2c_start_wait(DS1307_ADDR+I2C_WRITE);
134
  i2c_write(0x00);
135
  /* Keep the oscillator running. */
136
  i2c_write(toBCD(time_data->seconds) & ~_BV(CLOCK_HALT));
137
  i2c_write(toBCD(time_data->minutes));
138
  /* FIXME 24hr time. */
139
  i2c_write(toBCD(time_data->hours));
140
  i2c_write(toBCD(time_data->day));
141
  i2c_write(toBCD(time_data->date));
142
  i2c_write(toBCD(time_data->month));
143
  i2c_write(toBCD(time_data->year));
144
145
  i2c_stop();
146
  return true;
147
148
}
149
150
/* Initialise the DS11307. Assumes the TWI interface is already initialised. */
151
static inline bool ds1307_init(bool interrupts)
152
{
153
  /* Tell the DS1307 to start the oscillator (turn off CLOCK HALT) in
154
   * case it has lost power. */
155
  uint8_t reg0;
156
157
  /* Address, say read from memory slot 0, then read data. */
158
  i2c_start_wait(DS1307_ADDR+I2C_WRITE);
159
  i2c_write(0x0);
160
  i2c_rep_start(DS1307_ADDR+I2C_READ);
161
  reg0=i2c_readNak();
162
163
  /* Turn off the clock halt if necessary. */
164
  if(reg0 & _BV(CLOCK_HALT)) {
165
    i2c_start_wait(DS1307_ADDR+I2C_WRITE);
166
    i2c_write(0x0);
167
    i2c_write(reg0 & ~_BV(CLOCK_HALT));
168
  }
169
170
  /* Fire up the 1Hz interrupt. */
171
  if(interrupts) {
172
    i2c_start_wait(DS1307_ADDR+I2C_WRITE);
173
    i2c_write(SQW_CONTROL_REG);
174
    i2c_write(_BV(SQW_SQWE) | SQW_RS1_RS0_1Hz);
175
  }
176
177
  i2c_stop();
178
179
  return true;
180
181
}
182
183
184
void set_time_string(char *time_str2)
185
{
186
  /* Function will use a formatted string containing the current time to set RTC clock 
187
     Format: hh:mm:ss
188
  */
189
  
190
  char time_str1 [3];                                          // Temporary string array
191
  struct ds1307_time_t t;                                      // Declare structure "t" as a copy of structure ds1307_time_t
192
  
193
  ds1307_read(&t);                                            // Read DS1307 and put data in "t struct" so we can write back the date
194
  memset( time_str1, 0, sizeof( time_str1));                  // Empty the temporary string
195
  time_str1[0]=time_str2[0];                                  // Copy first character from source string to temporary string
196
  time_str1[1]=time_str2[1];                                  // Copy second character from source string to temporary string
197
  t.hours=atoi (time_str1);                                    // Convert temporary string to integer value and store in t structure
198
  time_str1[0]=time_str2[3];                                  //
199
  time_str1[1]=time_str2[4];                                  // ... same for the rest of the string
200
  t.minutes=atoi (time_str1);                                  //
201
  time_str1[0]=time_str2[6];                                  //
202
  time_str1[1]=time_str2[7];                                  //
203
  t.seconds=atoi (time_str1);                                  //
204
  ds1307_write(&t);                                            // Write structure to RTC
205
206
  return;                                                      // Return
207
}
208
209
void set_date_string(char *date_str2)
210
{
211
  /* Function will use a formatted string containing the current time to set RTC clock 
212
     Format: dd.mm.yyyy
213
  */
214
  
215
  char date_str1 [3];                                          // Temporary string array
216
  struct ds1307_time_t t;                                      // Declare structure "t" as a copy of structure ds1307_time_t
217
  
218
  ds1307_read(&t);                                            // Read DS1307 and put data in "t struct" so we can write back the time
219
  memset( date_str1, 0, sizeof( date_str1));                  // Empty the string
220
  date_str1[0]=date_str2[0];                                  // Copy first character from source string to temporary string
221
  date_str1[1]=date_str2[1];                                  // Copy second character from source string to temporary string
222
  t.date=atoi (date_str1);                                    // Convert temporary string to integer value and store in t structure
223
  date_str1[0]=date_str2[3];                                  //  
224
  date_str1[1]=date_str2[4];                                  // ... same for the rest of the string
225
  t.month=atoi (date_str1);                                    //
226
  date_str1[0]=date_str2[8];                                  //
227
  date_str1[1]=date_str2[9];                                  //
228
  t.year=atoi (date_str1);                                    //
229
  ds1307_write(&t);                                            // Write structure to RTC
230
231
  return;                                                      // Return
232
}
233
234
  
235
char* get_time_string(void)
236
{
237
  /* Function will return a formatted string containing the current time for easy use on LCD and UART 
238
     Format: hh:mm:ss
239
  */
240
  
241
  char time_str1 [3];                                          // Temporary string array
242
  static char time_str2 [11];                                  // Needs to be static to survive function exit
243
  struct ds1307_time_t t;                                      // Declare structure "t" as a copy of structure ds1307_time_t
244
  
245
  memset( time_str2, 0, sizeof( time_str2));                  // Empty the string to avoid appending
246
  
247
  ds1307_read(&t);                                            // Read DS1307 and put data in "t struct"
248
  if (t.hours<10) strcat (time_str2,"0");                    // Add leading zero if required
249
  itoa (t.hours,time_str1,10);                                // Convert hours into ASCII
250
  strncat (time_str2,time_str1,2);                            // Append hours string to output string
251
  strcat (time_str2,":");                                      // Append ":"
252
  if (t.minutes<10) strcat (time_str2,"0");                  // Add leading zero if required
253
  itoa (t.minutes,time_str1,10);                              // Convert minutes to ASCII
254
  strncat (time_str2,time_str1,2);                            // Append minutes string to output string
255
  strcat (time_str2,":");                                      // Append ":"
256
  if (t.seconds<10) strcat (time_str2,"0");                  // Add leading zero if required
257
  itoa (t.seconds,time_str1,10);                              // Convert seconds to ASCII
258
  strncat (time_str2,time_str1,2);                            // Append seconds string to output string
259
260
  return time_str2;                                            // Return output string
261
}
262
263
264
char* get_date_string(void)
265
{
266
  /* Function will return a formatted string containing the current date for easy use on LCD and UART 
267
     Format: dd.mm.yyyy
268
  */
269
  
270
  char date_str1 [3];                                          // Temporary string array
271
  static char date_str2 [11];                                  // Needs to be static to survive function exit
272
  struct ds1307_time_t t;                                      // Declare structure "t" as a copy of structure ds1307_time_t
273
  
274
  memset( date_str2, 0, sizeof( date_str2));                  // Empty the string to avoid appending
275
  
276
  ds1307_read(&t);                                            // Read DS1307 and put data in "t struct"
277
  if (t.date<10) strcat (date_str2,"0");                      // Add leading zero if required
278
  itoa (t.date,date_str1,10);                                // Convert date into ASCII
279
  strncat (date_str2,date_str1,2);                            // Append date string to output string
280
  strcat (date_str2,".");                                      // Append "."
281
  if (t.month<10) strcat (date_str2,"0");                    // Add leading zero if required
282
  itoa (t.month,date_str1,10);                                // Convert month to ASCII
283
  strncat (date_str2,date_str1,2);                            // Append month string to output string
284
  strcat (date_str2,".20");                                    // Append ".20"
285
  if (t.year<10) strcat (date_str2,"0");                      // Add leading zero if required
286
  itoa (t.year,date_str1,10);                                // Convert year to ASCII
287
  strncat (date_str2,date_str1,2);                            // Append year string to output string
288
289
  return date_str2;                                            // Return output string
290
}
291
292
#endif /* _ds1307_H_ */

von Michael (Gast)


Lesenswert?

SUPER!

bin im Moment dabei eine DS1338 am ATMEGA32 zu verwenden.

habe weder mit RTC noch mit I2C gearbeitet bis jetzt. Habe mich aber 
ebenfalls für die PF lib entschieden, da kommt mir deine umgebaute 
rtc-lib gerade recht.

Das einzige was mir bei der PF lib noch fehlt ist eine function zum 
senden und empfangen von mehreren bytes, so dass man ein array z.b. 
"calender" mit allen inhalten auf einmal übertragen kann.

Wenn ich so weit bin werde ich hie rein kleines update von der ein oder 
andren function hier bringen.

Danke schonmal für das posten, hilft mir gut weiter :)

von Jürgen (Gast)


Lesenswert?

Hi,

ich habe eine bescheidene Frage bezüglich der Funktionen dieser lib.

Ich möchte lediglich einen Funktionsaufruf von ds1307_read un 
ds1308_write starten. In diesen Funktionen sind ja die Zeiger als 
Parameter drin. Sorry, aber ich konnte nirgends finden wie ich diese 
Funktion aus meiner main loop aufrufe.


static inline bool ds1307_read(struct ds1307_time_t *time_data)
static inline bool ds1307_write(struct ds1307_time_t *time_data)


Die Datentypen sind bei mir ebenfalls das struct von der lib

struct ds1307_time_t {
  uint8_t seconds;
  uint8_t minutes;
  uint8_t hours;
  uint8_t day;
  uint8_t date;
  uint8_t month;
  uint8_t year;
}

Wie also rufe ich folgende funktionen (lesen und schreiben auf) Merci 
für die kleine Unterstützung

von bomba (Gast)


Lesenswert?

Hi,

ich habe eine Frage

ich versuche vergeblich diese Funktion get_time_string() aufzurufen und 
auf einem LCD darzustellen. Hat jemand eine idee wie das gehen soll?

Mfg

von Thomas K. (muetze1)


Lesenswert?

@Jürgen:
1
int main(void)
2
{
3
  // init TWI
4
  // init DS1307 (ds1307_init())
5
 
6
  ...
7
8
  ds1307_time_t lTimeStruct;
9
10
  if ( ds1307_read(&lTimeStruct) )
11
  {
12
    // mach was mit der Zeit in lTimeStruct
13
  }
14
  else
15
    // Fehler aufgetreten
16
}

@bomba:

du bekommst einen direkten String zurück, das bedeutet du kannst diesen 
direkt deiner LCD Schreib-Routine übergeben, wenn diese einen char 
Pointer akzeptiert. Aber das hängt vor allem von deiner LCD Bibliothek 
ab - die gibt es schliesslich wie Sand am Meer (wie halt auch 
unterschiedliche Displays & Controller).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.