PICマイコンで現在時刻を取得する。I2C制御の DS3231 を使ってみる

概要

DS3231 を使って現在時刻を取得する!!

PICマイコンで現在時刻を取得したくなり、色々と探していたところ、リアルタイムクロック(RTC)というものを使えば時間を取得できるということがわかりました。AmazonでI2C制御のRTCが売っていたので、今回はそれを使って字時刻を取得しようと思います。

使用機器

DS3231 概要

DS3231 は、EEPROMを備えたRTCです。I2C経由で時刻を書き込むと時刻が保存されます。書き込んだ後は自動で時間が刻まれていきます。

また、電源を切ってもボタン電池があれば、記録した時刻が失われることはありません。

ちなみにCR2032ボタン電池を使うと危ないです。充電式のLIR2032を使用してください。

DS3231 を使用するにはI2Cで制御する必要があります。I2Cについては、この記事で解説しています。

配線図(Fritzing)

DS3231 の配線図
ブレッドボードの配線図

DS3231 制御ヘッダープログラム(DS3231.h)

アドレスの値は、使用する機器によって異なるので、適宜置き換えてください。

RTC_ADR = 動かなければ変更する。

#include <xc.h>
#include <stdint.h>
    
#define RTC_ADR 0xD0
    
struct Date{
    uint8_t year;
    uint8_t month;
    uint8_t day;
    uint8_t hour;
    uint8_t min;
    uint8_t sec;
};

void write_date(struct Date *date);
void read_date(struct Date *date);
uint8_t read_(uint8_t address);
uint8_t bcd_2_decimal(uint8_t number);
uint8_t decimal_2_bcd(uint8_t number);

DS3231 制御プログラム(DS3231.c)


#include "i2c.h"
#include "DS3231.h"

#include "mcc_generated_files/mcc.h"


/**
 * RTC format to number
 * @param number
 * @return 
 */
uint8_t bcd_2_decimal(uint8_t number){
    return ((number >> 4) * 10 + (number & 0x0F));
}

/**
 * number to RCT format
 * @param number
 * @return 
 */
uint8_t decimal_2_bcd(uint8_t number){
    return (((number / 10) << 4) + (number % 10));
}

/**
 * Write date to RTC
 * @param date
 */
void write_date(struct Date *date){
    i2c_start();
    i2c_write(RTC_ADR);
    i2c_write(0x00);

    i2c_write(decimal_2_bcd(date->sec));        //write sec
    i2c_write(decimal_2_bcd(date->min));        //write min
    i2c_write(decimal_2_bcd(date->hour));       //write hour
    i2c_write(1);                               //write day_of_week
    i2c_write(decimal_2_bcd(date->day));        //write day
    i2c_write(decimal_2_bcd(date->month));      //write month
    i2c_write(decimal_2_bcd(date->year));       //write year
    i2c_stop();
    
    __delay_ms(200);
}


/**
 * Read data from RTC
 * @param address (0:sec, 1:min, 2:hour, 3:day_week, 4:day, 5:month, 6:yaer)
 * @return 
 */
uint8_t _read(uint8_t address){
    uint8_t data;
    i2c_start();
    i2c_write(RTC_ADR);
    i2c_write(address);
    
    i2c_repeated_start();
    
    i2c_write(RTC_ADR | 0x01);
    data = bcd_2_decimal(i2c_read(1));
    i2c_stop();
    
    return data;
}

/**
 * Read date from RTC & update date
 * @param date
 */
void read_date(struct Date *date){ 
    date->year = _read(6);      //read year(necessary add 2000)
    date->month = _read(5);     //read month
    date->day = _read(4);       //read day
    _read(3);                   //read day_of_week
    date->hour = _read(2);      //read hour
    date->min = _read(1);       //read min
    date->sec = _read(0);       //read sec
}

メインプログラム(main.c)


#include "mcc_generated_files/mcc.h"
#include "DS3231.h"
#include "i2c.h"


void main(void)
{
    // initialize the device
    SYSTEM_Initialize();
        
    ANSELB = 0xCA;
    
    WPUB = 0x24;
    OPTION_REGbits.nWPUEN = 0;
    
    SSP2ADD = 0x13;
    SSP2CON1 = 0x28;
    SSP2CON2 = 0x0;
    SSP2STAT = 0;
    
    struct Date date;    
    date.year = 20;
    date.month = 11;
    date.day = 15;
    date.hour = 8;
    date.min = 40;
    date.sec = 0;
    
    write_date(&date);
    
            
    read_date(&date);
    
    while (1)
    {
        read_date(&date);        
        __delay_ms(20);
    }
}

コメントする