Cライブラリ「WiringPi」を用いて、Raspberry PIでRTC-8564NBのアラーム機能とタイマー機能を持つプログラム作成を作成しました。RTC-8564NBの時計機能とクロック出力機能は「Raspberry PIでRTC-8564NBの時計プログラムの作成 」に示します。

RTC-8564NBが持つ機能のうち、アラーム機能とタイマー機能を実装します。これらの機能は,RTC-8564NBに内蔵されているレジスタを設定することにより実現可能です。このRTC-8564NBはI2Cで制御するので、Cライブラリ「WiringPi」のI2Cを使用します。

アラーム機能は、時間になると通知する機能で、プログラムでは、現在のカレンダ時刻から一分後にアラームを通知するように作成しました。アラーム通知は、RTC-8564NBのレジスタに割り当てられているAlarmFlagが「1」になることにより知ることができます。

タイマー機能は、一定時間になると通知する機能で、プログラムでは、1秒ごとに通知するように作成しました。通知は、RTC-8564NBのレジスタに割り当てられているTimerFlagが「1」になることにより知ることができます。

rtc_int.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);
//  	printf("Write adr:%x data:%x \n",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);
//  	printf("Read adr:%x data:%x \n",adr,*data);
  	adr ++;
  	data ++;
  }
}

int decimalToBCD(int decimal) {
  return (((decimal / 10) << 4) | (decimal % 10));
}

int BCDToDecimal(int bcd) {
  return ((bcd >> 4) * 10 + (bcd & 0x0f));
}

void setAlarm(char enableFlags, struct alarmTime *at, char interruptEnable) {
  char control2;
  char data[4];
  
  // Read Control2 register
  getRegisters(RTC8564_CONTROL2, 1, &control2);

  control2 &= (~RTC8564_AIE_BIT);
  setRegisters(RTC8564_CONTROL2, 1, &control2);

  data[0] = (enableFlags & RTC8564_AE_MINUTE)  ? decimalToBCD(at->minute)  : RTC8564_AE_BIT;
  data[1] = (enableFlags & RTC8564_AE_HOUR)    ? decimalToBCD(at->hour)    : RTC8564_AE_BIT;
  data[2] = (enableFlags & RTC8564_AE_DAY)     ? decimalToBCD(at->day)     : RTC8564_AE_BIT;
  data[3] = (enableFlags & RTC8564_AE_WEEKDAY) ? decimalToBCD(at->weekday) : RTC8564_AE_BIT;
  setRegisters(RTC8564_MINUTE_ALARM, 4, data);

  if (interruptEnable) {
    control2 |= RTC8564_AIE_BIT;
  } else {
    control2 &= ~RTC8564_AIE_BIT;
  }
  setRegisters(RTC8564_CONTROL2, 1, &control2);
}

void getAlarm(char *enableFlags, struct alarmTime *at) {
  char data[4];
  int i;
  
  getRegisters(RTC8564_MINUTE_ALARM, 4, data);
  
  at->minute  = BCDToDecimal(data[0] & 0x7f);
  at->hour    = BCDToDecimal(data[1] & 0x3f);
  at->day     = BCDToDecimal(data[2] & 0x3f);
  at->weekday = BCDToDecimal(data[3] & 0x07);
  
  *enableFlags = 0;
  for (i = 0; i < 4; i++) {
    if (!(data[i] & RTC8564_AE_BIT)) {
      *enableFlags |= (1 << i);
    }
  }
}

int getAlarmFlag() {
  char control2;

  getRegisters(RTC8564_CONTROL2, 1, &control2);

  return (control2 & RTC8564_AF_BIT) ? 1 : 0;
}  

void clearAlarmFlag() {
  char control2;

  getRegisters(RTC8564_CONTROL2, 1, &control2);
  control2 &= ~RTC8564_AF_BIT;
  setRegisters(RTC8564_CONTROL2, 1, &control2);
}  

void setTimer(char enableFlag, char repeatMode, char clockMode, char counter, char interruptEnable) {
  char control2;
  char data[4];
    
  data[0] = 0;
  setRegisters(RTC8564_TIMER_CONTROL, 1, data);
  
  if (enableFlag) {
    getRegisters(RTC8564_CONTROL2, 1, &control2);
    control2 &= ~(RTC8564_TITP_BIT | RTC8564_TF_BIT | RTC8564_TIE_BIT);
    setRegisters(RTC8564_CONTROL2, 1, &control2);
  
    if (repeatMode) {
      control2 |= RTC8564_TITP_BIT;
    }
  
    if (interruptEnable) {
      control2 |= RTC8564_TIE_BIT;
    }
  
    setRegisters(RTC8564_CONTROL2, 1, &control2);
    setRegisters(RTC8564_TIMER, 1, &counter);
  
    clockMode |= RTC8564_TE_BIT;
    setRegisters(RTC8564_TIMER_CONTROL, 1, &clockMode);
  }
}

int getTimerFlag() {
  char control2;

  getRegisters(RTC8564_CONTROL2, 1, &control2);

  return (control2 & RTC8564_TF_BIT) ? 1 : 0;
}  

void clearTimerFlag() {
  char control2;

  getRegisters(RTC8564_CONTROL2, 1, &control2);
  control2 &= ~RTC8564_TF_BIT;
  setRegisters(RTC8564_CONTROL2, 1, &control2);
}


int main(int argc, char **argv) {
  char control[2];
  char data[2];

  struct alarmTime set = {1, 0, 0, 0}; // Alarm : 1 minite
  struct alarmTime get ;
  char enableFlags;
  int count ;
  char control2;
	
  if(init_dev()==1)  return 1;
	
  control[0] =  RTC8564_STOP_BIT;
  control[1] =  0x00;
  sleep(1);	
  setRegisters(RTC8564_CONTROL1, 2, control);
  control[0] = 0x00;
  setRegisters(RTC8564_CONTROL1, 1, control);
	
  getRegisters(RTC8564_MINUTES, 1, data);
  set.minute = BCDToDecimal(data[0] & 0x7f) + 1;
  setAlarm(RTC8564_AE_MINUTE, &set, 0);       // Setup alarm 1 minite
  count = 5;
  while(count){
  	count--;
  	getAlarm(&enableFlags, &get);
  	printf("Alarm minute:%d hour:%d day:%d weekday:%d enableFlags:%x getAlarmFlag:%x\n",
  		get.minute, get.hour,get.day,get.weekday,enableFlags,getAlarmFlag());
    
	sleep(20);	
  }

  setTimer(1, 1, RTC8564_CLK_1SEC, 5, 1);    // Setup timer interrupt.5 sec
  count = 5;
  while(count--){
  	printf("Timer getTimerFlag:%x\n", getTimerFlag());
	sleep(2);	
  }
  return 0;
}

コンパイル・リンクは次のコマンドで実行します。

# gcc -o rtc_int rtc_int.c -lwiringPi

出来上がったプログラムを次のコマンドで実行します。

# sudo ./rtc_int

実行結果を次に示します。アラームは、時間が経過するとAlarmFlagが設定されていることが確認できます。タイマーも同様に時間が経過するとTimerFlagが設定されていることが確認できます。

# ./rtc_int
Alarm minute:40 hour:0 day:0 weekday:0 enableFlags:1 getAlarmFlag:0
Alarm minute:40 hour:0 day:0 weekday:0 enableFlags:1 getAlarmFlag:0
Alarm minute:40 hour:0 day:0 weekday:0 enableFlags:1 getAlarmFlag:0
Alarm minute:40 hour:0 day:0 weekday:0 enableFlags:1 getAlarmFlag:1
Alarm minute:40 hour:0 day:0 weekday:0 enableFlags:1 getAlarmFlag:1
Timer getTimerFlag:0
Timer getTimerFlag:0
Timer getTimerFlag:0
Timer getTimerFlag:1
Timer getTimerFlag:1