#!/usr/bin/env python
# coding: utf-8
# オリジナルの作成:2015/05/04
# # 13-リアルタイムクロックでアラーム時計をつくる
#
# ## RTC(リアルタイムクロック)シールドをつくる
# ### RTC8564シールド
# リアルタイムクロックは、価格と入手製を考えて秋月のリアルタイムクロック(RTC)モジュール を使用しました。
#
# - http://akizukidenshi.com/catalog/g/gI-00233/
#
# いつものようにテクノペンで回路を作成しました。(今回はかなり回路が変わりましたので、これは参考程度に!)
#
#
# 最初は、RTCのアラームの割込をD7に付けていたのですが、Arduinoの割込がD2という制約があったので、 修正しました。
#
#
# このままだと本体の電源を切ったときに、バックアップ電池から本体に電流が流れてしまうため、 RTC8564のVccと本体の間にダイオードを入れ、シールドを外したときにRTC8564が動くように バックアップ電池のGNDをRTC8564のGNDに接続しました。
#
#
# ## RTC8564ライブラリ
# LBEDには、まだ割込クラスInterruptInがないので、珍しくArduino3.3Vでライブラリを 開発しました。
#
# クラス定義は、以下の様にしました。
#
# ```C++
# #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;
# }
# };
# ```
# ### 時刻合わせのスケッチ
# 新規スケッチを開いて、スケッチ→ライブラリ使用からlbeDuinoとlbeDuinoUserをセットします。 次に以下のスケッチをコピーします。rtc.set_time(2015, 4, 29, 18, 51, 0);の部分に数分後の時刻をセットします。
#
# ```C++
# #include
#
# #include
# #include
#
# // 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を離します。
#
#
#
# これで、時刻が正確なリアルタイムクロック・シールドは完成です。
# ## アラーム機能
# リアルタイムクロックへのアラームセットは、set_alarm(h, m)で行います。 アラーム時間になると、D2のピンがLOWになることで、アラームを知らせます。
#
# リアルタイムクロックのアラーム機能のテスト用に、毎分0秒にアラームが鳴るスケッチを作ってみました。
#
# ```C++
# #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)の作成
# 割込処理は、組み込みのシステムでは非常によく使われる技術ですが、 理解するのが難しく、上手く動作しないときのデバッグも大変です。
#
# そのため、lbedではできるだけsetupとloop処理だけでスケッチをまとめて きました。
#
# 今回は、リアルタイムクロックのアラームの通知を割込処理を使わないと 実現できないため、割込クラス(InterruptIn)を実装することにしました。
# ### クラスの定義
# InterruptInのクラス定義もmbedにならい、以下の様な簡単なものとしました。
#
# ```C++
# 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シールドを動かす
# lbeDuinoのPrintクラスの#if 0に変えて#if 1に変えて簡易printfが使えるように しました。Arduino版では、XPrintクラスを追加し、printfが使えるようにしました。
#
# 以下のスケッチでbeDuinoでRTC8564シールドを動かしてみました。
#
# ```C++
# #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);
# }
# }
# ```
#
#
#
# 今回の作成したRTC8564ShieldとI2cLCDShield、lbeDuino、Arduino3.3V版です。
#
#
# ## lbeDuinoのソースの取得
# ここで紹介しましたlbeDuinoのソースは、以下のGitHubから取得できます。
#
# - https://github.com/take-pwave/lbed
#
# lbeDuinoに必要なフォルダーは以下の通りです。
#
# - CMSISv2p00_LPC11xx
# - LBED_lbeDuino
# - LBED_lbeDuino_USERLIB
# - LBED_lbeDuino_MAIN
#
# サンプルプログラムは、Examplesにあります。詳しくは、Arduino勉強会/0I-lbeDuinoの開発環境構築を参照してください。
# In[ ]: