Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Interface for the DS1307 RTC.
- */
- #include <avr/io.h>
- #include <avr/interrupt.h>
- #include <avr/pgmspace.h>
- #include <avr/sleep.h>
- #include <stdint.h>
- #include "i2c.h"
- #include <stdio.h>
- #include "uart.h"
- #include "rtc.h"
- // Slave address of the DS1307. Bitwise OR the R/W bit with it.
- #define DS1307_ADDR (0x68 << 1)
- #define UN_BCD(v) (((v) & 0x0F) + 10 * (((v) & 0xF0) >> 4))
- void rtc_regdump() {
- // Register dump
- uart_hexdump(i2c_start(DS1307_ADDR | 1));
- puts_P(PSTR("\r\nRTC register dump:\r"));
- for (int i = 0; i < 6; i++) {
- uart_hexdump(i);
- putchar(':');
- uart_hexdump(i2c_readAck());
- puts_P(PSTR("\r"));
- }
- uart_hexdump(6);
- putchar(':');
- uart_hexdump(i2c_readNak());
- puts_P(PSTR("\r"));
- }
- /*
- * Initializes the RTC. Set up the I2C interface, and starts the RTC's
- * oscillator.
- */
- void rtc_init() {
- i2c_init();
- // Bit 7 of the seconds register must be reset to enable the oscillator,
- // it is initialized to 1 on reset. Date/time are initialized to
- // 0 automatically.
- i2c_start(DS1307_ADDR); // Write
- i2c_write(0); // Register pointer
- i2c_write(0); // Clear register
- i2c_stop();
- }
- void rtc_read_bytes(unsigned char *buffer, char addr, size_t n) {
- i2c_start(DS1307_ADDR); // Write
- i2c_write(addr); // Register pointer
- i2c_rep_start(DS1307_ADDR | 1); // Read..
- while (n-- > 1)
- *buffer++ = i2c_readAck();
- *buffer++ = i2c_readNak();
- }
- void rtc_write_bytes(unsigned char *buffer, char addr, size_t n) {
- i2c_start(DS1307_ADDR);
- i2c_write(addr);
- while (n-- > 0)
- i2c_write(*buffer++);
- i2c_stop();
- }
- /*
- * Closed form for the number of leap years before a given year, where
- * year >= 0. Gregorian calendar.
- */
- unsigned short leapYearsBefore(short year) {
- // Input can't be unsigned, since year 0 is common, which yields several
- // thousand days.
- year--;
- return (year / 4) - (year / 100) + (year / 400);
- }
- /*
- * Return 1 if the given year is a leap year, 0 otherwise.
- * Again, uses the Gregorian calendar.
- */
- char isLeapYear(unsigned short year) {
- return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
- }
- // Length of each month in days.
- const unsigned char month_lens[] PROGMEM = {31,28,31,30,31,30,31,31,30,31,30,31};
- /*
- * Read the time from the RTC, and return it as a number of seconds since
- * 00:00 on Jan 1, year 0.
- */
- time_t rtc_read() {
- i2c_start(DS1307_ADDR);
- i2c_write(0); // Reset register pointer
- i2c_rep_start(DS1307_ADDR | 1);
- unsigned char time_buffer[7];
- for (int i = 0; i < 6; i++) {
- time_buffer[i] = i2c_readAck();
- }
- time_buffer[6] = i2c_readNak();
- i2c_stop();
- // time_buffer now contains the BCD data from the RTC. Decode that into
- // a number of seconds. The epoch is January 1, year 0, since we don't
- // care what time it actually is-- the RTC is used only as an interval
- // timer in this application.
- short year = UN_BCD(time_buffer[6]);
- unsigned char months = UN_BCD(time_buffer[5]);
- // 16 bits enough for 179 years
- unsigned short days = 365 * year + leapYearsBefore(year);
- for (int i = 0; i < months; i++) {
- days += pgm_read_byte(&month_lens[i]);
- }
- if (months > 2 && isLeapYear(year))
- days++; // We're past feb. 29 in this year
- days += UN_BCD(time_buffer[4]);
- // 32 bits enough for 136 years
- time_t seconds = days * 86400;
- seconds += UN_BCD(time_buffer[2]) * 3600;
- seconds += UN_BCD(time_buffer[1]) * 60;
- seconds += UN_BCD(time_buffer[0]);
- return seconds;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement