[[Arduino勉強会]] #contents 2015/05/04からのアクセス回数 &counter; ** RTC(リアルタイムクロック)シールドをつくる [#haabdb0f] *** RTC8564シールド [#oe6494ee] リアルタイムクロックは、価格と入手製を考えて秋月のリアルタイムクロック(RTC)モジュール を使用しました。 - http://akizukidenshi.com/catalog/g/gI-00233/ いつものようにテクノペンで回路を作成しました。(今回はかなり回路が変わりましたので、これは参考程度に!) &ref(RTC8564Shield_sch.png); 最初は、RTCのアラームの割込をD7に付けていたのですが、Arduinoの割込がD2という制約があったので、 修正しました。 &ref(RTC8564Shield_brd.png); このままだと本体の電源を切ったときに、バックアップ電池から本体に電流が流れてしまうため、 RTC8564のVccと本体の間にダイオードを入れ、シールドを外したときにRTC8564が動くように バックアップ電池のGNDをRTC8564のGNDに接続しました。 &ref(RTC8564Shield_brd2.png); *** RTC8564ライブラリ [#t12e35b7] LBEDには、まだ割込クラスInterruptInがないので、珍しくArduino3.3Vでライブラリを 開発しました。 クラス定義は、以下の様にしました。 #pre{{ #define NOT_APPLICABLE (0x80) class RTC8564 { public: RTC8564(PinName sda, PinName scl); void setup(); ~RTC8564(); unsigned char s,m,h,D,W,M; short Y; void read_rtc(); void reset(); void set_time( unsigned short Y, // 年 unsigned char M, // 月 unsigned char D, // 日 unsigned char h, // 時 unsigned char m, // 分 unsigned char s); // 秒 void command(unsigned char reg, unsigned char dat); void set_alarm( unsigned char h, unsigned char m ); void clear_alarm_flag(); protected: unsigned char read(unsigned char reg); I2C _i2c; private: // 10進から16進のBCDコードに変換 unsigned char dec2Bcd(unsigned char val) { return (unsigned char)((val/10) << 4 | val%10); } // 16進のBCDコードから10進に変換 unsigned char bcd2Dec(unsigned char val) { return (unsigned char)((val/16) *10 + val%16); } // y,m, dから曜日を計算する(0を日曜日として0-6を返す) unsigned char zeller(int y, int m, int d) { if (m < 3) { y--; m += 12; } return (unsigned char)( y + y/4 - y/100 + y/400 + ( 13*m + 8 )/5 + d )%7; } }; }} *** 時刻合わせのスケッチ [#ybd3e98e] 新規スケッチを開いて、スケッチ→ライブラリ使用からlbeDuinoとlbeDuinoUserをセットします。 次に以下のスケッチをコピーします。rtc.set_time(2015, 4, 29, 18, 51, 0);の部分に数分後の時刻をセットします。 #pre{{ #include <lbed.h> #include <AQCM0802.h> #include <RTC8564.h> // D8番ピンSDA, D9番ピンSCL AQCM0802 lcd(D8, D9); RTC8564 rtc(D8, D9); // タクトスイッチ DigitalIn sw1(D2); DigitalIn sw2(D3); char buf[12]; int disp_time() { lcd.cls(); lcd.locate(0, 0); sprintf(buf, "%d/%02d/%02d", rtc.Y, rtc.M, rtc.D); lcd.print(buf); lcd.locate(0, 1); sprintf(buf, "%02d:%02d:%02d", rtc.h, rtc.m, rtc.s); lcd.print(buf); } void setup() { sw1.mode(PullUp); sw2.mode(PullUp); lcd.setup(); rtc.setup(); } void loop() { if (!sw1) { rtc.set_time(2015, 4, 29, 18, 51, 0); } rtc.read_rtc(); disp_time(); wait_ms(1000); } }} スケッチをArduino3.3V版に書き込み、セット時刻近くになったらsw1を押し続け、 時間がきたらsw1を離します。 &ref(Run_RTC8564Shield.png); これで、時刻が正確なリアルタイムクロック・シールドは完成です。 ** アラーム機能 [#j95a3e81] リアルタイムクロックへのアラームセットは、set_alarm(h, m)で行います。 アラーム時間になると、D2のピンがLOWになることで、アラームを知らせます。 リアルタイムクロックのアラーム機能のテスト用に、毎分0秒にアラームが鳴るスケッチを作ってみました。 #pre{{ #include "lbed.h" #include "I2cLCD.h" #include "RTC8564.h" I2cLCD lcd(A4, A5, 5); // sda, scl, reset RTC8564 rtc(A4, A5); Tone beep(D3); int hasWakeup = 0; int pin2 = 2; // 割込処理関数 void pin2Interrupt(void) { hasWakeup = 1; } int disp_time() { lcd.cls(); lcd.locate(0, 0); sprintf(buf, "%d/%02d/%02d", rtc.Y, rtc.M, rtc.D); lcd.print(buf); lcd.locate(0, 1); sprintf(buf, "%02d:%02d:%02d", rtc.h, rtc.m, rtc.s); lcd.print(buf); } void setup() { pinMode(pin2, INPUT_PULLUP); lcd.setup(); rtc.setup(); // rtc.set_time(2014, 12, 31, 23, 59, 45); lcd.locate(0, 0); lcd.print("Set Alarm!"); wait_ms(1000); // アラームセット時間hに関係なく(0x80)、毎0秒にアラームをセット rtc.set_alarm(0x80, 0); attachInterrupt (0, pin2Interrupt, FALLING); } void loop() { delay(1000); rtc.read_rtc(); disp_time(); if(hasWakeup) { hasWakeup = 0; lcd.locate(0, 1); lcd.println("Wake Up!"); beep.tone(440, 500); rtc.set_alarm(0x80, (rtc.m+1)%60); } } }} ** 割込クラス(InterruptIn)の作成 [#h6acf24f] 割込処理は、組み込みのシステムでは非常によく使われる技術ですが、 理解するのが難しく、上手く動作しないときのデバッグも大変です。 そのため、lbedではできるだけsetupとloop処理だけでスケッチをまとめて きました。 今回は、リアルタイムクロックのアラームの通知を割込処理を使わないと 実現できないため、割込クラス(InterruptIn)を実装することにしました。 *** クラスの定義 [#g6312029] InterruptInのクラス定義もmbedにならい、以下の様な簡単なものとしました。 #pre{{ class InterruptIn : public DigitalIn { public: InterruptIn(); InterruptIn(PinName pin, const char* name = 0); void rise(void (*fptr)(void)) { setup_interrupt(fptr, 1); } void fall(void (*fptr)(void)){ setup_interrupt(fptr, 0); } private: void setup_interrupt(void(*fptr)(void), int rising); }; }} *** lbeDuinoでRTC8564シールドを動かす [#b580539d] lbeDuinoのPrintクラスの#if 0に変えて#if 1に変えて簡易printfが使えるように しました。Arduino版では、XPrintクラスを追加し、printfが使えるようにしました。 以下のスケッチでbeDuinoでRTC8564シールドを動かしてみました。 ((何かRTCからの最初の割込が上手くとれない時がありますが、タクトスイッチを使うと動くようになりました。)) #pre{{ #include "lbed.h" #include "AQCM0802.h" #include "RTC8564.h" #include "Tone.h" AQCM0802 lcd(A4, A5); // sda, scl, reset RTC8564 rtc(A4, A5); Tone beep(D3); char buf[12]; InterruptIn sw1(D2); int hasWakeup = 0; int pin2 = 2; // 割込処理関数 void pin2Interrupt(void) { hasWakeup = 1; } int disp_time() { lcd.cls(); lcd.locate(0, 0); lcd.printf("%d/%02d/%02d", rtc.Y, rtc.M, rtc.D); lcd.locate(0, 1); lcd.printf("%02d:%02d:%02d", rtc.h, rtc.m, rtc.s); } void setup() { sw1.mode(PullUp); lcd.setup(); rtc.setup(); // rtc.set_time(2014, 12, 31, 23, 59, 45); lcd.locate(0, 0); lcd.print("Set Alarm!"); wait_ms(1000); // アラームセット時間hに関係なく(0x80)、毎0秒にアラームをセット rtc.set_alarm(0x80, 0); sw1.fall(pin2Interrupt); } void loop() { wait_ms(1000); rtc.read_rtc(); disp_time(); if (hasWakeup) { hasWakeup = 0; lcd.locate(0, 1); lcd.println("Wake Up!"); beep.tone(440, 500); rtc.set_alarm(0x80, (rtc.m + 1) % 60); } } }} &ref(Run_RTC8564Shield2.png); 今回の作成したRTC8564ShieldとI2cLCDShield、lbeDuino、Arduino3.3V版です。 &ref(UsedShield.png); ** lbeDuinoのソースの取得 [#g9fdcc38] ここで紹介しましたlbeDuinoのソースは、以下のGitHubから取得できます。 - https://github.com/take-pwave/lbed lbeDuinoに必要なフォルダーは以下の通りです。 - CMSISv2p00_LPC11xx - LBED_lbeDuino - LBED_lbeDuino_USERLIB - LBED_lbeDuino_MAIN サンプルプログラムは、Examplesにあります。詳しくは、[[Arduino勉強会/0I-lbeDuinoの開発環境構築]]を参照してください。 ** コメント [#x9415288] #vote(おもしろかった[39],そうでもない[14],わかりずらい[41]) #vote(おもしろかった[39],そうでもない[15],わかりずらい[41]) 皆様のご意見、ご希望をお待ちしております。勉強会で分からなかったこと等、お気軽に問い合わせて下さい。 スパム防止に画像の文字列も入力してください。 #comment_kcaptcha