概要
DS3231 を使って現在時刻を取得する!!
PICマイコンで現在時刻を取得したくなり、色々と探していたところ、リアルタイムクロック(RTC)というものを使えば時間を取得できるということがわかりました。AmazonでI2C制御のRTCが売っていたので、今回はそれを使って字時刻を取得しようと思います。
使用機器
DS3231 概要
DS3231 は、EEPROMを備えたRTCです。I2C経由で時刻を書き込むと時刻が保存されます。書き込んだ後は自動で時間が刻まれていきます。
また、電源を切ってもボタン電池があれば、記録した時刻が失われることはありません。
ちなみにCR2032ボタン電池を使うと危ないです。充電式のLIR2032を使用してください。
DS3231 を使用するにはI2Cで制御する必要があります。I2Cについては、この記事で解説しています。
配線図(Fritzing)
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);
}
}