test
2011/08/02 先負
Moon:2.2 - 12:13 am by chameleon
やけに揺れた気がするけど、自分の地方で震度3らしい。
駿河湾が震源らしいので、地震がだんだん近づいてきている気がするのは気のせいか・・・。
Moon:20.6 - 11:10 pm by chameleon
世間では夏休みが始まっているという今日、ようやく出張から解放されました。一週間以上の激戦でした・・・。
日本じゃ台風が来ていたらしいですが、外に出したままのものも、そのまま同じ場所にありましたから風はたいしたことなかったのでしょうか・・・。
デジタル台風とかで移動軌跡をみると、かなり変なふうに動いたようです。
もっとも自分の移動ルートはこの台風の比ではありませんが・・・。
Moon:13.6 - 10:06 pm by chameleon
今日も関連企業の皆様と飲み会でした・・・。まったく、転職後は、このような会は数知れず・・・。
飲み会に行くのに休暇を取っていかなければならないのも何とも・・・。
Moon:12.5 - 8:17 pm by chameleon
Moon:11.5 - 8:51 pm by chameleon
利用しているサーバーで昨日から障害が発生していました。昨日中には障害は解決されたようですが、自分のアカウントではMySQLサーバーへの接続が確立できませんでした。
初めて、レンタルサーバーのサポート使いました。500円払うと優先サポート権が得られるらしいので、それで対応を依頼しました。きわめて迅速に対応していただけました。データベースのバックアップもとれない状況だったので、だめならいい潮時とサイトを閉じる気持ちも若干ありました。
障害が出る前から、サイトにアクセスするとページが開かなかったりやたらと重かったりして、リロードしたりしてしのいでいたんですが、今回の障害の対応後は今のところ順調な感じです。正直サーバーが逼迫しているのかぁ、空いている所へ引っ越そうかと、別のレンタルサーバーを調べたりもしていたのですが、結果的に十分満足な状況になりました。まだ、しばらくはサイトも続けられそうです。
とはいえ、ずっとこのブログも更新していませんでした。
いや、転職後ほんとに仕事が忙しかったんです。で、今は気象観測の研究中です。
次の更新はいつになるのか・・・。
Moon:27.0 - 9:07 pm by chameleon
長らくつとめていた職種を離れ、本日異動しました。
明日から、全く新しい職場にてお仕事です。環境も激変、仕事内容も激変です。
とりあえず今日は新しい職場の駐車場を確認してきました・・・。
と、久しぶりのブログの更新・・・。引き継ぎを含めてほんとに忙しかったです。明日からはさらに・・・。
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地獄を連想させます。このあたりがもう少し洗練されるといいんですが・・・。
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秒をセットしています。具体的なスケッチは次のエントリーで。