RTC-4543(RTC-4543SA/SB)を使う(後編)

前回はこちら
例によってAVRマイコン、ATmega328Pで実験しました。たぶんATtiny2313でも動くと思います。
ちなみに、1Fの電気二重層コンデンサでバックアップする実験をしたところ、4、5日は保持出来そうな感じでした。


port.h(ポート定義ファイル) 回路に応じて変更してください。

/*
 *  EPSON TOYOCOM RTC-4543SA/SB ポート定義 for AVR ATmega328P
 *  port.h
 *  by 99yen 2010/9/12 CC BY-NC
 */

#define RTC_DDR DDRC
#define RTC_PORT PORTC
#define RTC_PIN PINC
#define RTC_CE (1<<PC0)
#define RTC_WR (1<<PC1)
#define RTC_CLK (1<<PC2)
#define RTC_DATA (1<<PC3)

rtc.h(ライブラリヘッダ)

/*
 *  EPSON TOYOCOM RTC-4543SA/SB ライブラリヘッダ for AVR
 *  rtc.h
 *  by 99yen 2010/9/12 CC BY-NC
 */

/* RTC用日時構造体 DATETIME */
typedef struct{
	uint8_t sec;
	uint8_t min;
	uint8_t hour;
	uint8_t wday; /* 曜日(1-7 1:Sun) */
	uint8_t day;
	uint8_t mon;
	uint8_t year; /* 年下2桁(01-99) */
	union{
		uint8_t uint8;
		int8_t int8;
		struct{
			unsigned b0 : 1;
			unsigned b1 : 1;
			unsigned b2 : 1;
			unsigned b3 : 1;
			unsigned b4 : 1;
			unsigned b5 : 1;
			unsigned b6 : 1;
			unsigned b7 : 1;
		}bit;
	}user;
}DATETIME;

/* 関数プロトタイプ宣言 */
void rtc_read(DATETIME *dt);
void rtc_write(const DATETIME *dt);

rtc.c(ライブラリ本体)

/*
 *  EPSON TOYOCOM RTC-4543SA/SB ライブラリ for AVR
 *  rtc.c
 *  by 99yen 2010/9/12 CC BY-NC
 *  WinAVR 20100110でコンパイル確認
 */
#include "port.h"

/* 非公開関数プロトタイプ宣言 */
static inline void _rtc_clk(void);
static inline uint8_t _rtc_getbit(void);
static inline void _rtc_setbit(uint8_t bit);
static inline uint8_t _rtc_get(uint8_t n);
static inline void _rtc_set(uint8_t n, uint8_t data);
static inline void _rtc_toread(void);
static inline void _rtc_towrite(void);
static inline void _rtc_toidle(void);

/* RTCから日時を読み出す */
void rtc_read(DATETIME *dt){
	_rtc_toread();
	
	dt->sec  = _rtc_get(4) + (_rtc_get(3) * 10);
	_rtc_get(1); // FDTビット

	dt->min  = _rtc_get(4) + (_rtc_get(3) * 10);
	dt->user.bit.b0 = _rtc_get(1);

	dt->hour = _rtc_get(4) + (_rtc_get(2) * 10);
	dt->user.bit.b1 = _rtc_get(1);
	dt->user.bit.b2 = _rtc_get(1);

	dt->wday = _rtc_get(3);
	dt->user.bit.b3 = _rtc_get(1);

	dt->day  = _rtc_get(4) + (_rtc_get(2) * 10);
	dt->user.bit.b4 = _rtc_get(1);
	dt->user.bit.b5 = _rtc_get(1);

	dt->mon  = _rtc_get(4) + (_rtc_get(1) * 10);
	dt->user.bit.b6 = _rtc_get(1);
	dt->user.bit.b7 = _rtc_get(1);
	_rtc_get(1); // TMビット

	dt->year = _rtc_get(4) + (_rtc_get(4) * 10);

	_rtc_toidle();
}

/* RTCに日時を書き込む */
void rtc_write(const DATETIME *dt){
	_rtc_towrite();

	_rtc_set(4, dt->sec % 10);
	_rtc_set(3, dt->sec / 10);
	_rtc_set(1, 0); // FDTビット

	_rtc_set(4, dt->min % 10);
	_rtc_set(3, dt->min / 10);
	_rtc_set(1, dt->user.bit.b0);
	
	_rtc_set(4, dt->hour % 10);
	_rtc_set(2, dt->hour / 10);
	_rtc_set(1, dt->user.bit.b1);
	_rtc_set(1, dt->user.bit.b2);

	_rtc_set(3, dt->wday);
	_rtc_set(1, dt->user.bit.b3);

	_rtc_set(4, dt->day % 10);
	_rtc_set(2, dt->day / 10);
	_rtc_set(1, dt->user.bit.b4);
	_rtc_set(1, dt->user.bit.b5);

	_rtc_set(4, dt->mon % 10);
	_rtc_set(1, dt->mon / 10);
	_rtc_set(1, dt->user.bit.b6);
	_rtc_set(1, dt->user.bit.b7);
	_rtc_set(1, 0); // TMビット

	_rtc_set(4, dt->year % 10);
	_rtc_set(4, dt->year / 10);

	_rtc_toidle();
}

/* RTCに1つクロックを送信 */
static inline void _rtc_clk(void){
    RTC_PORT |= RTC_CLK;
    RTC_PORT &= ~RTC_CLK;
}

/* RTCから1ビット取得 */
static inline uint8_t _rtc_getbit(void){
	_rtc_clk();
	if(RTC_PIN & RTC_DATA){
		return 1;
	}
	else{
		return 0;
	}
}

/* RTCに1ビット書き込む */
static inline void _rtc_setbit(uint8_t bit){
	if(bit){
		RTC_PORT |= RTC_DATA;
	}
	else{
		RTC_PORT &= ~RTC_DATA;
	}
	_rtc_clk();
}

/* RTCから指定ビット数取得(LSB) */
static inline uint8_t _rtc_get(uint8_t n){
	uint8_t data = 0;
	uint8_t t, i;

	for(i = 0; i < n ; i++){
		t = _rtc_getbit();
		data |= (t<<i);
	}
	return data;
}

/* RTCに指定ビット数書き込む(LSB) */
static inline void _rtc_set(uint8_t n, uint8_t data){
	uint8_t i;

	for(i = 0; i < n ; i++){
		_rtc_setbit((data>>i) & 1);
	}
}

/* RTCをデータ出力モードに */
/* RTC → AVR */
static inline void _rtc_toread(void){
	RTC_PORT &= ~RTC_DATA;
	RTC_DDR  &= ~RTC_DATA;
	RTC_PORT &= ~RTC_WR;
	RTC_PORT |=  RTC_CE;
}

/* RTCをデータ入力モードに */
/* AVR → RTC */
static inline void _rtc_towrite(void){
	RTC_PORT |= RTC_WR;
	RTC_DDR  |= RTC_DATA;
	RTC_PORT |= RTC_CE;
}

/* RTCを待機モードに */
static inline void _rtc_toidle(void){
	RTC_PORT &= ~RTC_CE;
	RTC_PORT &= ~RTC_DATA;
	RTC_DDR  &= ~RTC_DATA;
}

これらをファイルに保存して、プロジェクトに追加してください。

DATETIME dt;
rtc_read(&dt);

とすると構造体dtに値が入ります。書き込みは

dt.year = 10;
dt.mon = 1;
dt.day = 1;
dt.wday = 6;
dt.hour = 0;
dt.min = 0;
dt.sec = 0;
rtc_write(&dt);

というふうにすればOKです。ユーザービットも使えます。

なお、お約束ですがこのソースを使って起こった結果については保障しません。
ライセンスはCC BY-NCでお願いします。
クリエイティブ・コモンズ・ライセンス