DS3231にはアラームが2系統ある。どちらかのアラームが発動すると、INT/SQW端子がローになる。
- アラーム1は
「毎秒(正秒)」
「1分間に1回(秒で指定)」
「1時間に1回(分、秒で指定)」
「いち日に1回(時、分、秒で指定)」
「ひと月に1回(日、時、分、秒で指定)」
「1週間に1回(曜、時、分、秒で指定)」
のいずれかのタイミングでアラームが発動できる。 - アラーム2は
「毎分(正分)」
「1時間に1回(分で指定)」
「いち日に1回(時、分で指定)」
「ひと月に1回(日、時、分で指定)」
「1週間に1回(曜、時、分で指定)」
のいずれかのタイミングでアラームが発動できる。
ここでは、アラーム1を毎分5秒のときに、アラーム2を毎分0秒のときに発動させて、そのタイミングでアラームフラグが立つかどうかをI2C経由でポーリングして確かめる。同時にロジアナでINT/SQW端子を観測する。
#include <avr/io.h> #include <util/delay.h> #include "USART.h" #include "myI2Cv2.h" #include "DS3231.h" int main(){ initUSART(); DS3231 rtc; // リアルタイムクロックDS3231 (I2Cスレーブ)を実体化する。 myI2Cv2.enable(80); // システムクロックの80分周をI2CクロックとしてAVRのI2Cモジュールを有効化する。 rtc.setDateTimeMan(); // USART経由で手動で時刻合わせをして、 printString("***** Set the alarm 1 *****\n"); // USART経由で手動でアラーム1の発動タイミングを設定して、 rtc.setAlarmMan(1); printString("***** Set the alarm 2 *****\n"); // USART経由で手動でアラーム2の発動タイミングを設定して、 rtc.setAlarmMan(2); rtc.enableAlarm(1); // アラーム1を有効化して、 rtc.enableAlarm(2); // アラーム2を有効化して、 while(1){ if(rtc.alarmActivated(1)){ // アラーム1が発動したら、 // 何かをして、 rtc.getDateTimeBCD(); rtc.printDateTime(); printString(" Alarm 1 has been activated.\n"); rtc.clearAlarmFlag(1); // アラーム1発動フラグを解除して、 } if(rtc.alarmActivated(2)){ // アラーム2が発動したら、 // 何かをして、 rtc.getDateTimeBCD(); rtc.printDateTime(); printString(" Alarm 2 has been activated.\n"); rtc.clearAlarmFlag(2); // アラーム2発動フラグを解除して、 } _delay_ms(200); // またアラームの発動を待つ。を繰り返す。 } myI2Cv2.disable(); return 0; }
uint8_t alarmActivated(uint8_t whichAlarm); // アラームが出たかどうか void enableAlarm(uint8_t whichAlarm); // アラームを有効化する。 void disableAlarm(uint8_t whichAlarm); // アラームを無効化する。 void clearAlarmFlag(uint8_t whichAlarm); // アラームフラグをクリアする。 void setAlarmBCD(uint8_t whichAlarm, uint8_t *buff); // アラーム発動タイミングを設定。buffは{秒,分,時,曜/日}または{分,時,曜/日}。 void setAlarmMan(uint8_t whichAlarm); // USART経由で手動でアラーム発動タイミングを設定。setAlarmBCD()も含めて実行する。
uint8_t DS3231::alarmActivated(uint8_t whichAlarm){ myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_W); // スレーブに呼びかけて、writeであることを示して、 myI2Cv2.writeByte(CONTROL_STATUS); // スレーブ側のレジスタポインタをセットして、 myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_R); // スレーブに呼びかけて、readであることを示して、 uint8_t cs = myI2Cv2.readByteNACK(); // 目的のCONTROL_STATUSレジスタの内容を読み出して、 myI2Cv2.stop(); // ストップコンディションを生成して、 /* if (whichAlarm==1){return (cs & 0b01) == 0b01;} // アラーム1が出たかどうかを返す。 else if(whichAlarm==2){return (cs & 0b10) == 0b10;} // アラーム2が出たかどうかを返す。*/ return (cs & whichAlarm) && 1; // アラームが出たかどうかを返す。 } void DS3231::enableAlarm(uint8_t whichAlarm){ clearAlarmFlag(whichAlarm); // 念のためアラームフラグをクリアしておく。 myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_W); // スレーブに呼びかけて、writeであることを示して、 myI2Cv2.writeByte(CONTROL); // スレーブ側のレジスタポインタをセットして、 myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_R); // スレーブに呼びかけて、readであることを示して、 uint8_t cnt = myI2Cv2.readByteNACK(); // 目的のCONTROLレジスタの内容を読み出して、 /* if (whichAlarm==1){cnt |= (0b101);} // INTCNビットとA1IEビットとをセットする。 else if(whichAlarm==2){cnt |= (0b110);} // INTCNビットとA2Eビットとをセットする。*/ cnt |= (0b100 | whichAlarm); // INTCNビット(ビット[2])と、A2EビットかA1Eビットかいずれかとをセットする。 myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_W); // スレーブに呼びかけて、writeであることを示して、 myI2Cv2.writeByte(CONTROL); // スレーブ側のレジスタポインタをセットして、 myI2Cv2.writeByte(cnt); // そのレジスタを書き換えて、 myI2Cv2.stop(); // ストップコンディションを生成する。 } void DS3231::disableAlarm(uint8_t whichAlarm){ myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_W); // スレーブに呼びかけて、writeであることを示して、 myI2Cv2.writeByte(CONTROL); // スレーブ側のレジスタポインタをセットして、 myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_R); // スレーブに呼びかけて、readであることを示して、 uint8_t cnt = myI2Cv2.readByteNACK(); // 目的のCONTROLレジスタの内容を読み出して、 // cnt &= ~(0b111); // INTCN、A2IE、A1IEの各ビットをクリアして、 cnt &= ~whichAlarm; // A2IE、A1IEのどちらかのビットをクリアして、 myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_W); // スレーブに呼びかけて、writeであることを示して、 myI2Cv2.writeByte(CONTROL); // スレーブ側のレジスタポインタをセットして、 myI2Cv2.writeByte(cnt); // そのレジスタを書き換えて、 myI2Cv2.stop(); // ストップコンディションを生成する。 } void DS3231::clearAlarmFlag(uint8_t whichAlarm){ myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_W); // スレーブに呼びかけて、writeであることを示して、 myI2Cv2.writeByte(CONTROL_STATUS); // スレーブ側のレジスタポインタをセットして、 myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_R); // スレーブに呼びかけて、readであることを示して、 uint8_t cs = myI2Cv2.readByteNACK(); // 目的のCONTROLレジスタの内容を読み出して、 /* if (whichAlarm==1){cs &= ~(0b01);} // A1Fビットをクリアして、 else if(whichAlarm==2){cs &= ~(0b10);} // A2Fビットをクリアして、*/ cs &= ~whichAlarm; // A2FビットまたはA1Fビットをクリアして、 myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_W); // スレーブに呼びかけて、writeであることを示して、 myI2Cv2.writeByte(CONTROL_STATUS); // スレーブ側のレジスタポインタをセットして、 myI2Cv2.writeByte(cs); // そのレジスタを書き換えて、 myI2Cv2.stop(); // ストップコンディションを生成する。 } void DS3231::setAlarmBCD(uint8_t whichAlarm, uint8_t *buff){ // myI2Cv2.start(); // スタートコンディションを生成して、 myI2Cv2.writeByte(ADDRESS_W); // スレーブに呼びかけて、writeであることを示して、 if (whichAlarm==1){myI2Cv2.writeByte(ALARM_1_SECOND); myI2Cv2.writeBytes(4, buff);} else if(whichAlarm==2){myI2Cv2.writeByte(ALARM_2_MINUTE); myI2Cv2.writeBytes(3, buff);} myI2Cv2.stop(); // ストップコンディションを生成する。 } void DS3231::setAlarmMan(uint8_t whichAlarm){ if(whichAlarm==1){ uint8_t buff[4] = {0x80, 0x80, 0x80, 0x80}; // マスクビット(ビット[7])はとりあえず最初に全部マスクしておく。 printString("Select from the followings:\n"); printString("0: Alarm once per second\n"); printString("1: Alarm when seconds match\n"); printString("2: Alarm when minutes and seconds match\n"); printString("3: Alarm when hours, minutes, and seconds match\n"); printString("4: Alarm when date, hours, minutes, and seconds match\n"); printString("5: Alarm when day, hours, minutes, and seconds match\n"); uint8_t mode = contain(getNumber(), 0, 5); switch(mode){ case 0: break; case 1: printString("Set seconds, 0-59: "); buff[0] = dec2bcd(contain(getNumber(), 0, 59)); break; case 2: printString("Set minutes, 0-59: "); buff[1] = dec2bcd(contain(getNumber(), 0, 59)); printString("Set seconds, 0-59: "); buff[0] = dec2bcd(contain(getNumber(), 0, 59)); break; case 3: printString("Set hours, 0-23: ") ; buff[2] = dec2bcd(contain(getNumber(), 0, 23)); printString("Set minute, 0-59: ") ; buff[1] = dec2bcd(contain(getNumber(), 0, 59)); printString("Set seconds, 0-59: "); buff[0] = dec2bcd(contain(getNumber(), 0, 59)); break; case 4: printString("Set a date, 1-31: ") ; buff[3] = dec2bcd(contain(getNumber(), 1, 31)); printString("Set hours, 0-23: ") ; buff[2] = dec2bcd(contain(getNumber(), 0, 23)); printString("Set minutes, 0-59: "); buff[1] = dec2bcd(contain(getNumber(), 0, 59)); printString("Set seconds, 0-59: "); buff[0] = dec2bcd(contain(getNumber(), 0, 59)); break; case 5: printString("Set a day, 1-7, e.g. Mon=1, Sun=7: "); buff[3] = contain(getNumber(), 1, 7); printString("Set hours, 0-23: ") ; buff[2] = dec2bcd(contain(getNumber(), 0, 23)); printString("Set minutes, 0-59: ") ; buff[1] = dec2bcd(contain(getNumber(), 0, 59)); printString("Set seconds, 0-59: ") ; buff[0] = dec2bcd(contain(getNumber(), 0, 59)); buff[3] |= (1 << 6); // 曜ビットに1を立てる。 break; default:break; } setAlarmBCD(1, buff); } if(whichAlarm==2){ uint8_t buff[3] = {0x80, 0x80, 0x80}; // マスクビット(ビット[7])はとりあえず最初に全部マスクしておく。 printString("Select from the followings:\n"); printString("0: Alarm once per minute\n"); printString("1: Alarm when minutes match\n"); printString("2: Alarm when hours and minutes match\n"); printString("3: Alarm when date, hours, and minutes match\n"); printString("4: Alarm when day, hours, and minutes match\n"); uint8_t mode = contain(getNumber(), 0, 4); switch(mode){ case 0: break; case 1: printString("Set minutes, 0-59: "); buff[0] = dec2bcd(contain(getNumber(), 0, 59)); break; case 2: printString("Set hours, 0-23: ") ; buff[1] = dec2bcd(contain(getNumber(), 0, 23)); printString("Set minutes, 0-59: "); buff[0] = dec2bcd(contain(getNumber(), 0, 59)); break; case 3: printString("Set a date, 1-31: ") ; buff[2] = dec2bcd(contain(getNumber(), 1, 31)); printString("Set hours, 0-23: ") ; buff[1] = dec2bcd(contain(getNumber(), 0, 23)); printString("Set minutes, 0-59: "); buff[0] = dec2bcd(contain(getNumber(), 0, 59)); break; case 4: printString("Set a day, 1-7, e.g. Mon=1, Sun=7: "); buff[2] = contain(getNumber(), 1, 7); printString("Set hours, 0-23: ") ; buff[1] = dec2bcd(contain(getNumber(), 0, 23)); printString("Set minutes, 0-59: ") ; buff[0] = dec2bcd(contain(getNumber(), 0, 59)); buff[2] |= (1 << 6); // 曜ビットに1を立てる。 break; default:break; } setAlarmBCD(2, buff); } }