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_ */
|