以前の記事でRTCモジュールを使った基本的な時計の使い方を紹介したが、今回はアラーム機能を使った割り込みによる定期処理を行う方法について説明する。
Arduinoで例えば1分毎に何らかの処理を行いたい場合、loop処理内でdelay関数で60000ms程度待機させる方法もあるが、バッテリー駆動させる場合は電力の無駄だし、delayと処理を繰り返すたびに少しずつずれが生じてくる。
バッテリーを節約する方法としてWatchdogタイマーとSleepを使う方法もあるが、最長8秒のためインターバルが分や時間単位になるとやや処理が面倒になってくる。
そこでDS3231系のRTCモジュールのアラーム機能を使うと、毎秒、毎分、毎時間、毎日、毎週等の単位で簡単に割り込みを起こし定期処理を行う事が出来る。RTCモジュールなので、Arduinoの簡易時計機能よりも正確である。
配線は通信用のSCL/SDAと、割り込み用にSQWピンを使う。SQWピンは波形生成と共通のため、アラーム機能を使う場合は波形生成の機能はオフにしておく必要がある。下記配線例はArduino MEGA。Arudino UNOであればPin 2もしくは3をSQWと繋ぐ。
ライブラリは下記ライブラリを使用。
https://github.com/JChristensen/DS3232RTC
秒単位で指定したい場合はAlarm 1を、分単位で指定する場合はAlarm 2を使う。RTCモジュールの時計はすでに合わせてあるものとする。
使い方は簡単で、attachInterruptで割り込みが変化した際に実行する関数を指定(RTCの割り込みはLOWになるので、FALLING指定)、setAlarmで割り込みのタイミングを指定、alarmInterrupt関数でアラームを有効化、alarm関数で割り込みフラグをリセットする。
下記サンプルコードは毎分00秒にRTCから割り込みを発生させ、シリアルポートに時刻を出力後電力セーブモードに入るコードである。
//Reference : //https://github.com/JChristensen/DS3232RTC //http://forum.arduino.cc/index.php?topic=109062.0 //http://donalmorrissey.blogspot.jp/2010/04/sleeping-arduino-part-5-wake-up-via.html //http://easylabo.com/2015/04/arduino/8357/ #include <DS3232RTC.h> //http://github.com/JChristensen/DS3232RTC #include <Time.h> //http://www.arduino.cc/playground/Code/Time #include <Wire.h> //http://arduino.cc/en/Reference/Wire (included with Arduino IDE) #include <avr/sleep.h> #include <avr/power.h> bool rtcint = false; void setup(void) { //clear all RTC.alarmInterrupt(1, false); RTC.alarmInterrupt(2, false); RTC.oscStopped(true); //sync time with RTC module Serial.begin(9600); setSyncProvider(RTC.get); // the function to get the time from the RTC if (timeStatus() != timeSet) Serial.println("Unable to sync with the RTC"); else Serial.println("RTC has set the system time"); Serial.flush(); //show current time, sync with 0 second digitalClockDisplay(); synctozero(); //set alarm to fire every minute RTC.alarm(2); attachInterrupt(4, alcall, FALLING); RTC.setAlarm(ALM2_EVERY_MINUTE , 0, 0, 0); RTC.alarmInterrupt(2, true); digitalClockDisplay(); } void loop(void) { //process clock display and clear interrupt flag as needed if (rtcint) { rtcint = false; digitalClockDisplay(); RTC.alarm(2); } //go to power save mode enterSleep(); } void synctozero() { //wait until second reaches 0 while (second() != 0) { delay(100); } } void alcall() { //per minute interrupt call rtcint = true; } void digitalClockDisplay(void) { // digital clock display of the time setSyncProvider(RTC.get); //sync time with RTC Serial.print(hour()); printDigits(minute()); printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); Serial.flush(); } void printDigits(int digits) { // utility function for digital clock display: prints preceding colon and leading 0 Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void enterSleep(void) { //enter sleep mode to save power set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_mode(); sleep_disable(); power_all_enable(); }
電子ペーパーディスプレイと組み合わせた時計作成も参考に。
[GPG] Arduino用RTCモジュール DS3231 / AT24C32
はじめまして
当方、Arduino unoとDS3231を用いて、こちらの定期処理を行いたいと考えております。初歩的な質問なのですが、DS3231の時計合わせはどのようにするのでしょうか。お時間ありましたら、教えていただけると大変助かります。どうぞ宜しくお願い致します。