test

2011/08/02 先負 投稿時の月齢:2.2  月名:三日月  潮汐:中潮 Moon:2.2 - 12:13 am by chameleon

Click for Kasugai, Japan Forecast

駿河湾で地震

- 12:05 am by chameleon

やけに揺れた気がするけど、自分の地方で震度3らしい。
駿河湾が震源らしいので、地震がだんだん近づいてきている気がするのは気のせいか・・・。

研修なう

2011/08/01 友引 投稿時の月齢:1.7  月名:二日月  潮汐:大潮 Moon:1.7 - 11:38 am by chameleon

研修会参加中
いい息抜きです!

長期出張から帰ってきました

2011/07/21 友引 投稿時の月齢:20.6  月名:二十日余の月  潮汐:中潮 Moon:20.6 - 11:10 pm by chameleon

世間では夏休みが始まっているという今日、ようやく出張から解放されました。一週間以上の激戦でした・・・。
日本じゃ台風が来ていたらしいですが、外に出したままのものも、そのまま同じ場所にありましたから風はたいしたことなかったのでしょうか・・・。

デジタル台風とかで移動軌跡をみると、かなり変なふうに動いたようです。
もっとも自分の移動ルートはこの台風の比ではありませんが・・・。

不本意ながら

2011/07/14 先勝 投稿時の月齢:13.6  月名:待宵月  潮汐:大潮 Moon:13.6 - 10:06 pm by chameleon

今日も関連企業の皆様と飲み会でした・・・。まったく、転職後は、このような会は数知れず・・・。
飲み会に行くのに休暇を取っていかなければならないのも何とも・・・。

暑い だが、29度設定

2011/07/13 赤口 投稿時の月齢:12.5  月名:十三夜  潮汐:中潮 Moon:12.5 - 8:17 pm by chameleon

全く暑い。職場ではエアコン設定温度は29℃かつ、それに達するまでは稼働さえしない。
昼休み中及び、終業後は即座に切れる。もちろん始業前に稼働していることはない。
職場を観察していると、温厚な人々もエアコンが切れると、キレ始める。
このような状況なので、贅沢な設定温度にすることもできないが、あまり除湿されないので相当に苦しいことは間違いない状況だ。

外気の方がひんやりと感じる。

本日の気温等の観測結果は図の通りです。
昼頃の日射が若干少なくなっていますが、昼休み中はエアコンもオフとなっていますから、室内はむしろ暑苦しくなっていましたね。
早く涼しくなってほしい。

CORESERVER不調

2011/07/12 大安 投稿時の月齢:11.5  月名:十二日月  潮汐:中潮 Moon:11.5 - 8:51 pm by chameleon

利用しているサーバーで昨日から障害が発生していました。昨日中には障害は解決されたようですが、自分のアカウントではMySQLサーバーへの接続が確立できませんでした。

初めて、レンタルサーバーのサポート使いました。500円払うと優先サポート権が得られるらしいので、それで対応を依頼しました。きわめて迅速に対応していただけました。データベースのバックアップもとれない状況だったので、だめならいい潮時とサイトを閉じる気持ちも若干ありました。

障害が出る前から、サイトにアクセスするとページが開かなかったりやたらと重かったりして、リロードしたりしてしのいでいたんですが、今回の障害の対応後は今のところ順調な感じです。正直サーバーが逼迫しているのかぁ、空いている所へ引っ越そうかと、別のレンタルサーバーを調べたりもしていたのですが、結果的に十分満足な状況になりました。まだ、しばらくはサイトも続けられそうです。

とはいえ、ずっとこのブログも更新していませんでした。
いや、転職後ほんとに仕事が忙しかったんです。で、今は気象観測の研究中です。

次の更新はいつになるのか・・・。

本日、ほぼ退職

2011/03/31 仏滅 投稿時の月齢:27.0  月名:二十八日月  潮汐:中潮 Moon:27.0 - 9:07 pm by chameleon

長らくつとめていた職種を離れ、本日異動しました。
明日から、全く新しい職場にてお仕事です。環境も激変、仕事内容も激変です。
とりあえず今日は新しい職場の駐車場を確認してきました・・・。

と、久しぶりのブログの更新・・・。引き継ぎを含めてほんとに忙しかったです。明日からはさらに・・・。

ArduinoUnoでRealTimeClockをNTPと同期させる Step.3 Aruduino IDE Ver.0021用にライブラリを修正する

2010/12/03 先勝 投稿時の月齢:26.8  月名:二十七日月  潮汐:中潮 Moon:26.8 - 12:15 am by chameleon

ArduinoUnoでRealTimeClockをNTPと同期させる Step.2 RTC8564用ライブラリの制作で、RealTimeClockを利用して、Aruduinoに計時させようと考えているわけですが、そもそも基準となる正確な時間をどのように与えるのかという問題があります。
やはり、NTPサーバーより時刻を得るのがいいのではないかと考えて、Aruduinoの開発環境用に作成されたライブラリ「Time Library」を利用してみることにします。
ダウンロードして得られた「Time.zip」を解凍すると「DS1307RTC」「Time」「TimAlarms」のフォルダができるので、librariesフォルダにコピーします。

そして、サンプルスケッチに「TimeNTP.pde」というNTPサーバーから時刻を得るスケッチがありましたので、Aruduino IDE Ver.0021環境からAruduino Unoに当該スケッチをアップロードしてみます。
TimeNTP.pdeをIDEで開いて確認すると、冒頭部分に

#include <Time.h> 
#include <Ethernet.h>
#include <UdpBytewise.h>  // UDP library from: bjoern@cs.stanford.edu 12/30/2008 
#if  UDP_TX_PACKET_MAX_SIZE <64 ||  UDP_RX_PACKET_MAX_SIZE <64
#error : UDP packet size to small - modify UdpBytewise.h to set buffers to 64 bytes
#endif

と記述されていて、他にも「UdpBytewise.h」が必要なことがわかります。NTPサーバーはUDPを利用しますから、UDP関連のライブラリがいくつか必要なようです。このライブラリ一式はここからダウンロードできます。解凍したらできあがったファイルを「Ethernet Library」フォルダにコピーします。
ちなみに、UdpBytewise.hに記述されていてるUDP_TX_PACKET_MAX_SIZE とUDP_RX_PACKET_MAX_SIZE の値を64に変更しておけと書いてありますから、直しておきます。

では、コンパイルしてみます。はい・・・見事エラーの嵐ですね。
どうやらSPI.hをインクルードしろといっているようです。確かIDEがVer.0019になってからEthernet Liburaryを使うときにはインクルードが必要になりました。
TimeNTP.pdeに以下を書き加えます。

#include <SPI.h>

さて、もう一度コンパイルしてみます。ますますひどいエラーの洗礼を受けました。これだけ一気に表示されると意味がわかりませんね・・・。
気を取り直して落ち着いてエラーを見ながら考えてみます。まずtypes.hについて解決します。これは「UdpBytewise.cpp」を以下のように修正して解決します。

//extern "C" {
//#include "types.h"
#include "w5100.h"
#include "socket.h"
//}

次に、 ‘Sn_MR_UDP’と ‘getSn_RX_RSR’が宣言されていないというエラーを解決します。いや、確かに宣言されていません。インクルードされているファイルに宣言されているのでしょう。いやいやいやいや、宣言されていないからエラーになるんだから、「かつて宣言されていた」変数名と考えた方がいいわけですね。つまり、依存しているライブラリのコードが修正されて、命名方法が変わったと言うことでしょう。となると、AruduinoIDEの純正ライブラリ群が怪しいです。関連するライブラリをざっと見ます。 ‘Sn_MR_UDP’と ‘getSn_RX_RSR’という命名からソケット関係のライブラリじゃないかと見当をつけておきます。やはり、UDPライブラリの中で、’Sn_MR_UDP’と ‘getSn_RX_RSR’に対応する新しい命名の変数を見つけました。これが変わっていたので、IDEのVer.0019あたりからコンパイルエラーが出るようです。

すべてを修正したコードを次に記述しておきます。
UdpBytewise.cpp

/*
* UdpBytewise.cpp: Library to send/receive UDP packets with the Arduino ethernet shield.
* Drop UdpBytewise.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/
* TODO: should protect buffer access with critical sections
*
* MIT License:
* Copyright (c) 2008 Bjoern Hartmann
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* bjoern@cs.stanford.edu 12/30/2008
*/
 
//extern "C" {
//#include "types.h"
#include "w5100.h"
#include "socket.h"
//}
 
#include "Ethernet.h"
#include "UdpBytewise.h"
 
/* Start UDP socket, listening at local port PORT */
void UdpBytewiseClass::begin(uint16_t port) {
     _port = port;
     _sock = 0; //TODO: should not be hardcoded
     _txIndex =0;
     _rxIndex =0;
     _rxSize = 0;
     _txOverflowStrategy = UDP_TX_OVERFLOW_SPLIT;
     //socket(_sock,Sn_MR_UDP,port,0);
     socket(_sock,SnMR::UDP,_port,0);
}
 
 
/* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes. */
int UdpBytewiseClass::available() {
     if(_rxSize==0 || _rxSize-_rxIndex==0) {
           //if local buffer is empty or depleted
           //check wiz5100 buffer for new packet
           // _rxSize = getSn_RX_RSR(_sock); //note: return value is inflated by 8 byte header
              _rxSize = W5100.getRXReceivedSize(_sock); //note: return value is inflated by 8 byte header
           if(_rxSize){
                 //if we have a new packet there
                 //reset buffer index
                 _rxIndex=0;
                 //copy packet into our local buffer
                 _rxSize = recvfrom(_sock,_rxBuffer,_rxSize-8,_rxIp,&_rxPort);
           } else {
                 //else do nothing and rxsize is still 0
                 ;
           }
           return _rxSize; //return the new number of bytes in our buffer
     } else{
           //if buffer is not empty, return remaining # of bytes
           return (_rxSize-_rxIndex);
     }
}
 
 
/* Start a new packet with given target ip and port
* returns 1 on success, 0 if we already started a packet */
int UdpBytewiseClass::beginPacket(uint8_t *ip, unsigned int port) {
     if(_txIndex==0) {
           //ok to start new packet - copy ip and port
           _txIp[0]=ip[0];
           _txIp[1]=ip[1];
           _txIp[2]=ip[2];
           _txIp[3]=ip[3];
           _txPort = port;
           return 1;
     }
     else {
           //we already started a packet and have data in it
           return 0;
     }
}
 
 
/* Add a byte to the currently assembled packet if there is space
* if there isn't space, either truncate (ignore) or split the packet.
*/
void UdpBytewiseClass::write(uint8_t b) {
     if(_txIndex>= UDP_TX_PACKET_MAX_SIZE) {
           //buffer is full - we can either truncate the packet or split in two
           switch (_txOverflowStrategy) {
                 case UDP_TX_OVERFLOW_SPLIT:
                       endPacket();
                       beginPacket(_txIp,_txPort);
                       //fall through to normal add of byte to buffer below
                       break;
                 case UDP_TX_OVERFLOW_TRUNCATE:
                 default:
                       //don't add - just ignore bytes past buffer size
                       return;
           }
     }
     _txBuffer[_txIndex++] = b;
}
 
/* send an assembled packet out
* returns # of bytes sent on success, 0 if there's nothing to send */
int UdpBytewiseClass::endPacket() {
     // send the packet
     uint16_t result = sendto(_sock,(const uint8_t *)_txBuffer,_txIndex,_txIp,_txPort);
     // reset buffer index
     _txIndex=0;
     // return sent bytes
     return (int)result;
}
 
/* read the next byte of the last rececived packet */
int UdpBytewiseClass::read() {
     if(_rxIndex <_rxSize) {
           // if there is something to be read, return the next byte
           return _rxBuffer[_rxIndex++];
     } else {
           //we already sent the last byte - nothing to do
           return -1;
     }
}
 
void UdpBytewiseClass::getSenderIp(uint8_t*ip) {
     ip[0]=_rxIp[0];
     ip[1]=_rxIp[1];
     ip[2]=_rxIp[2];
     ip[3]=_rxIp[3];
}
 
unsigned int  UdpBytewiseClass::getSenderPort() {
     return _rxPort;
}
 
/* what should we do when we try to add to a full outgoing packet?
* UDP_TX_OVERFLOW_TRUNCATE - throw overflow bytes away
* UDP_TX_OVERFLOW_SPLIT - split into multiple packets
*/
void UdpBytewiseClass::setOverflowStrategy(uint8_t strategy) {
     _txOverflowStrategy = strategy;
}
 
/* Create one global object */
UdpBytewiseClass UdpBytewise;

コンパイルすると通りました。

さらに、今回は必要ありませんでしたが、UdpRawというライブラリもIDE Ver.0021でコンパイルすると同様のエラーが出ますので、上記と同じ変数を同じように修正します。
同様にいかに修正したファイルを掲載しておきます。

UdpRaw.cpp

/*
 *  UdpRaw.cpp: Library to send/receive UDP packets with the Arduino ethernet shield.
 *  This version only offers minimal wrapping of socket.c/socket.h
 *  Drop UdpRaw.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ 
 *
 * MIT License:
 * Copyright (c) 2008 Bjoern Hartmann
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * bjoern@cs.stanford.edu 12/30/2008
 */
 
//extern "C" {
//#include "types.h"
#include "w5100.h"
#include "socket.h"
//}
 
#include "Ethernet.h"
#include "UdpRaw.h"
 
/* Start UDP socket, listening at local port PORT */
void UdpRawClass::begin(uint16_t port) {
    _port = port;
    _sock = 0; //TODO: should not be hardcoded
    //socket(_sock,Sn_MR_UDP,_port,0);
    socket(_sock,SnMR::UDP,_port,0);//Sn_MR_UDP
}
 
/* Send packet contained in buf of length len to peer at specified ip, and port */
/* Use this function to transmit binary data that might contain 0x00 bytes*/
/* This function returns sent data size for success else -1. */
uint16_t UdpRawClass::sendPacket(uint8_t * buf, uint16_t len,  uint8_t * ip, uint16_t port){
    return sendto(_sock,(const uint8_t *)buf,len,ip,port);
}
 
/* Send  zero-terminated string str as packet to peer at specified ip, and port */
/* This function returns sent data size for success else -1. */
uint16_t UdpRawClass::sendPacket(const char str[], uint8_t * ip, uint16_t port){    
    // compute strlen
    const char *s;
    for(s = str; *s; ++s);
    uint16_t len = (s-str);
    // send packet
    return sendto(_sock,(const uint8_t *)str,len,ip,port);
}
/* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes. 
 * returned value includes 8 byte UDP header!*/
int UdpRawClass::available() {
    //return getSn_RX_RSR(_sock);//W5100.getRXReceivedSize(_sock);
    return W5100.getRXReceivedSize(_sock);//getSn_RX_RSR(_sock);
}
 
 
/* Read a received packet into buffer buf (which is of maximum length len); */
/* store calling ip and port as well. Call available() to make sure data is ready first. */
/* NOTE: I don't believe len is ever checked in implementation of recvfrom(),*/
/*       so it's easy to overflow buffer. so we check and truncate. */
/* returns number of bytes read, or negative number of bytes we would have needed if we truncated */
int UdpRawClass::readPacket(uint8_t * buf, uint16_t bufLen, uint8_t *ip, uint16_t *port) {
    int packetLen = available()-8; //skip UDP header;
    if(packetLen <0 ) return 0; // no real data here    
    if(packetLen > (int)bufLen) {
        //packet is too large - truncate
        //HACK - hand-parse the UDP packet using TCP recv method
        uint8_t tmpBuf[8];
        int i;
        //read 8 header bytes and get IP and port from it
        recv(_sock,tmpBuf,8);
        ip[0] = tmpBuf[0];
        ip[1] = tmpBuf[1];
        ip[2] = tmpBuf[2];
        ip[3] = tmpBuf[3];
        *port = tmpBuf[4];
        *port = (*port <<8) + tmpBuf[5];
        
        //now copy first (bufLen) bytes into buf        
        for(i=0;i<(int)bufLen;i++) {
            recv(_sock,tmpBuf,1);
            buf[i]=tmpBuf[0];
        }
        
        //and just read the rest byte by byte and throw it away
        while(available()) {
            recv(_sock,tmpBuf,1);
        }
        
        return (-1*packetLen);
        
        //ALTERNATIVE: requires stdlib - takes a bunch of space
        /*//create new buffer and read everything into it
        uint8_t * tmpBuf = (uint8_t *)malloc(packetLen);
        recvfrom(_sock,tmpBuf,packetLen,ip,port);
        if(!tmpBuf) return 0; //couldn't allocate
        // copy first bufLen bytes
        for(unsigned int i=0; i<bufLen; i++) {
            buf[i]=tmpBuf[i];
        }
        //free temp buffer
        free(tmpBuf);
        */
        
        
    } 
    return recvfrom(_sock,buf,bufLen,ip,port);
}
 
/* Read a received packet, throw away peer's ip and port.  See note above. */
int UdpRawClass::readPacket(uint8_t * buf, uint16_t len) {
    uint8_t ip[4];
    uint16_t port[1];
    return recvfrom(_sock,buf,len,ip,port);
}
 
 
 
 
/* Create one global object */
UdpRawClass UdpRaw;

これでイーサネットを使うライブラリのかなりものもがAruduino IDE Ver.0021でコンパイルが通るようになるはずです。
需要があれば修正ライブラリという形で、ダウンロードできるようにします。

それにしても、Aruduinoは便利ですが、IDEのバージョンアップに伴って依存しているライブラリによってコンパイルができなかったりするという現象は、かつてのWindows環境でのDLL地獄を連想させます。このあたりがもう少し洗練されるといいんですが・・・。

ArduinoUnoでRealTimeClockをNTPと同期させる Step.2 RTC8564用ライブラリの制作

2010/12/02 赤口 投稿時の月齢:26.3  月名:二十七日月  潮汐:中潮 Moon:26.3 - 12:30 pm by chameleon

ArduinoUnoでRealTimeClockをNTPと同期させる Step.1で制御系のだいたいの構想は立ちました。

なぜ、RealTimeClockが必要なのかは突っ込みどころ満載ですが、単に使ってみたかったからに他なりません。実際には、Timeライブラリを使えばArduinoの内部クロックで計時できます。
が、リアルタイムクロックのタイマー機能などを使えば、定期的に温度計測するタイミングなどを、単純なコードで記述できますし、arduinoのCPUの負荷も若干軽減できるはずです。

使ったリアルタイムクロックは秋月電子のものです。エプソントヨコムのRTC8564というチップをのせています。データシートも付属していましたが、エプソントヨコムのWEBサイトから詳細なマニュアルが入手できました。

このリアルタイムクロック用のライブラリを作成してみます。まあ、作らなくてもいいんですが・・・。一応、時計あわせやタイマー、アラームを設定できるようにしたりという機能を実装してみます。制作時間30分くらいなので、あまり突っ込んだ内容になっていないのは笑いですませます。

extern "C" {
    #include <stdlib.h>
    #include <string.h>
    #include <inttypes.h>
}
 
/************************************************/
/* Real Time Clock Module                       */
/* RTC-8564JE/NB                                */
/*                                              */
/* 1pin CLKOE  - open                           */
/* 2pin CLKOUT - Arduino D7                     */
/* 3pin INT    - open                           */
/* 4pin Vss    - Arduino GND                    */
/* 5pin SDA    - Arduino A4                     */
/* 6pin SCL    - Arduino A5                     */
/* 7pin NC     - open                           */
/* 8pin Vdd    - Arduino 5V <<< (or 3V3)       */
/************************************************/
 
/************************************************/
/* includes                                     */
/************************************************/
#include    <WConstants.h>
#include    <Wire.h>
#include    "RTC8564.h"
 
/************************************************/
/* defines                                      */
/************************************************/
//Register address
#define    RTC8564_SLAVE_ADRS    (0xA2 >> 1)    //0x51
#define    RTC8564_CTRL1        0x00
#define    RTC8564_CTRL2        0x01
#define    RTC8564_SEC            0x02
#define    RTC8564_MIN            0x03
#define    RTC8564_HOUR        0x04
#define    RTC8564_DAY            0x05
#define    RTC8564_WEEK        0x06
#define    RTC8564_MONTH        0x07
#define    RTC8564_YEAR        0x08
#define    RTC8564_MIN_ALM        0x09
#define    RTC8564_HOUR_ALM    0x0A
#define    RTC8564_DAY_ALM        0x0B
#define    RTC8564_WEEK_ALM    0x0C
#define    RTC8564_CLK_FREQ    0x0D
#define    RTC8564_TIM_CTRL    0x0E
#define    RTC8564_TIMER        0x0F
#define    BCD2Decimal(x)        (((x>>4)*10)+(x&0xf))
//For mask
#define CLOCK_STOP            0x20    //RTC停止
#define CLOCK_START            0x00    //RTC始動
////For Alarm
#define ALARM_CLEAR            0x07    //AFのみ0クリア
#define ALARM_INT_DIS        0x05    //AFを0クリアし、/INTを禁止
#define ALARM_INT_ENA        0x02    ///INTを許可*/
////For Timer
#define TIMER_INT_DIS        0x0A    //TFを0クリアし、/INTを禁止
#define TIMER_INT_ENA        0x01    ///INTを許可
#define TIMER_CLEAR            0x0B    //TFのみ0クリア
////For bit operation
#define AND                    0
#define OR                    1
 
/************************************************/
/* constructors                                 */
/************************************************/
RTC8564::RTC8564()
    : _seconds(0),
     _minutes(0),
     _hours(0),
     _days(0),
     _weekdays(0),
     _months(0),
     _years(0),
     _century(0)
{
}
 
//Public Methods//////////////////////////////////
/************************************************/
/* Initialization of RTC                        */
/************************************************/
void RTC8564::begin(void){
    Wire.begin();
    if(isvalid() == false){
        init();
    }
}
 
/************************************************/
/* The same period of time                      */
/************************************************/
void RTC8564::sync(uint8_t date_time[],uint8_t size){
    controlClock(CLOCK_STOP);
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_SEC);    //Set of time data
    Wire.send(date_time, size);
    Wire.endTransmission();    
    controlClock(CLOCK_START);
}
 
/*******************************************************************/
/* Settings of alarm                                               */
/* >>>The alarm value is set with BCD.                             */
/*                                                                 */
/* 0 clearing of AF. And /INT output is prohibited.<<<ALARM_CLEAR  */
/* 0 clearing of TF. And /INT output is prohibited.<<<TIMER_CLEAR  */
/* Other values are not changed.                                   */
/* flag='AND' -> c2reg & val                                      */
/* flag='OR'  ->  c2reg | val                                      */
/*******************************************************************/
uint8_t set_c2reg(int val,int flag){
    uint8_t buff;
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_CTRL2);
    Wire.requestFrom(RTC8564_SLAVE_ADRS, 1);
    if(flag==0){
        buff = Wire.receive() & val;//val=0x05 AF>>0 AIE>>0 /INTの出力禁止
    }else{
        buff = Wire.receive() | val;
    }
    Wire.endTransmission();
    
    //return buff;
    
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_CTRL2);
    Wire.send(buff);
    Wire.endTransmission();
}
 
/************************************************/
/* Set at alarm time                         */
/************************************************/
void RTC8564::alarm_set(int aweek,int aday,int ahour,int amin){
    set_c2reg(ALARM_INT_DIS,AND);    //アラーム機能停止        
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_MIN_ALM);      //アラーム分のアドレス
    Wire.send(amin);                  //アラーム分の値 0-59 
    Wire.send(ahour);                 //アラーム時の値 0-23
    Wire.send(aday);                  //アラーム日の値 1-31
    Wire.send(aweek);                 //アラーム曜の値 日月火水木金土 0123456 
    Wire.endTransmission(); //上位5bitは Don't Care
    set_c2reg(ALARM_INT_ENA,OR);    //アラーム機能開始
}
 
/************************************************/
/* Reset alarm flag(only AF flag)              */
/************************************************/
void RTC8564::alarm_reset(void){
    set_c2reg(ALARM_CLEAR,AND);        //AFのみ0クリアする 0x07
}
 
/************************************************/
/* Set Timer                                   */
/************************************************/
void RTC8564::timer_set(int timer){
    set_c2reg(TIMER_INT_DIS,AND);    //TFを0クリアする TIEに0を書き込み /INTの出力禁止
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_TIM_CTRL);
    Wire.send(0x02);                //TE=0 TD1=1 TD0=0(1Hz 1秒桁更新にセット)
    Wire.send(timer);                //タイマー間隔(秒指定)
    Wire.endTransmission();
    set_c2reg(TIMER_INT_ENA,OR);    //TIEに1を書き込み /INTの出力許可
}
 
/************************************************/
/* Repetition processing of the timer         */
/************************************************/
void RTC8564::timer_reload(bool repeat){
    uint8_t buff;
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_CTRL2);
    Wire.requestFrom(RTC8564_SLAVE_ADRS, 1);
    if(repeat == false){
        buff = Wire.receive() & 0x0f;//TI/TPを0にする(繰り返しなし)
    }
    else{
        buff = Wire.receive() | 0x10;//TI/TPを1にする(繰り返しあり)
    }
    Wire.endTransmission();
    
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_CTRL2);
    Wire.send(buff);
    Wire.endTransmission();    
}
 
/******************************************************/
/* Set clockout                          */
/* tfreq: 32768Hz=0x80,1024Hz=0x81,32Hz=0x82,1Hz=0x83 */
/******************************************************/
void RTC8564::timer_clockout(int tfreq){
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_CLK_FREQ);
    Wire.send(tfreq);
    Wire.endTransmission();
}
 
/************************************************/
/* Timer beginning                            */
/* 4096Hz:0x81,64Hz:0x81,1sec:0x82,1min:0x83    */
/* After setting the interval time,             */
/*                         you begin the timer. */
/* 4096Hz:0x81,64Hz:0x81,1sec:0x82,1min:0x83    */
/************************************************/
void RTC8564::timer_start(int tc){
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_TIM_CTRL);
    Wire.send(tc);                //timer値 (0x82)>>>TE=1 TD1=1 TD0=0 1Hz 1秒桁更新
    Wire.endTransmission();    
}
 
/************************************************/
/* Reset timer flag(only TF flag)              */
/************************************************/
void RTC8564::timer_reset(void){
    set_c2reg(TIMER_CLEAR,AND);    //0x0B TFのみを0クリアする
}
/************************************************/
/* The value of the C2 register is obtained.    */
/************************************************/
int RTC8564::get_c2reg(void){
    uint8_t buff;
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_CTRL2);
    Wire.endTransmission();
    Wire.requestFrom(RTC8564_SLAVE_ADRS, 1);
    buff = Wire.receive() & 0x0C;//AF,TF以外をマスク
    Wire.endTransmission();    
    return buff;                //0x08>>>AF=1 0x04>>>TF=1 0x0C>>>AF=TF=1 0x00 AF=TF=0
}
 
/************************************************/
/* Whether RTC can use it is examined.          */
/************************************************/
bool RTC8564::available(void){
    uint8_t buff[7];
    
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_SEC);            // write reg addr 02
    Wire.endTransmission();    
    Wire.requestFrom(RTC8564_SLAVE_ADRS, 7);
    
    for(int i=0; i<7; i++){
        if(Wire.available()){
            buff[i] = Wire.receive();
        }
    }
    
    _seconds  = buff[0] & 0x7f;
    _minutes  = buff[1] & 0x7f;
    _hours      = buff[2] & 0x3f;
    _days      = buff[3] & 0x3f;
    _weekdays = buff[4] & 0x07;
    _months      = buff[5] & 0x1f;
    _years      = buff[6];
    _century  = (buff[5] & 0x80) ? 1 : 0;
    return (buff[0] & 0x80 ? false : true);
}
 
/************************************************/
/* The flag of VL is examined.                  */
/************************************************/
bool RTC8564::isvalid(void){
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_SEC);
    Wire.endTransmission();
    Wire.requestFrom(RTC8564_SLAVE_ADRS, 1);
    if(Wire.available()){
        uint8_t buff = Wire.receive();
        return (buff & 0x80 ? false : true);    //VLをチェックする。
    }
    return false;
}
 
/************************************************/
/* The flag of AF is examined.                  */
/************************************************/
bool RTC8564::alarm_check(void){
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_CTRL2);
    Wire.endTransmission();
    Wire.requestFrom(RTC8564_SLAVE_ADRS,1);
    if(Wire.available())
    {
      return ((Wire.receive() & 0x08) != 0x08 ? false : true);
    }
    return false;
}
 
/************************************************/
/* The flag of TF is examined.                  */
/************************************************/
bool RTC8564::timer_check(void){ 
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);
    Wire.send(RTC8564_CTRL2);
    Wire.endTransmission();
    Wire.requestFrom(RTC8564_SLAVE_ADRS, 1);
    if(Wire.available())    
    {
      return ((Wire.receive() & 0x04) != 0x04 ? false : true);
    }
    return false;
}
 
//Private Methods/////////////////////////////////
/************************************************/
/* Initialization                               */
/************************************************/
void RTC8564::init(void)
{
    delay(3000);                //tSTA >> Ta=+25C Vdd=1V8 Max->3.0s 
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);    //0x51
    Wire.send(RTC8564_CTRL1);    //The following values are written from the register address 0x00. 
    Wire.send(0x20);            //00 Control 1 >> STOP=1
    Wire.send(0x00);            //01 Control 2 >> FLAG CLEAR
    Wire.send(0x00);            //02 Seconds
    Wire.send(0x00);            //03 Minutes
    Wire.send(0x09);            //04 Hours
    Wire.send(0x01);            //05 Days
    Wire.send(0x01);            //06 Weekdays
    Wire.send(0x01);            //07 Months
    Wire.send(0x01);            //08 Years
    Wire.send(0x00);            //09 Minutes Alarm
    Wire.send(0x00);            //0A Hours Alarm
    Wire.send(0x00);            //0B Days Alarm
    Wire.send(0x00);            //0C Weekdays Alarm
    Wire.send(0x00);            //0D CLKOUT
    Wire.send(0x00);            //0E Timer control
    Wire.send(0x00);            //0F Timer
    Wire.send(0x00);            //00 Control 1, STOP=0
    Wire.endTransmission();
}
 
/************************************************/
/* STOP flag control function                   */
/* 0x20 STOP=1(Clock stop)                      */
/* 0x00 STOP=0(Clock start)                     */
/************************************************/
void RTC8564::controlClock(int flag){
    Wire.beginTransmission(RTC8564_SLAVE_ADRS);    //0x51
    Wire.send(RTC8564_CTRL1);                    //0x00
    Wire.send(flag);                            //STOP
    Wire.endTransmission();
}
 
 
 
 
uint8_t RTC8564::seconds(uint8_t format) const {
    if(format == Decimal) return BCD2Decimal(_seconds);
    return _seconds;
}
 
uint8_t RTC8564::minutes(uint8_t format) const {
    if(format == Decimal) return BCD2Decimal(_minutes);
    return _minutes;
}
 
uint8_t RTC8564::hours(uint8_t format) const {
    if(format == Decimal) return BCD2Decimal(_hours);
    return _hours;
}
 
uint8_t RTC8564::days(uint8_t format) const {
    if(format == Decimal) return BCD2Decimal(_days);
    return _days;
}
 
uint8_t RTC8564::weekdays() const {
    return _weekdays;
}
 
uint8_t RTC8564::months(uint8_t format) const {
    if(format == Decimal) return BCD2Decimal(_months);
    return _months;
}
 
uint8_t RTC8564::years(uint8_t format) const {
    if(format == Decimal) return BCD2Decimal(_years);
    return _years;
}
 
bool RTC8564::century() const {
    return _century;
}
 
/************************************************/
/* Preinstantiate Objects                       */
/************************************************/
RTC8564 RTC = RTC8564();

ヘッダファイルが

#ifndef RTC8564_h
#define RTC8564_h
 
#include <inttypes.h>
 
class RTC8564
{
private:
    void init(void);
    void controlClock(int flag);
    uint8_t _seconds;
    uint8_t _minutes;
    uint8_t _hours;
    uint8_t _days;
    uint8_t _weekdays;
    uint8_t _months;
    uint8_t _years;
    bool    _century;
    
public:
    enum {
        BCD = 0,
        Decimal = 1,
    };
    RTC8564();
    void begin(void);
    void sync(uint8_t date_time[],uint8_t size = 7);
    bool available(void);
    bool isvalid(void);    
    void alarm_set(int aweek,int aday,int ahour,int amin);
    void alarm_reset(void);
    bool alarm_check(void);
    bool timer_check(void);
    void timer_set(int timer);
    void timer_start(int tc);
    void timer_reload(bool repeat);
    void timer_clockout(int tfreq);
    void timer_reset(void);
    int  get_c2reg(void);    
    uint8_t seconds(uint8_t format = RTC8564::BCD) const;
    uint8_t minutes(uint8_t format = RTC8564::BCD) const;
    uint8_t hours(uint8_t format = RTC8564::BCD) const;
    uint8_t days(uint8_t format = RTC8564::BCD) const;
    uint8_t weekdays() const;
    uint8_t months(uint8_t format = RTC8564::BCD) const;
    uint8_t years(uint8_t format = RTC8564::BCD) const;
    bool century() const;
};
 
extern RTC8564 RTC;
 
#endif

使い方は
RTC.sync(0×01,0×02,0×03,0×04,05,0×06,0×10);
でリアルタイムクロックに時刻をセットしたりできます。
ちなみに10年6月4日金曜日3時2分1秒をセットしています。具体的なスケッチは次のエントリーで。

Download