-
-
Save cosard/4135891 to your computer and use it in GitHub Desktop.
| #include "uart.h" | |
| #include "rtc.c" | |
| // Baud rate setting | |
| #define BAUD 9600 | |
| void main(void) { | |
| // Serial channel (9600, N,8,1) | |
| uart_init((UART_BAUD_SELECT((BAUD),F_OSC))); | |
| sei(); // interrupt enable | |
| unsigned char sec, temp; | |
| sec = 0; | |
| struct rtc_time ds1302; | |
| struct rtc_time *rtc; | |
| rtc = &ds1302; | |
| ds1302_init(); | |
| ds1302_update(rtc); // update all fields in the struct | |
| ds1302_set_time(rtc, SEC, 31); //set the seconds to 31 | |
| while (1) // read seconds and send it via uart continuously | |
| { | |
| ds1302_update_time(rtc, SEC); //read the seconds | |
| uart_putc(rtc->second); // send byte to serial line , you may not send it via uart, | |
| uart_puts_P( "\r"); // LF // I just want to mention how to use the data with this | |
| _delay_ms(100); | |
| } | |
| } |
| // rtc.c | |
| // author COSAR DINDAR | |
| // Date: November,23th 2012 | |
| #include <avr/interrupt.h> | |
| #include <avr/io.h> | |
| #include <stdio.h> | |
| #include <stdbool.h> | |
| #include <util/delay.h> | |
| #include "rtc.h" | |
| void ds1302_update_time(struct rtc_time * time, unsigned char field) // read time, field can be SEC, MIN, HOUR... | |
| { | |
| unsigned char temp; | |
| ds1302_comms(time, field, 0, READ); | |
| } | |
| void ds1302_set_time(struct rtc_time * time, unsigned char field, unsigned char w_byte) // set time, field can be SEC, MIN, HOUR... | |
| { // w_byte can be the value you want to set | |
| unsigned char temp; | |
| ds1302_comms(time, field, w_byte, WRITE); | |
| } | |
| void ds1302_comms(struct rtc_time * time, unsigned char field, unsigned char write_byte, unsigned char rw) | |
| { | |
| unsigned char temp; | |
| if(rw == READ) | |
| { | |
| if(field == SEC) | |
| { | |
| temp = ds1302_read_byte(sec_r); | |
| time->second = ((temp & 0x0F) + ((temp & 0x70)>>4)*10); | |
| } | |
| else if(field == MIN) | |
| { | |
| temp = ds1302_read_byte(min_r); | |
| time->minute = ((temp & 0x0F) + ((temp & 0x70)>>4)*10); | |
| } | |
| else if(field == HOUR) | |
| { | |
| temp = ds1302_read_byte(hour_r); | |
| if(temp & 0x80 == 1) // 12 format | |
| { | |
| if(temp & 0x20 == 1) // PM | |
| time->hour_format = PM; | |
| else // AM | |
| time->hour_format = AM; | |
| time->hour = ((temp & 0x0F) + ((temp & 0x10)>>4)*10); | |
| } | |
| else // 24 format | |
| { | |
| time->hour_format = H24; | |
| time->hour = ((temp & 0x0F) + ((temp & 0x30)>>4)*10); | |
| } | |
| } | |
| else if(field == DAY) | |
| { | |
| temp = ds1302_read_byte(day_r); | |
| time->day = (temp & 0x07); | |
| } | |
| else if(field == DATE) | |
| { | |
| temp = ds1302_read_byte(date_r); | |
| time->date = ((temp & 0x0F) + ((temp & 0x30)>>4)*10); | |
| } | |
| else if(field == MONTH) | |
| { | |
| temp = ds1302_read_byte(month_r); | |
| time->month = ((temp & 0x0F) + ((temp & 0x10)>>4)*10); | |
| } | |
| else if(field == YEAR) | |
| { | |
| temp = ds1302_read_byte(year_r); | |
| time->year = ((temp & 0x0F) + ((temp & 0xF0)>>4)*10); | |
| } | |
| } | |
| else if(rw == WRITE) | |
| { | |
| if(field == SEC) | |
| { | |
| ds1302_write_byte(sec_w, (((write_byte/10)<<4) & 0x70 | (write_byte%10))); | |
| } | |
| else if(field == MIN) | |
| { | |
| ds1302_write_byte(min_w, (((write_byte/10)<<4) & 0x70 | (write_byte%10))); | |
| } | |
| else if(field == HOUR) | |
| { | |
| if(time->hour_format == AM) | |
| ds1302_write_byte(hour_w, (((write_byte/10)<<4) & 0x10 | (write_byte%10)) | 0x80); | |
| else if(time->hour_format == PM) | |
| ds1302_write_byte(hour_w, (((write_byte/10)<<4) & 0x10 | (write_byte%10)) | 0xA0); | |
| else if(time->hour_format == H24) | |
| ds1302_write_byte(hour_w, ((((write_byte/10)<<4) & 0x30) | (write_byte % 10))); | |
| } | |
| else if(field == DAY) | |
| { | |
| ds1302_write_byte(day_w, write_byte & 0x03); | |
| } | |
| else if(field == DATE) | |
| { | |
| ds1302_write_byte(date_w, (((write_byte/10)<<4) & 0x30 | (write_byte%10))); | |
| } | |
| else if(field == MONTH) | |
| { | |
| ds1302_write_byte(month_w, (((write_byte/10)<<4) & 0x10 | (write_byte%10))); | |
| } | |
| else if(field == YEAR) | |
| { | |
| ds1302_write_byte(year_w, (((write_byte/10)<<4) & 0xF0 | (write_byte%10))); | |
| } | |
| } | |
| } | |
| void ds1302_update(struct rtc_time * time) | |
| { | |
| ds1302_update_time(time, SEC); | |
| ds1302_update_time(time, MIN); | |
| ds1302_update_time(time, HOUR); | |
| ds1302_update_time(time, DAY); | |
| ds1302_update_time(time, DATE); | |
| ds1302_update_time(time, MONTH); | |
| ds1302_update_time(time, YEAR); | |
| } | |
| void ds1302_init(void) // sets all pins as output and low | |
| { | |
| ds1302_PORT |= (1<<rst) | (1<<clk) | (1<<io); | |
| clk_0(); // sclk -> 0 | |
| rst_0(); // rst -> 0 | |
| io_0(); // io -> 0 | |
| } | |
| void ds1302_reset(void) //sets the pins to begin the ds1302 communication | |
| { | |
| clk_0(); // sclk -> 0 | |
| rst_0(); // rst -> 0 | |
| rst_1(); // rst -> 1 | |
| _delay_us(4); | |
| } | |
| unsigned char ds1302_read_byte(unsigned char w_byte) //read the byte with register w_byte | |
| { | |
| unsigned char temp; | |
| ds1302_reset(); | |
| write(w_byte); | |
| temp = read(); | |
| rst_0(); // finish transmittion | |
| clk_0(); | |
| return temp; | |
| } | |
| void ds1302_write_byte(unsigned char w_byte, unsigned char w_2_byte) //write the byte with register w_byte | |
| { | |
| ds1302_reset(); | |
| write(w_byte); | |
| write(w_2_byte); | |
| rst_0(); // finish transmittion | |
| clk_0(); | |
| } | |
| void write(unsigned char W_Byte) //writes the W_Byte to the DS1302 | |
| { | |
| unsigned char i; | |
| ds1302_DDR |= (1<<io); // io as output -> 1 | |
| for(i = 0; i < 8; ++i) | |
| { | |
| io_0(); | |
| if(W_Byte & 0x01) | |
| { | |
| io_1(); | |
| } | |
| clk_0(); | |
| _delay_us(2); | |
| clk_1(); | |
| _delay_us(2); | |
| W_Byte >>=1; | |
| } | |
| } | |
| unsigned char read() //reads the ds1302 reply | |
| { | |
| unsigned char i, R_Byte, TmpByte; | |
| R_Byte = 0x00; | |
| ds1302_DDR &= ~(1<<io); // io as input -> 0 | |
| for(i = 0; i < 8; ++i) //get byte | |
| { | |
| clk_1(); | |
| _delay_us(2); | |
| clk_0(); | |
| _delay_us(2); | |
| TmpByte = 0; | |
| if(bit_is_set(ds1302_PIN,io)) | |
| TmpByte = 1; | |
| TmpByte <<= 7; | |
| R_Byte >>= 1; | |
| R_Byte |= TmpByte; | |
| } | |
| return R_Byte; | |
| } |
| // rtc.c | |
| // author COSAR DINDAR | |
| // Date: November,23th 2012 | |
| #ifndef _RTC_H_ | |
| #define _RTC_H_ | |
| // ds1302 connection | |
| #define ds1302_PORT PORTD | |
| #define ds1302_DDR DDRD | |
| #define ds1302_PIN PIND | |
| #define rst 4 | |
| #define clk 6 | |
| #define io 7 | |
| #define rst_1() ds1302_PORT |= (1<<rst); | |
| #define rst_0() ds1302_PORT &= ~ (1<<rst); | |
| #define clk_1() ds1302_PORT |= (1<<clk); | |
| #define clk_0() ds1302_PORT &= ~ (1<<clk); | |
| #define io_1() ds1302_PORT |= (1<<io); | |
| #define io_0() ds1302_PORT &= ~ (1<<io); | |
| #define AM 10 | |
| #define PM 11 | |
| #define H24 12 | |
| #define READ 15 | |
| #define WRITE 16 | |
| #define mon 1 | |
| #define tue 2 | |
| #define wed 3 | |
| #define thu 4 | |
| #define fri 5 | |
| #define sat 6 | |
| #define sun 7 | |
| #define sec_w 0x80 | |
| #define sec_r 0x81 | |
| #define min_w 0x82 | |
| #define min_r 0x83 | |
| #define hour_w 0x84 | |
| #define hour_r 0x85 | |
| #define date_w 0x86 | |
| #define date_r 0x87 | |
| #define month_w 0x88 | |
| #define month_r 0x89 | |
| #define day_w 0x8a | |
| #define day_r 0x8b | |
| #define year_w 0x8c | |
| #define year_r 0x8d | |
| #define SEC 20 | |
| #define MIN 21 | |
| #define HOUR 22 | |
| #define DAY 22 | |
| #define DATE 23 | |
| #define MONTH 24 | |
| #define YEAR 25 | |
| #define w_protect 0x8e | |
| struct rtc_time{ | |
| char second; | |
| char minute; | |
| char hour; | |
| char day; | |
| char date; | |
| char month; | |
| char year; | |
| char hour_format; | |
| }; | |
| void ds1302_update_time(struct rtc_time *, unsigned char); | |
| void ds1302_set_time(struct rtc_time * time, unsigned char field, unsigned char w_byte); | |
| void ds1302_comms(struct rtc_time *, unsigned char, unsigned char, unsigned char); | |
| void ds1302_update(struct rtc_time *); | |
| void ds1302_init (void); //ds1302 init | |
| void ds1302_reset(void); //ds1302_reset | |
| unsigned char ds1302_read_byte(unsigned char); | |
| void ds1302_write_byte(unsigned char, unsigned char); | |
| void write(unsigned char); | |
| unsigned char read(void); | |
| void ds1302_write_byte(unsigned char,unsigned char); | |
| #endif |
This library have BUG.
between ds1302_reset and read or write must be delay 4uS. Datasheet page 9 AC Electrical charasteristics - RST to CLK setup.
Library works with 3V+ battery. But with low battery voltage it can read bad rtc result.
@bronek999 Thanks for the comment. I will edit it accordingly.
Hi Corsard!
Line #97 of rtc.c shall correctly be
ds1302_write_byte(hour_w, ((((write_byte/10)<<4) & 0x30) | (write_byte % 10)));
& 0x30 instead of & 0x10 is the difference.
Thanks for the lib, anyway! :)
Do you have an avr-libc library for LCD1602 ?
else if(field == YEAR)
{
temp = ds1302_read_byte(year_r);
time->minute = ((temp & 0x0F) + ((temp & 0xF0)>>4)*10);
}
should by time->year =..
rgds
else if(field == YEAR) { temp = ds1302_read_byte(year_r); time->minute = ((temp & 0x0F) + ((temp & 0xF0)>>4)*10); }
should by time->year =..
rgds
Thanks @roman65536 updated based on your comment.
Can I get the uart.h file please ?