Sim's blog

電子工作はじめてみました

RTC-8564NBを使ってみる

2008-10-13 03:06:11 | AVR
このところI2CでつなげるアイテムとAVRで遊んできました。
- 温度センサーLM73
- カラーセンサーADJD-S371-QR999

今回は秋月で売っているリアルタイムクロックモジュールRTC-8564NBを使ってみました(通販番号I-00233)。このICはある意味定番のようで、ぐぐってみると、いろいろな方が使われています。
メーカーのサイトです。データシートとアプリケーションノートがダウンロードできます。

秋月のモジュールは変換基板上に実装されているので、そのままブレッドボードに挿して使えます。

デフォルトではI2Cのラインはプルアップされていないので、自分でプルアップしてやる必要があります。もしくはジャンパをはんだで盛って接続してやります。プルアップ抵抗は2.2kΩにしています。

ピン配置です(写真と合わせてあります)。
 5 SDA  4 Vss
 6 SCL  3 INT
 7 NC   2 CLKOUT
 8 Vdd  1 CLKOE

CLKOUTは設定で周期を変えれますが、今回は1Hzのパルスを出力しています。CLKOUTをAVRの外部割込み入力INT0につないでいます。割り込みが起きるたびにRTC-8564NBから時間を読み取ってLCDに表示しています。


ソースです。
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/twi.h>
#include <util/delay.h>
#include "lcd.h"
#include "i2c.h"

#define RTC8564 (0x51 << 1)

#define CTRL1 0x00
#define CTRL2 0x01
#define SEC   0x02
#define MIN   0x03
#define HOUR  0x04
#define DAY   0x05
#define WDAY  0x06
#define MONTH 0x07
#define YEAR  0x08
#define CKOUT 0x0d // CLKOUT frequency 7:FE 1:FD1 0:FD0
#define CTRLT 0x0e // Timer Control 7:TE 1:TD1 0:TD0

// RTC8564にコマンドを送る
void write(uint8_t address, uint8_t data)
{
    i2c_start(RTC8564 | TW_WRITE);
    i2c_write(address);
    i2c_write(data);
    i2c_stop();
}

// 曜日の名前
const char *wdname[7] = {
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
};

// 割り込み処理ルーチン (see iomx8.h)
ISR(INT0_vect)
{
    uint8_t year, month, day, wday, hour, min, sec;

    // RTC-8564の読み込み
    i2c_start(RTC8564 | TW_WRITE);
    i2c_write(SEC);
    i2c_stop();
    i2c_start(RTC8564 | TW_READ);
    sec   = i2c_read_ack() & 0x7f; // 02 秒
    min   = i2c_read_ack() & 0x7f; // 03 分
    hour  = i2c_read_ack() & 0x3f; // 04 時
    day   = i2c_read_ack() & 0x3f; // 05 日
    wday  = i2c_read_ack() & 0x07; // 06 曜日
    month = i2c_read_ack() & 0x1f; // 07 月
    year  = i2c_read_nak();        // 08 年
    i2c_stop();

    // 表示
    lcd_locate(0, 0);
    lcd_hex2(0x20);
    lcd_hex2(year);
    lcd_putc('/');
    lcd_hex2(month);
    lcd_putc('/');
    lcd_hex2(day);

    lcd_locate(0, 1);
    lcd_hex2(hour);
    lcd_putc(':');
    lcd_hex2(min);
    lcd_putc(':');
    lcd_hex2(sec);

    lcd_locate(0, 2);
    lcd_puts(wdname[wday]);
}

int main()
{
    lcd_init();
    i2c_init();
    _delay_ms(1000); // 1秒待つ

    // 外部割込み初期化
    EICRA = _BV(ISC01) | _BV(ISC00); // INT0立ち上がりエッジ
    EIMSK = _BV(INT0);  // INT0割り込み許可

    // RTC8564初期化
    write(CTRL1, 0x20); // stop
    write(CTRL2, 0x00);
    write(CTRLT, 0x00);
    write(CKOUT, 0x83); // 7:FE=1 10:FD=11 (1Hz)
    write(YEAR,  0x08); // 年 (下位2桁)
    write(MONTH, 0x10); // 月
    write(DAY,   0x12); // 日
    write(HOUR,  0x23); // 時
    write(MIN,   0x59); // 分
    write(SEC,   0x50); // 秒
    write(WDAY,  0x00); // 曜日
    write(CTRL1, 0x00); // start

    sei();              // 割り込み許可
    while(1){
        sleep_enable(); // CPUスリープ
        sleep_cpu();
        sleep_disable();
    }
}

時間の調整機能がないので、時計としては不完全です。
データはBCDなので、表示するのに割り算がいりません。読み出したデータの上位にはゴミがついているのでちゃんとマスクしてやらないといけません。

今回はじめて使ったのは外部割込みとCPUのスリープです。

勝手にカウントアップしてくれるし、60進数のこととか考えなくても読み出すだけで時計になっているので簡単です。

最新の画像もっと見る

コメントを投稿