b. 임베디드/AVR

[ATmega328] DS1307 RTC I2C(TWI)통신 2탄

로봇쟁이 2018. 8. 4. 01:30
1탄에서는 출력만 했는데
이번 2탄에서는 셋업, 출력 두가지를 모두 했습니다. ^^;;

 
#define F_CPU   16000000    //Clock frequency
#define F_SCL   100000      //100kHz
#include <avr/io.h>
#include <stdio.h>
#include <string.h>
#include <util/twi.h>
#include <util/delay.h>
#include <avr/interrupt.h>
 
#define DS1307_R        0xD1
#define DS1307_W        0xD0
#define DS1307_YEAR     0x06
#define DS1307_MONTH    0x05
#define DS1307_DATE     0x04
#define DS1307_DAY      0x03
#define DS1307_HOUR     0x02
#define DS1307_MIN      0x01
#define DS1307_SEC      0x00
 
 
struct Read_DT{
    unsigned char yr, mh, date, dday, hours, minutes, seconds;
};
 
void i2c_init(void) {
    TWSR = 0;
    TWBR = ((F_CPU / F_SCL) - 16) / 2;      //100kHz
    TWCR = 0x04;                            //TWI Enable
}
 
int i2c_start(void) {
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);         // Send Start Condition
    while((TWCR & (1<<TWINT))==0);                  // Wait for TWINT Flag set
    return 0;
}
 
int i2c_write(unsigned char data) {
    TWDR = data;                                    // Load "data" into TWDR Register. 
    TWCR = (1<<TWINT)|(1<<TWEN);                    // Clear TWINT bit in TWCR to start transmission of address
    while((TWCR & (1<<TWINT)) == 0);                // Wait for TWINT Flag set
    return 0;
}
 
unsigned char i2c_read() {
    TWCR = (1<<TWINT)|(1<<TWEN);
    while((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}
 
int i2c_stop(void) {
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);         // Transmit STOP Condition
    return 0;
}
  
unsigned char i2c_getc(unsigned char cmd) {
    i2c_start();
    i2c_write(DS1307_W);
    i2c_write(cmd);
    i2c_start();
    i2c_write(DS1307_R);
    unsigned char data = i2c_read();
    i2c_stop();
    _delay_us(5);
 
    return data;
}
 
void Tx_Char(char Tdata) {
    while(!(UCSR0A & (1<<UDRE0)));
    UDR0 = Tdata;
}
 
void Tx_String(char *str) {
    while(*str) {
        Tx_Char(*str++);
    }
}
 
Read_DT DS1307_now() {
    Read_DT i;
    i.yr = i2c_getc(DS1307_YEAR);
    i.yr = ((i.yr>>4) & 0x0F)*10 + (i.yr & 0x0F);
    i.mh = i2c_getc(DS1307_MONTH);
    i.mh = ((i.mh>>4) & 0x01)*10 + (i.mh & 0x0F);
    i.date = i2c_getc(DS1307_DATE);
    i.date = ((i.date>>4) & 0x03)*10 + (i.date & 0x0F);
 
    i.dday = i2c_getc(DS1307_DAY);
    i.dday = (i.dday & 0x07);
 
    i.hours = i2c_getc(DS1307_HOUR);
    i.hours = ((i.hours>>4) & 0x07)*10 + (i.hours & 0x0F);
    i.minutes = i2c_getc(DS1307_MIN);
    i.minutes = ((i.minutes>>4) & 0x07)*10 + (i.minutes & 0x0F);
    i.seconds = i2c_getc(DS1307_SEC);
    i.seconds = ((i.seconds>>4) & 0x07)*10 + (i.seconds & 0x0F);
    return i;
}
 
void DS1307_set(byte ss, byte mm, byte hr, byte wd, byte md, byte mh, byte yr) {
    i2c_start();
    i2c_write(DS1307_W);
    i2c_write(0x00);
    i2c_write(DecToBcd(ss));    //seconds
    i2c_write(DecToBcd(mm));    //min
    i2c_write(DecToBcd(hr));    //hour
    i2c_write(DecToBcd(wd));    //weekday
    i2c_write(DecToBcd(md));    //day
    i2c_write(DecToBcd(mh));    //month
    i2c_write(DecToBcd(yr));    //year
    i2c_write(0x00);
    i2c_stop();
    _delay_us(5);
}
 
 
byte DecToBcd(byte val) {
    return ((val/10*16) + (val%10));
}
 
 
int main(void) {
    
    char str[30];
    UCSR0A = 0;
    UCSR0B = (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0);    //RX INT EN, RX & TX Enable
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);                    //8bit no parity
    UBRR0H = 0;    UBRR0L = 8;     
    
    i2c_init();
//    DS1307_set(50, 2, 17, 3, 17, 7, 18);
    while(1) {
        char *dday;
        Read_DT dt;
        dt = DS1307_now();
        switch(dt.dday) {
            case 0:
                dday = "SUN";
                break;
            case 1:
                dday = "MON";
                break;
            case 2:
                dday = "TUE";
                break;
            case 3:
                dday = "WED";
                break;
            case 4:
                dday = "TUR";
                break;                                                                
            case 5:
                dday = "FRI";
                break;
            case 6:
                dday = "SAT";
                break;                
        }
        sprintf(str, "%02d-%02d-%02d  %02d:%02d:%02d   %s\r\n", dt.yr+2000, dt.mh, dt.date, dt.hours, dt.minutes, dt.seconds, dday);
        Tx_String(str);
        _delay_ms(500);
    }
}




조금 비교를 하자면

구조체를 이용해서 RTC 데이터를 묶어서 이해하기 편하게 했습니다.


그리고 DS1307_now(), DS1307_set(byte..) 함수를 만들었습니다.

DS1307_now함수는 현재시간을 알려주는 함수이고 set함수는 RTC를 셋업하는 함수입니다.


동작을 한번 시켜보면 금방 알수 있을 듯 합니다. ^^

알람시계는 이제 금방 만들수 있지 않을까요?? ㅎㅎ



반응형