Raspberry PIで、Cライブラリ「WiringPi」を用いて、リアルタイムクロック(RTC)モジュール「RTC-8564NB」を動作させました。西暦(二桁)・月・日・曜・時・分・秒の設定と読み出す時計機能と、32.768kHz,1024Hz, 32Hz, 1HzのCMOS出力が可能で、2番ピンから出力するクロック出力機能を実装しました。なお、RTC-8564NBとRaspberry PIの接続図は、「Raspberry PIへリアルタイムクロックモジュールのI2C接続 」に示します。また、RTC-8564NBのアラーム機能とタイマー機能は「RTC-8564NBによるタイマー作成 」に示します。
WiringPiのインストール
WiringPiを使用するには、I2CライブラリとWiringPi本体をインストールする必要があります。
次のコマンドでI2Cライブラリをインストールします。
# sudo apt-get install libi2c-dev
WiringPi本体はソースコードをgit経由で次のコマンドにより取得します。
# git clone git://git.drogon.net/wiringPi
ダウンロードが完了すると、カレントディレクトリにwiringPiディレクトリができるので、次のコマンドでビルドします。
# cd wiringPi # ./build
RTC-8564NBプログラム作成
RTC-8564NBが持つ機能のうち、時計機能とクロック出力機能を実装します。これらの機能は,RTC-8564NBに内蔵されているレジスタを設定することにより実現可能です。このRTC-8564NBはI2Cで制御するので、Cライブラリ「WiringPi」を用いて、I2Cを制御します。
プログラムのソースコード「rtc.c」を次に示します。setDateTime関数で時計を設定し、getDateTime関数で時計を読み出します。setClkoutFrequency関数は、クロック出力端子「CLKOUT」2ピンにデータを出力し、1秒ごとに点灯/消灯を繰り返すように設定します。
rtc.c
#include <stdio.h> #include <wiringPi.h> #include <wiringPiI2C.h> // I2C Address #define RTCS8564_I2C_ADDRESS 0x51 // Registers #define RTC8564_CONTROL1 0x00 #define RTC8564_CONTROL2 0x01 #define RTC8564_SECONDS 0x02 #define RTC8564_MINUTES 0x03 #define RTC8564_HOURS 0x04 #define RTC8564_DAYS 0x05 #define RTC8564_WEEKDAYS 0x06 #define RTC8564_MONTH_CENTURY 0x07 #define RTC8564_YEARS 0x08 #define RTC8564_MINUTE_ALARM 0x09 #define RTC8564_HOUR_ALARM 0x0a #define RTC8564_DAY_ALARM 0x0b #define RTC8564_WEEKDAY_ALARM 0x0c #define RTC8564_CLKOUT_FREQUENCY 0x0d #define RTC8564_TIMER_CONTROL 0x0e #define RTC8564_TIMER 0x0f // Control1 register #define RTC8564_STOP_BIT 0x20 // Control2 register #define RTC8564_TIE_BIT 0x01 #define RTC8564_AIE_BIT 0x02 #define RTC8564_TF_BIT 0x04 #define RTC8564_AF_BIT 0x08 #define RTC8564_TITP_BIT 0x10 // Calendar registers #define RTCS8564_CAL_VL 0x80 #define RTCS8564_CAL_CENTURY 0x80 // Alarm register #define RTC8564_AE_NONE 0x00 #define RTC8564_AE_MINUTE 0x01 #define RTC8564_AE_HOUR 0x02 #define RTC8564_AE_DAY 0x04 #define RTC8564_AE_WEEKDAY 0x08 #define RTC8564_AE_ALL (RTC8564_AE_MINUTE | RTC8564_AE_HOUR | RTC8564_AE_DAY | RTC8564_AE_WEEKDAY) #define RTC8564_AE_BIT 0x80 // Timer control register #define RTC8564_CLK_244US 0x00 #define RTC8564_CLK_15MS 0x01 #define RTC8564_CLK_1SEC 0x02 #define RTC8564_CLK_1MIN 0x03 #define RTC8564_TE_BIT 0x80 // Clkout frequency register #define RTC8564_CLKOUT_32768HZ 0x00 #define RTC8564_CLKOUT_1024HZ 0x01 #define RTC8564_CLKOUT_32HZ 0x02 #define RTC8564_CLKOUT_1HZ 0x03 #define RTCS8564_FE_BIT 0x80 // date and time struct dateTime { char second; // 0-59 char minute; // 0-59 char hour; // 0-23 char day; // 1-31 char month; // 1-12 char year; // 00-199 char weekday; // 0(Sun)-6(Sat) }; // alarm struct alarmTime { char minute; // 0-59 char hour; // 0-23 char day; // 1-31 char weekday; // 0(Sun)-6(Sat) }; static int dev; static int init_dev(void) { if ((dev = wiringPiI2CSetup(RTCS8564_I2C_ADDRESS)) == -1) { return 1 ; } return 0; } void setRegisters(char address, int numData, char *data) { char adr; int i; adr = address; for (i = 0; i < numData; i++) { wiringPiI2CWriteReg8 (dev, adr, *data); adr ++; data ++; } } void getRegisters(char address, int numData, char *data) { char adr; int i; adr = address; for (i = 0; i < numData; i++) { *data = wiringPiI2CReadReg8 (dev, adr); adr ++; data ++; } } int decimalToBCD(int decimal) { return (((decimal / 10) << 4) | (decimal % 10)); } int BCDToDecimal(int bcd) { return ((bcd >> 4) * 10 + (bcd & 0x0f)); } void setDateTime(struct dateTime *dt) { char data[7]; data[0] = RTC8564_STOP_BIT; setRegisters(RTC8564_CONTROL1, 1, data); data[0] = decimalToBCD(dt->second); data[1] = decimalToBCD(dt->minute); data[2] = decimalToBCD(dt->hour); data[3] = decimalToBCD(dt->day); data[4] = decimalToBCD(dt->weekday); data[5] = decimalToBCD(dt->month); if (dt->year > 100) { data[6] = decimalToBCD(dt->year - 100); data[5] |= RTCS8564_CAL_CENTURY; } else { data[6] = decimalToBCD(dt->year); } setRegisters(RTC8564_SECONDS, 7, data); data[0] = 0x00; setRegisters(RTC8564_CONTROL1, 1, data); } int getDateTime(struct dateTime *dt) { char data[7]; getRegisters(RTC8564_SECONDS, 7, data); if (data[0] & RTCS8564_CAL_VL) { return -1; } dt->second = BCDToDecimal(data[0] & 0x7f); dt->minute = BCDToDecimal(data[1] & 0x7f); dt->hour = BCDToDecimal(data[2] & 0x3f); dt->day = BCDToDecimal(data[3] & 0x3f); dt->weekday = BCDToDecimal(data[4] & 0x07); dt->month = BCDToDecimal(data[5] & 0x1f); dt->year = BCDToDecimal(data[6]); if (data[5] & RTCS8564_CAL_CENTURY) { dt->year += 100; } return 0; } void setClkoutFrequency(char frequency) { frequency |= RTCS8564_FE_BIT; setRegisters(RTC8564_CLKOUT_FREQUENCY, 1, &frequency); } int main(int argc, char **argv) { struct dateTime dt = {0, 0, 0, 1, 1, 13, 2}; // 2013 January 1st, Tue 00:00:50 struct dateTime get_dt; int count ; if(init_dev()==1) return 1; setDateTime(&dt); count = 5; while(count--){ getDateTime(&get_dt); printf("second:%d minute:%d hour:%d\n",get_dt.second,get_dt.minute, get_dt.hour); sleep(5); } setClkoutFrequency( RTC8564_CLKOUT_1HZ); // Setup CLKOUT frequency. return 0; }
コンパイル・リンクは次のコマンドで実行します。
# gcc -o rtc rtc.c -lwiringPi
出来上がったプログラムを次のコマンドで実行します。
# sudo ./rtc
次のように結果が表示され、LEDが1秒ごとに点灯/消灯を繰り返します。
# ./rtc second:0 minute:0 hour:0 second:5 minute:0 hour:0 second:10 minute:0 hour:0 second:15 minute:0 hour:0 second:20 minute:0 hour:0
RTC-8564NBのプログラムは最初は「C library for Broadcom BCM 2835 as used in Raspberry Pi 」を使用して作成し、実際に動作させてみましたが、次の点が分からなくて断念し、違うRaspberry PI用のC言語ライブラリ「WiringPi」を使用して作成しました。
- 書き込みするレジスタの設定、読み出すレジスタの設定など、レジスタのアドレスの設定方法がわからない。
- 一つのAPIで複数のデータが指定できるように、バッファサイズが指定されているが、これは同じレジスタに対して繰り返してreadもしくはWriteするのかが分からない。