Advertisement
tari

Untitled

May 29th, 2012
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.56 KB | None | 0 0
  1. /*
  2.  * Interface for the DS1307 RTC.
  3.  */
  4. #include <avr/io.h>
  5. #include <avr/interrupt.h>
  6. #include <avr/pgmspace.h>
  7. #include <avr/sleep.h>
  8. #include <stdint.h>
  9. #include "i2c.h"
  10.  
  11. #include <stdio.h>
  12. #include "uart.h"
  13. #include "rtc.h"
  14.  
  15. // Slave address of the DS1307.  Bitwise OR the R/W bit with it.
  16. #define DS1307_ADDR (0x68 << 1)
  17.  
  18. #define UN_BCD(v) (((v) & 0x0F) + 10 * (((v) & 0xF0) >> 4))
  19.  
  20. void rtc_regdump() {
  21.     // Register dump
  22.     uart_hexdump(i2c_start(DS1307_ADDR | 1));
  23.     puts_P(PSTR("\r\nRTC register dump:\r"));
  24.     for (int i = 0; i < 6; i++) {
  25.         uart_hexdump(i);
  26.         putchar(':');
  27.         uart_hexdump(i2c_readAck());
  28.         puts_P(PSTR("\r"));
  29.     }
  30.     uart_hexdump(6);
  31.     putchar(':');
  32.     uart_hexdump(i2c_readNak());
  33.     puts_P(PSTR("\r"));
  34. }
  35.  
  36. /*
  37.  * Initializes the RTC.  Set up the I2C interface, and starts the RTC's
  38.  * oscillator.
  39.  */
  40. void rtc_init() {
  41.     i2c_init();
  42.     // Bit 7 of the seconds register must be reset to enable the oscillator,
  43.     // it is initialized to 1 on reset.  Date/time are initialized to
  44.     // 0 automatically.
  45.     i2c_start(DS1307_ADDR);     // Write
  46.     i2c_write(0);               // Register pointer
  47.     i2c_write(0);               // Clear register
  48.     i2c_stop();
  49. }
  50.  
  51. void rtc_read_bytes(unsigned char *buffer, char addr, size_t n) {
  52.     i2c_start(DS1307_ADDR);     // Write
  53.     i2c_write(addr);            // Register pointer
  54.     i2c_rep_start(DS1307_ADDR | 1); // Read..
  55.     while (n-- > 1)
  56.         *buffer++ = i2c_readAck();
  57.     *buffer++ = i2c_readNak();
  58. }
  59.  
  60. void rtc_write_bytes(unsigned char *buffer, char addr, size_t n) {
  61.     i2c_start(DS1307_ADDR);
  62.     i2c_write(addr);
  63.     while (n-- > 0)
  64.         i2c_write(*buffer++);
  65.     i2c_stop();
  66. }
  67.  
  68. /*
  69.  * Closed form for the number of leap years before a given year, where
  70.  * year >= 0.  Gregorian calendar.
  71.  */
  72. unsigned short leapYearsBefore(short year) {
  73.     // Input can't be unsigned, since year 0 is common, which yields several
  74.     // thousand days.
  75.     year--;
  76.     return (year / 4) - (year / 100) + (year / 400);
  77. }
  78.  
  79. /*
  80.  * Return 1 if the given year is a leap year, 0 otherwise.
  81.  * Again, uses the Gregorian calendar.
  82.  */
  83. char isLeapYear(unsigned short year) {
  84.     return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
  85. }
  86.  
  87. // Length of each month in days.
  88. const unsigned char month_lens[] PROGMEM = {31,28,31,30,31,30,31,31,30,31,30,31};
  89.  
  90. /*
  91.  * Read the time from the RTC, and return it as a number of seconds since
  92.  * 00:00 on Jan 1, year 0.
  93.  */
  94. time_t rtc_read() {
  95.     i2c_start(DS1307_ADDR);
  96.     i2c_write(0);               // Reset register pointer
  97.  
  98.     i2c_rep_start(DS1307_ADDR | 1);
  99.     unsigned char time_buffer[7];
  100.     for (int i = 0; i < 6; i++) {
  101.         time_buffer[i] = i2c_readAck();
  102.     }
  103.     time_buffer[6] = i2c_readNak();
  104.     i2c_stop();
  105.  
  106.     // time_buffer now contains the BCD data from the RTC.  Decode that into
  107.     // a number of seconds.  The epoch is January 1, year 0, since we don't
  108.     // care what time it actually is-- the RTC is used only as an interval
  109.     // timer in this application.
  110.     short year = UN_BCD(time_buffer[6]);
  111.     unsigned char months = UN_BCD(time_buffer[5]);
  112.     // 16 bits enough for 179 years
  113.     unsigned short days = 365 * year + leapYearsBefore(year);
  114.  
  115.     for (int i = 0; i < months; i++) {
  116.         days += pgm_read_byte(&month_lens[i]);
  117.     }
  118.     if (months > 2 && isLeapYear(year))
  119.         days++;     // We're past feb. 29 in this year
  120.     days += UN_BCD(time_buffer[4]);
  121.  
  122.     // 32 bits enough for 136 years
  123.     time_t seconds = days * 86400;
  124.     seconds += UN_BCD(time_buffer[2]) * 3600;
  125.     seconds += UN_BCD(time_buffer[1]) * 60;
  126.     seconds += UN_BCD(time_buffer[0]);
  127.     return seconds;
  128. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement