SSブログ

MaruduinoでXBeeを使ってみる。主に送信。 [アプリケーション]

※スケッチを書き込む時はXBeeを外すか、接続を全て外してから行ってください。
※2個のXBeeが必要です。また、Maruduinoと対向する側はPCに接続し、X-CTUでモニターします。
Img_2364.jpg
XBeeの使用例です。
これはLiquidCrystalライブラリとxbee-arduinoライブラリを使用しています。
http://code.google.com/p/xbee-arduino/
xbee-arduinoライブラリのインストールは適宜サイトを読んで行って下さい。

Xbeeはシリーズ1を使っています。上記ライブラリを使用するためにはX-CTUでMaruduinoに搭載する側のXBeeにAPI2モードを設定しておきます。端末通信速度はデフォルトの9600bpsに設定しています。使用チャンネルやPAN ID、16bitアドレスなどは適宜設定してください。

相手側はAPIモードでも良いのですが、今回はATモードにしてあります。ターミナル画面でSHOW HEXを設定しておくと、数字がインクリメントされるデータが送られてくるのが判ります。
/*
  LiquidCrystal Library - Hello World
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
  The circuit:
 * LCD RS pin to digital DI2
 * LCD Enable pin to digital Di3
 * LCD D4 pin to digital DI4
 * LCD D5 pin to digital DI5
 * LCD D6 pin to digital DI6
 * LCD D7 pin to digital DI7
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 
 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe
 modified 22 Nov 2010
 by Tom Igoe
 
 This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 */

/**
 * Copyright (c) 2009 Andrew Rapp. All rights reserved.
 *
 * This file is part of XBee-Arduino.
 *
 * XBee-Arduino is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * XBee-Arduino is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with XBee-Arduino.  If not, see <http://www.gnu.org/licenses/>.
 */


// include the library code:
#include <LiquidCrystal.h>
#include <XBee.h>
/*************************************************************************/
/* defines                                                               */
/*************************************************************************/
#if 0
#define  DI13     2
#define  DI12     3
#define  DI11     4
#define  DI10     5
#define  DI9      6
#define  DI8      7
#define  DI7      8
#define  DI6      9
#define  DI5      10
#define  DI4      11
#define  DI3      12
#define  DI2      13
#define  DI1      
#define  DI0      
#else
#define  DI13     13
#define  DI12     12
#define  DI11     11
#define  DI10     10
#define  DI9      9
#define  DI8      8
#define  DI7      7
#define  DI6      6
#define  DI5      5
#define  DI4      4
#define  DI3      3
#define  DI2      2
#define  DI1      1
#define  DI0      0
#endif

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(DI2, DI3, DI4, DI5, DI6, DI7);
XBee xbee = XBee();
unsigned long start = millis();
uint8_t payload[] = { 0, 0 };
Tx16Request tx = Tx16Request(0, payload, sizeof(payload));
TxStatusResponse txStatus = TxStatusResponse();
int suc_cnt,flt_cnt,loop_cnt;

void setup()
{
  lcd.begin(16, 2);
  lcd.print("Xbee Test!");
  xbee.begin(9600);
}

void loop()
{
  // start transmitting after a startup delay.  Note: this will rollover to 0 eventually so not best way to handle
  if (millis() - start > 15000)
  {
    payload[0] = loop_cnt >> 8 & 0xff;
    payload[1] = loop_cnt++ & 0xff;
    xbee.send(tx);
  }

  // after sending a tx request, we expect a status response
  // wait up to 5 seconds for the status response
  if (xbee.readPacket(5000))
  {
    lcd.setCursor(0, 1);
             //0123456789012345
    lcd.print("                ");
    // got a response!
    // should be a znet tx status            	
    if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE)
    {
      xbee.getResponse().getZBTxStatusResponse(txStatus);
      // get the delivery status, the fifth byte
      if (txStatus.getStatus() == SUCCESS)
      {
        // success.  time to celebrate
        lcd.setCursor(0, 1);
        lcd.print("OK:");
        lcd.print(++suc_cnt);lcd.print(":");lcd.print(flt_cnt);
      }
      else
      {
        // the remote XBee did not receive our packet. is it powered on?
        lcd.setCursor(0, 1);
        lcd.print("NG:");
        lcd.print(suc_cnt);lcd.print(":");lcd.print(++flt_cnt);
      }
    }
  }
  else
  {
    // local XBee did not provide a timely TX Status Response -- should not happen
    lcd.setCursor(0, 1);
    lcd.print("TRANSMIT ERR");
  }
  delay(200);
}


Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ (Make:PROJECTS)

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ (Make:PROJECTS)

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



フリスクサイズ XBeeインタフェースボードの製作、配付 MTM06にて [アプリケーション]

Img_2228.jpg作りました。
通常は下の写真の様な純正のUSBインタフェース基板を使うのですが、まあちょっとでかいですし、ハンドリングも悪いのでフリスクサイズの基板を作成しました。
ただし元々純正基板にあった機能をこのサイズに突っ込むのは難しいので、幾つかの機能は削除しています。ですが、実用上は問題無いでしょう。


Img_2231.jpg削ってしまった機能は、まずRSSI表示がありません。これにあと3個もLEDを追加しても見るかどうか、、、。

DIN、DOUTのモニターLEDは有りますが、点灯時間を延長する回路は搭載していません。

本来USBの電源利用は、PC側から大きな電流使って良いよ!と許可が出るまでスタンバイに入っているのですが、まあ回路を載せられない事も無いのですが、部品増えますし、面倒なのでUSBに接続したらいきなりフルパワーになっています。


Img_2229.jpgここだけは削れなかった機能としてはDTR、RTS、CTSのサポートとリセットスイッチとBDMコネクターです。

DTRはUSBインタフェースボード上でXBeeをスリープモードにした場合、SLEEP_RQの制御に使いますし、RTS、CTSはファームの更新時には大量の更新データを通信でやり取りしますので、その際に必要です。


x_ctu_zb_end_device_api_01.pngリセットスイッチはXBeeのモデムタイプを変更したりファームを更新する際には必ず必要です。それ以外にもCYCLIC SLEEPに設定した場合、コンフィギュレーションを変更しようにもXBeeがSLEEPに入っている場合はREADやWRITEが上手く行かない時が有ります。そんな時はREADやWRITEボタンを押した直後にこのリセットスイッチを押せば当然XBeeは起動からスタートしますので、すんなり通ります。

BDMコネクターはProgrammable XBeeのファームウエアをいじったり、その上で動作するアプリケーションのデバックには必須です。


このUSBインタフェースボードはMTM06にて実費(250円)で配付いたします。MTM06で配付するのは基板とドキュメントのみですが、事前に部品セット込みで予約いただければ、当日部品セットも用意いたしたいと思います。半田ごて等の工具も用意しておきますので、その場で組み立てOKです(笑)。


ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

  • 作者: 濱原 和明
  • 出版社/メーカー: オーム社
  • 発売日: 2005/04/25
  • メディア: 単行本



Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



超音波距離計測モジュール Ultrasonic Distanceの配付をMTM06辺りで行います。 #mtm06 [アプリケーション]

※欲しい方は事前に連絡ください。量産と言っても数に限りがあります。売り切れごめん(笑)です。

※秋月でニセラのT4016A1、R4016A1の扱いが無くなったと思いきや、今度は台湾メーカーでそっくりの品の扱いが始まったようです。
http://akizukidenshi.com/catalog/g/gI-00120/
購入して同様に使えるのか試してみます。
Img_2220.jpgMTM05の時にブレッドボードで組んでArduinoで動かして、それをPrototyping Labのトークセッションにて小林さんに紹介してもらった超音波距離計のモジュール基板です。

バンドパスフィルターの定数を決めるのに随分時間が掛かってしまった気もするけれど、わりと安定して動くようになりましたので、基板も量産してMTM06に持ち込む予定です。

基本的に基板のみの配付を予定しています。価格は実費のみの250円を予定しています。ただ部品セットの要望が大きければ検討いたします。
と言いますか、MTM06の会場で工具を用意しておきますので、その場で作ってみるみたいな事をしたいと思っています。

計測距離は8cm位から3m強測れます。
左右、上下の広がりですが、結構広い範囲を拾ってしまいますねこのセンサーは。なのでスポットで計測したい場合はホーンを付けた方が良さそうです。
データシートは以下のアドレスのT4016A1とR4016A1をご覧ください。
http://www.nicera.co.jp/pro/ut/ut-02.html

動かすマイコンはArduinoに限らずなんでも良いです。但し40KHz位の信号を出せる必要があります。


ultra_sonic_distance_03_01.png



Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



Mad Science ―炎と煙と轟音の科学実験54

Mad Science ―炎と煙と轟音の科学実験54

  • 作者: Theodore Gray
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/24
  • メディア: 大型本



Maruduinoで時計を作る。Wireライブラリ対応版 [アプリケーション]

このボードはハムフェア(http://bit.ly/14qQxv)のマルツさんのブースで展示予定です。触ってネー。

Img_2082.jpgもっとも自分でなんとかした訳ではなく、某所から、ロジアナまで持ち出しての動作解析をしてもらった結果です。
ある意味Wireライブラリの使い方の見本としてもどうぞ。
※Wireライブラリの中で割込みを使っている関係上、別の割り込みハンドラの中から呼んだり、割り込み禁止にしている状態では、Wireライブラリを使う事ができない様です。お気を付け。


/***********************************************************************/
/* LCD clock                                                           */
/* I2C bus control RTC()RTC8564 use                                    */
/*                                               designed by hamayan   */
/*                                               Copyright(C) hamayan  */
/***********************************************************************/
#include <string.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include <avr/io.h>

/*************************************************************************/
/* defines                                                               */
/*************************************************************************/
#define  DI13     13
#define  DI12     12
#define  DI11     11
#define  DI10     10
#define  DI9      9
#define  DI8      8
#define  DI7      7
#define  DI6      6
#define  DI5      5
#define  DI4      4
#define  DI3      3
#define  DI2      2
#define  DI1      1
#define  DI0      0
#define  AN0      14
#define  AN1      15
#define  AN2      16
#define  AN3      17
#define  AN4      18
#define  AN5      19

#define  SW1      AN3
#define  SW2      AN2
#define  SW3      AN1
#define  SW4      AN0

#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  RTC_BASE_ADDR      (0xa2 >> 1)

/*************************************************************************/
/*  global parameter                                                     */
/*************************************************************************/
enum RTC8564Str {SECONDS,MINUTES,HOURS,DAYS,WEEKDAYS,MONTHS,YEARS};

/* 0123456789012345678 */
/* 2007/11/21 15:12:00 */
char date[ 20 ];  /**/
char alarm_set_time[] = "00:00";

unsigned long sectim;
unsigned long lasttim;
unsigned char switches[3];
boolean  clock_disp = false;

const char date_limit[][2] = /*offset = 2*/
{
  {'0','9'},  /*year 10*/
  {'0','9'},  /*year 1*/
  {'/','/'},  /**/
  {'0','1'},  /*month 10*/
  {'0','9'},  /*month 1*/
  {'/','/'},  /**/
  {'0','3'},  /*day 10*/
  {'0','9'},  /*day 1*/
};
const char time_limit[][2] = /*offset = 0*/
{
  {'0','2'},  /*hour 10*/
  {'0','9'},  /*hour 1*/
  {':',':'},  /**/
  {'0','5'},  /*monite 10*/
  {'0','9'},  /*monite 1*/
  {':',':'},  /**/
  {'0','5'},  /*second 10*/
  {'0','9'},  /*second 1*/
};

LiquidCrystal lcd(DI8, DI9, DI4, DI5, DI6, DI7);

/*************************************************************************/
/*  prototype                                                            */
/*************************************************************************/
static void date_print( const char *src, int x, int y );
static void time_print( const char *src, int x, int y );
static void ConvertFromRTC2DateTime( void );

int I2C_Write( int addr, unsigned char data );
int I2C_Read( int addr, unsigned char *data );

int InitRTC8564( int force );
unsigned char *DateStr2RTC8564Str( unsigned char *dest, const char *source );
char *RTC8564Str2DateStr( char *dest, const unsigned char source[] );
int I2CRTC8564_Write( unsigned char addr, char data );
int I2CRTC8564_Read( unsigned char addr, char *buff );
int I2CRTC8564_Blk_Read( unsigned char addr, char *buff, int size );
int RTC8564_CalenderSet( const char *date_time );

#define  CalenderRead(buf)  I2CRTC8564_Blk_Read(RTC8564_SEC, buf, 7)

/*************************************************************************/
/*  digital2 external int handler                                        */
/*************************************************************************/
static void di2_int_hdr( void )
{
  sectim++;
}

/*************************************************************************/
/*  time display update                                                  */
/*************************************************************************/
static void time_disp_update( void )
{
  ConvertFromRTC2DateTime();  /*update clock*/
  if( clock_disp == true )
  {
    date_print(date,0,0);
    time_print(date,2,1);
  }
}

/*************************************************************************/
/*  Switch down detection                                                */
/*************************************************************************/
static unsigned char detect_sw_down( unsigned char *sw )
{
  unsigned char temp = PINC & 0x0f;

  sw[0] = sw[1];
  sw[1] = sw[2];
  sw[2] = temp ^ 0x0f;

  return sw[0] & sw[1] & temp;
}

/*************************************************************************/
/*  RTC8564 data convert to date time strings.                           */
/*************************************************************************/
static void ConvertFromRTC2DateTime( void )
{
  char buf[10];

  CalenderRead( buf );
  RTC8564Str2DateStr( date, (const unsigned char *)buf );  /**/
}

/*************************************************************************/
/*  Date lcd print                                                       */
/*************************************************************************/
static void date_print( const char *src, int x, int y )
{
  char buf[16];

  memcpy( buf, src, 10 );
  buf[10] = '\0';
  lcd.setCursor(x,y);
  lcd.print( buf );
}

/*************************************************************************/
/*  Time lcd print                                                       */
/*************************************************************************/
static void time_print( const char *src, int x, int y )
{
  char buf[16];

  memcpy( buf, &src[11], 8 );
  buf[8] = '\0';
  lcd.setCursor(x,y);
  lcd.print( buf );
}

/*************************************************************************/
/*  Time adjust                                                          */
/*************************************************************************/
static void time_adjust_mode( void )
{
  int pos = 2;
  char copy_date[20];
  boolean loop = true;

  memcpy( copy_date, date, sizeof(copy_date) );
  lcd.clear();
  date_print(copy_date,0,0);
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 10 )
        {
          loop = false;
          break;
        }
        if( pos == 4 || pos == 7 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --copy_date[pos] < date_limit[pos - 2][0] ) copy_date[pos] = date_limit[pos - 2][1];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos] );
        break;
      case 0b00000100:  /*up number*/
        if( ++copy_date[pos] > date_limit[pos - 2][1] ) copy_date[pos] = date_limit[pos - 2][0];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  pos = 0;
  loop = true;
  lcd.clear();
  time_print(copy_date,0,0);
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 8 )
        {
          loop = false;
          break;
        }
        if( pos == 2 || pos == 5 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --copy_date[pos + 11] < time_limit[pos][0] ) copy_date[pos + 11] = time_limit[pos][1];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos + 11] );
        break;
      case 0b00000100:  /*up number*/
        if( ++copy_date[pos + 11] > time_limit[pos][1] ) copy_date[pos + 11] = time_limit[pos][0];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos + 11] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  memcpy( date, copy_date, sizeof(date) );
  RTC8564_CalenderSet( date );  /*update calender.*/
  EIMSK |= 0x01;   /*int0 interrupt enable*/
}

/*************************************************************************/
/*  Alarm set                                                            */
/*************************************************************************/
static void Alarm_set_mode( void )
{
  int pos = 0;
  unsigned char temp;
  boolean loop = true;

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print( alarm_set_time );
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 5 )
        {
          loop = false;
          break;
        }
        if( pos == 2 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --alarm_set_time[pos] < time_limit[pos][0] ) alarm_set_time[pos] = time_limit[pos][1];
        lcd.setCursor(pos,0);
        lcd.print( alarm_set_time[pos] );
        break;
      case 0b00000100:  /*up number*/
        if( ++alarm_set_time[pos] > time_limit[pos][1] ) alarm_set_time[pos] = time_limit[pos][0];
        lcd.setCursor(pos,0);
        lcd.print( alarm_set_time[pos] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  temp = ((alarm_set_time[3] & 0x0f) << 4) + (alarm_set_time[4] & 0x0f);
  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  I2CRTC8564_Write( RTC8564_MIN_ALM, temp );
  EIMSK |= 0x01;   /*int0 interrupt enable*/

  temp = ((alarm_set_time[0] & 0x0f) << 4) + (alarm_set_time[1] & 0x0f);
  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  I2CRTC8564_Write( RTC8564_HOUR_ALM, temp );
  EIMSK |= 0x01;   /*int0 interrupt enable*/
}

/*************************************************************************/
/*  setup                                                                */
/*************************************************************************/
void setup()
{
  char buf[16];
  unsigned char temp;
//  static const char date_time[] = "2010/08/07 02:04:00";

  lcd.begin(16, 2);
  lcd.clear();
  lcd.println( "designed by hamayan." );

  Wire.begin();  /*set i2c master device*/
  TWSR &= 0xfc;  /*baud rate control. prescaler=x1*/
  TWBR = 72;     /*baud rate control. 100khz*/

  delay( 1000 );
  if( InitRTC8564( 0 ) < 0 )
  {
    lcd.clear();
    lcd.println( "rtc init error." );
    while(1) ;
  }

  I2CRTC8564_Read( RTC8564_MIN_ALM, (char *)&temp );
  if( !(temp & 0x80) )
  {
    alarm_set_time[3] = ((temp >> 4) & 0x07) + '0';
    alarm_set_time[4] = (temp & 0x0f) + '0';
    I2CRTC8564_Read( RTC8564_HOUR_ALM, (char *)&temp );
    alarm_set_time[0] = ((temp >> 4) & 0x03) + '0';
    alarm_set_time[1] = (temp & 0x0f) + '0';
  }

//  RTC8564_CalenderSet( date_time );  /*force setting calender.*/

  pinMode( SW1, INPUT );  /*set port at input mode*/
  pinMode( SW2, INPUT );  /*set port at input mode*/
  pinMode( SW3, INPUT );  /*set port at input mode*/
  pinMode( SW4, INPUT );  /*set port at input mode*/

  /*enable edge trigger interrupt*/
  attachInterrupt(0, di2_int_hdr, FALLING);
  DDRD &= ~0b00000100;  /*direction input*/
  PORTD |= 0b00000100;  /*enable pullup*/

  /*display alarm set time*/
  lcd.clear();
  lcd.setCursor(11,1);
  lcd.print( alarm_set_time );
  clock_disp = true;
  lasttim = millis() + 100;
}

/*************************************************************************/
/*  main loop                                                            */
/*************************************************************************/
void loop()
{
#define  ALARM_PERIOD  (60 * 5)
  unsigned char temp;
  static unsigned long oldsec;
  static int alarm_time;

  if( millis() > lasttim )
  {
    lasttim = millis() + 100;  /*next sample time update.*/
    switch ( detect_sw_down( switches ) )
    {
      case 0b00001010 :  /*time adjust mode*/
        clock_disp = false;
        time_adjust_mode();
        lcd.clear();
        lcd.setCursor(11,1);
        lcd.print( alarm_set_time );
        clock_disp = true;
        break;
      case 0b00001100 :  /*alarm set mode*/
        clock_disp = false;
        Alarm_set_mode();
        lcd.clear();
        lcd.setCursor(11,1);
        lcd.print( alarm_set_time );
        clock_disp = true;
        break;
      case 0b00001000 :  /*stop alarm*/
        alarm_time = 0;
        break;
      default :
        break;
    }
  }

  if( oldsec != sectim )
  {
    oldsec = sectim;
    time_disp_update();  /*clock display update*/

    if( date[18] == '0' &&
        date[17] == '0' &&
        alarm_set_time[4] == date[15] &&
        alarm_set_time[3] == date[14] &&
        alarm_set_time[1] == date[12] &&
        alarm_set_time[0] == date[11] )
      alarm_time = ALARM_PERIOD;  /*? minutes*/

    if( --alarm_time > 0 )
    {
      if( alarm_time % 3 ) tone( DI13, 1000, 800 );
    }
    else alarm_time = 0;
  }
}

/*************************************************************************/
/*  I2C Write function                                                   */
/*************************************************************************/
int I2C_Write( int addr, unsigned char data )
{
  Wire.beginTransmission( addr );
  Wire.send( data );
  return Wire.endTransmission();
}

/*************************************************************************/
/*  I2C Read function                                                    */
/*************************************************************************/
int I2C_Read( int addr, unsigned char *data )
{
  Wire.requestFrom( addr, 1 );
  while( Wire.available() == 0 ) ;
  *data = Wire.receive();
  return 0;
}

/*************************************************************************/
/* I2CRTC8564_Write                                                      */
/*************************************************************************/
int I2CRTC8564_Write( unsigned char addr, char data )
{
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );
  Wire.send( data );
  return Wire.endTransmission();
}

/*************************************************************************/
/* I2CRTC8564_Read                                                       */
/*************************************************************************/
int I2CRTC8564_Read( unsigned char addr, char *buff )
{
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );
  Wire.endTransmission();

  Wire.requestFrom( RTC_BASE_ADDR, 1 );
  while( Wire.available() == 0 ) ;
  *buff = Wire.receive();
  return 0;
}

/*************************************************************************/
/* I2CRTC8564_Blk_Read                                                   */
/*************************************************************************/
int I2CRTC8564_Blk_Read( unsigned char addr, char *buff, int size )
{
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );
  Wire.endTransmission();

  Wire.requestFrom( RTC_BASE_ADDR, size );
  while( Wire.available() < size ) ;
  for( ; size > 0; size-- )
  {
    *buff++ = Wire.receive();
  }
  return 0;
}

/*************************************************************************/
/* RTC-8564 initialize                                                   */
/*************************************************************************/
int InitRTC8564( int force )
{
  int i,ret;
  char temp,date_time[ 7 ],work[ 8 ];
  unsigned char rtc_adr;
  static const unsigned char RTC8564_Init_Code[] =
    {0x20, 0x11, 0x00,0x10,0x18,0x07,0x04,0x05, 0x10,0x80, 0x80,  0x80, 0x80,  0x00,0x81,63  };
   /*ctrl1,ctrl2,sec, min, hour,day, week,month,year,min_a,hour_a,day_a,week_a,freq,cont,timer*/

  /*RTC8564 confirmed VLbit*/
  if( I2CRTC8564_Read( RTC8564_SEC, &date_time[ SECONDS ] ) != 0 ) return (-1);

  if( date_time[ SECONDS ] & 0x80 || force )  /*VLbit was 1 then detected low voltage*/
  {
    for( rtc_adr = 0; rtc_adr < sizeof( RTC8564_Init_Code ); rtc_adr++ )
    {
      if( I2CRTC8564_Write( rtc_adr, RTC8564_Init_Code[ rtc_adr ] ) != 0 ) return (-1);
    }
    if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);  /*timer start*/

    for( i = 0; i < 100; i++ )
    {
      if( I2CRTC8564_Read( RTC8564_YEAR, &date_time[ YEARS ] ) != 0 ) return (-1);  /*RTC is not there.*/

      if( date_time[ YEARS ] == RTC8564_Init_Code[ RTC8564_YEAR ] )  /**/
      {
        break;
      }
      else
      {
        for( rtc_adr = 0; rtc_adr <= sizeof( RTC8564_Init_Code ); rtc_adr++ )
        {
          if( I2CRTC8564_Write( rtc_adr, RTC8564_Init_Code[ rtc_adr ] ) != 0 ) return (-1);
        }
        if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);
      }
    }
    if( i != 100 ) ret = 1;  /**/
    else ret = (-2);  /*initialize error*/
  }
  else ret = 0;

  if( ret > (-1) )
  {
    if( I2CRTC8564_Blk_Read( RTC8564_SEC, work, 7 ) != 0 ) return (-1);
    RTC8564Str2DateStr( date, (const unsigned char *)work );  /**/
  }

  return ret;
}

/*************************************************************************/
/*   0123456789012345678                                                 */
/*   2007/11/21 15:12:00                                                 */
/* DateStr2RTC8564Str( (unsigned char *)work, "2007/12/31 23:59:00" );   */
/* I2CRTC8564_Blk_Write( RTC8564_SEC, (const char *)work, 7 );           */
/*************************************************************************/
unsigned char *DateStr2RTC8564Str( unsigned char *dest, const char *source )
{
  dest[ 0 ] = ((source[ 17 ] & 0x07) << 4) | (source[ 18 ] & 0x0f);  /*second*/
  dest[ 1 ] = ((source[ 14 ] & 0x07) << 4) | (source[ 15 ] & 0x0f);  /*minute*/
  dest[ 2 ] = ((source[ 11 ] & 0x03) << 4) | (source[ 12 ] & 0x0f);  /*hour*/
  dest[ 3 ] = ((source[ 8 ] & 0x03) << 4) | (source[ 9 ] & 0x0f);  /*day*/
  dest[ 4 ] = 0;  /*week*/
  dest[ 5 ] = ((source[ 5 ] & 0x01) << 4) | (source[ 6 ] & 0x0f);  /*month*/
  dest[ 6 ] = ((source[ 2 ] & 0x0f) << 4) | (source[ 3 ] & 0x0f);  /*year*/

  return dest;
}

/*************************************************************************/
/*   0123456789012345678                                                 */
/*   2007/11/21 15:12:00                                                 */
/*************************************************************************/
char *RTC8564Str2DateStr( char *dest, const unsigned char source[] )
{
  dest[ 0 ] = '2';
  dest[ 1 ] = '0';
  dest[ 2 ] = (source[YEARS] >> 4) + '0';
  dest[ 3 ] = (source[YEARS] & 0x0f) + '0';
  dest[ 4 ] = '/';
  dest[ 5 ] = ((source[MONTHS] >> 4) & 0x01) + '0';
  dest[ 6 ] = (source[MONTHS] & 0x0f) + '0';
  dest[ 7 ] = '/';
  dest[ 8 ] = ((source[DAYS] >> 4) & 0x03) + '0';
  dest[ 9 ] = (source[DAYS] & 0x0f) + '0';
  dest[ 10 ] = ' ';
  dest[ 11 ] = ((source[HOURS] >> 4) & 0x03) + '0';
  dest[ 12 ] = (source[HOURS] & 0x0f) + '0';
  dest[ 13 ] = ':';
  dest[ 14 ] = ((source[MINUTES] >> 4) & 0x07) + '0';
  dest[ 15 ] = (source[MINUTES] & 0x0f) + '0';
  dest[ 16 ] = ':';
  dest[ 17 ] = ((source[SECONDS] >> 4) & 0x07) + '0';
  dest[ 18 ] = (source[SECONDS] & 0x0f) + '0';
  dest[ 19 ] = '\0';

  return dest;
}

/*************************************************************************/
/* RTC-8564 Calender Set                                                 */
/*************************************************************************/
int RTC8564_CalenderSet( const char *date_time )
{
  int i;
  unsigned char rtc_adr,work[ 8 ];

  DateStr2RTC8564Str( work, date_time );

  /*timer stop*/
  if( I2CRTC8564_Write( RTC8564_CTRL1, 0x20 ) != 0 ) return (-1);

  /*date and time write*/
  for( rtc_adr = RTC8564_SEC, i = 0; rtc_adr <= RTC8564_YEAR; rtc_adr++ )
  {
    if( I2CRTC8564_Write( rtc_adr, work[ i++ ] ) != 0 ) return (-1);
  }

  /*timer start*/
  if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);

  return 0;
}

/***********************************************************************/
/*                                               designed by hamayan   */
/*                                               Copyright(C) hamayan  */
/***********************************************************************/


Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



printfって便利だよね [アプリケーション]

Img_2092.jpgLiquidCrystalのprintライブラリは軽くて良いのですけれど、ちょっと不便なんですよね。
やっぱりprintfの簡単さは捨て難い物がある。特にデバッカーのサポートを受け難いArduinoでは、メッセージの出し方で随分開発効率が変わってくる。

と言う訳でツイッターでprintfの実現方法に触れられていましたので、LCD出力に適用してみました。

簡単なスケッチを下記に記載しておきます。
LCDとの接続はスケッチを参考としてください。と言うか、適宜自分の環境に合わせて変更してください。
※浮動小数点型には対応していないみたいです。
※生成可能な文字列の最大は、以下のスケッチなら127です。
#include <string.h>
#include <stdarg.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 10, 5, 4, 3, 2);

void LCDPrintf( const char *fmt, ... )
{
  char tmp[128];
  va_list args;
  va_start( args, fmt );
  vsnprintf( tmp, sizeof(tmp), fmt, args );
  va_end( args );
  lcd.print( tmp );
}

void setup()
{
  lcd.begin(16, 2);
  lcd.clear();
  LCDPrintf( "designed by hamayan." );
}

void loop()
{
  static int i;

  lcd.setCursor(0,1);
  LCDPrintf( "count %+04d", i-- );
  delay( 100 );
}


新版 明解C言語 入門編

新版 明解C言語 入門編

  • 作者: 柴田望洋
  • 出版社/メーカー: ソフトバンククリエイティブ
  • 発売日: 2004/08/28
  • メディア: 単行本



プログラミング言語C 第2版 ANSI規格準拠

プログラミング言語C 第2版 ANSI規格準拠

  • 作者: B.W. カーニハン
  • 出版社/メーカー: 共立出版
  • 発売日: 1989/06/15
  • メディア: 単行本



MaruduinoでDual Displayを実現する [アプリケーション]

実際のところとっても簡単に表示でき、情報量が2倍~です(笑)。
※タイプミスしているし(笑)
※ああ勿論、もっと沢山のLCDを増設できるんですよ。

Img_2092.jpg方法をご紹介するだけなので、サンプルアプリケーションも手抜きでexampleのHello,Worldを流用します。

まずその前に接続を行う必要があります。
今回使用するLCDは、基本パーツセットのLCDと、Prototyping Labの著者の小林様に譲っていただいたLCDシールド基板を組み立てた、この2つです。

LCDシールド基板の配線は既に基板上で行われていますので、敢えていじる所はありません。
基本パーツセットのLCDはご存知の様にユーザーが好きな接続を選べる様になっています。
以下の様に配線してください。

DI12(CN5)をRS(CN14)
DI10(CN5)をE(CN14)
DI5(CN5)をD4(CN14)
DI4(CN5)をD5(CN14)
DI3(CN5)をD6(CN14)
DI2(CN5)をD7(CN14)
です。つまりHello,Worldの基本的な接続の内、信号線Eへの配線が異なるのみです。
これは、個々のLCDを識別する為の信号線はEのみで済み、それ以外は共通化できるからです。
Eのみ個別の接続にし、新たにLCDインスタンスを生成すれば、LiquidCrystalライブラリで今まで通りに2つのLCDの制御が可能となります。

では具体的に改造したスケッチを以下に記載しておきます。すっごい簡単ですね。この辺がArduinoの良いところです。
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LiquidCrystal lcd2(12, 10, 5, 4, 3, 2);

void setup() {
  // set up the LCD's number of rows and columns: 
  lcd.begin(16, 2);
  lcd2.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("LCD1 display demo.");
  lcd2.print("LCD2 display demo.");
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  lcd2.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis()/1000);
  lcd2.print(millis()/1000);
}


Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



武蔵野電波のブレッドボーダーズ―誰でも作れる!遊べる電子工作

武蔵野電波のブレッドボーダーズ―誰でも作れる!遊べる電子工作

  • 作者: スタパ齋藤
  • 出版社/メーカー: オーム社
  • 発売日: 2009/11
  • メディア: 単行本



Maruduinoにシールド基板を搭載する。 [組み立て]

Img_2090.jpgMaruduinoもシールド基板を搭載する事ができます。
何故かここの実装について今まで書いていなかったので、今回、書いておきます。



Img_2089.jpgシングルラインのソケットヘッダー(6ピン2個と8ピン2個)を実装しますが、やはり一旦シールド基板側にソケットヘッダーを挿してしまって、その上でMaruduinoと合体させると、ヘッダーを気持ちよく実装できます。

ひっくり返して四隅を半田付け後、問題が無い事を確認したら全部半田付けして完了です。

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



Maruduinoで時計を作る。リアルタイムクロック(RTC MRX-8564)の利用。 [アプリケーション]

組み立て編はこちらです。
http://maruduino.blog.so-net.ne.jp/2010-08-07

Img_2082.jpg組み立てが完了したので、簡単な?スケッチを記述してみました。ご参考になれば幸いです。
Wireライブラリを使って通信してみたのですが、あまり安定しない、読み出しがおかしい?などがあったので、ソフトウエアでI2C通信を実現しています。
Arduinoは勿論マスターモードとしています。

操作方法を書いておきます。

時刻設定モード:
SW1とSW3の同時押しで時刻設定モードに入ります。
LCDの上段には変更する日付または時刻が表示され、下段には変更位置を示すポインターが表示されています。
SW2で数字を増やし、SW3で数字を減らしますが、上限、下限まで達すると循環します。
数字が確定したらSW4で次の項目に移動します。最後の項目である秒の変更が完了してSW4を押すと、その時点で時刻設定が確定します。
※SW1を押すと入力を取りやめ、通常の時刻表示モードに戻ります。
日付や時刻の整合性はあまりチェックしていませんので、注意してください。

アラーム設定モード:
SW1とSW2の同時押しでアラーム設定モードに入ります。
時刻設定モードと同様上段には時刻、下段にはポインターが表示されます。
その他操作も時刻設定モードと同じです。
時刻の整合性はあまりチェックしていませんので、注意してください。
※アラームを鳴らしたくない時は24:00に設定してください。

アラーム鳴動解除:
アラーム鳴動中にSW1を押す事で鳴動を解除できます。

バッテリーバックアップがされているので、電源を落としても時刻の更新やアラーム時刻の保持は行われています。


こうやってプロトタイピングして、もっとコンパクトであったり、電池で駆動できるものを作って日々の生活に役立てるとか良いですよね。
実際、Arduinoではありませんが、別のOne Chipマイコンで作った自作の目覚まし時計に日々起こされていますヨ。

以下にスケッチを記述しておきます。
※関数time_adjust_mode、Alarm_set_modeにアトミックな処理を追加 2010/08/07 18:35
/***********************************************************************/
/* LCD clock                                                           */
/* I2C bus control RTC()RTC8564 use                                    */
/*                                               designed by hamayan   */
/*                                               Copyright(C) hamayan  */
/***********************************************************************/
#define  _SOFT_I2C_
  
#if defined( _SOFT_I2C_ )
#else
#include <Wire.h>
#endif

#include <string.h>
#include <LiquidCrystal.h>
#include <avr/io.h>

/*************************************************************************/
/* defines                                                               */
/*************************************************************************/
#define  DI13     13
#define  DI12     12
#define  DI11     11
#define  DI10     10
#define  DI9      9
#define  DI8      8
#define  DI7      7
#define  DI6      6
#define  DI5      5
#define  DI4      4
#define  DI3      3
#define  DI2      2
#define  DI1      1
#define  DI0      0
#define  AN0      14
#define  AN1      15
#define  AN2      16
#define  AN3      17
#define  AN4      18
#define  AN5      19

#define  SW1      AN3
#define  SW2      AN2
#define  SW3      AN1
#define  SW4      AN0

#define  SCL_BIT         0b00100000   /*PC5=SCL*/
#define  SDA_BIT         0b00010000   /*PC4=SDA*/
#define  SCL_IS_HIGH     PORTC |= SCL_BIT  /*about 120ns swittching*/
#define  SCL_IS_LOW      PORTC &= ~SCL_BIT  /*about 120ns swittching*/
#define  SDA_IS_HIGH     PORTC |= SDA_BIT  /*about 120ns swittching*/
#define  SDA_IS_LOW      PORTC &= ~SDA_BIT  /*about 120ns swittching*/
#define  SDA_OUTPUT      DDRC |= SDA_BIT
#define  SDA_INPUT       DDRC &= ~SDA_BIT
#define  SCL_OUTPUT      DDRC |= SCL_BIT

#define  ACK             0  /*ACK Bit*/
#define  NACK            1  /*NACK Bit*/

#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

#if defined( _SOFT_I2C_ )
#define  RTC_BASE_ADDR      (0xa2)
#else
#define  RTC_BASE_ADDR      (0xa2 >> 1)
#endif

/*************************************************************************/
/*  global parameter                                                     */
/*************************************************************************/
enum RTC8564Str {SECONDS,MINUTES,HOURS,DAYS,WEEKDAYS,MONTHS,YEARS};

/* 0123456789012345678 */
/* 2007/11/21 15:12:00 */
char date[ 20 ];  /**/
char alarm_set_time[] = "00:00";

unsigned long sectim;
unsigned long lasttim;
unsigned char switches[3];
boolean  clock_disp = false;

const char date_limit[][2] = /*offset = 2*/
{
  {'0','9'},  /*year 10*/
  {'0','9'},  /*year 1*/
  {'/','/'},  /**/
  {'0','1'},  /*month 10*/
  {'0','9'},  /*month 1*/
  {'/','/'},  /**/
  {'0','3'},  /*day 10*/
  {'0','9'},  /*day 1*/
};
const char time_limit[][2] = /*offset = 0*/
{
  {'0','2'},  /*hour 10*/
  {'0','9'},  /*hour 1*/
  {':',':'},  /**/
  {'0','5'},  /*monite 10*/
  {'0','9'},  /*monite 1*/
  {':',':'},  /**/
  {'0','5'},  /*second 10*/
  {'0','9'},  /*second 1*/
};

LiquidCrystal lcd(DI8, DI9, DI4, DI5, DI6, DI7);

/*************************************************************************/
/*  prototype                                                            */
/*************************************************************************/
static void clk100( void );
static void I2C_Terminate( void );
static void StartCondition( void );
static void StopCondition( void );
static int RcvAck( void );
static void ResAck( int ack );
static void BitWrite( int data );
static int BitRead( void );
static int ByteWrite( int data );
static int ByteRead( int ack );

static void date_print( const char *src, int x, int y );
static void time_print( const char *src, int x, int y );
static void ConvertFromRTC2DateTime( void );

void I2C_Init( void );
int I2C_Block_Write( int addr, const char *data, int size );
int I2C_Block_Read( int addr, char *data, int size );
int I2C_Write( int addr, unsigned char data );
int I2C_Read( int addr, unsigned char *data );

int InitRTC8564( int force );
unsigned char *DateStr2RTC8564Str( unsigned char *dest, const char *source );
char *RTC8564Str2DateStr( char *dest, const unsigned char source[] );
int I2CRTC8564_Write( unsigned char addr, char data );
int I2CRTC8564_Read( unsigned char addr, char *buff );
int I2CRTC8564_Blk_Read( unsigned char addr, char *buff, int size );
int I2CRTC8564_Blk_Write( unsigned char addr, const char *data, int size );
int RTC8564_CalenderSet( const char *date_time );

#define  CalenderRead(buf)  I2CRTC8564_Blk_Read(RTC8564_SEC, buf, 7)

/*************************************************************************/
/*  digital2 external int handler                                        */
/*************************************************************************/
static void di2_int_hdr( void )
{
  sectim++;
  ConvertFromRTC2DateTime();  /*update clock*/
  if( clock_disp == true )
  {
    date_print(date,0,0);
    time_print(date,2,1);
  }
}

/*************************************************************************/
/*  Switch down detection                                                */
/*************************************************************************/
static unsigned char detect_sw_down( unsigned char *sw )
{
  unsigned char temp = PINC & 0x0f;

  sw[0] = sw[1];
  sw[1] = sw[2];
  sw[2] = temp ^ 0x0f;

  return sw[0] & sw[1] & temp;
}

/*************************************************************************/
/*  RTC8564 data convert to date time strings.                           */
/*************************************************************************/
static void ConvertFromRTC2DateTime( void )
{
  char buf[10];

  CalenderRead( buf );
  RTC8564Str2DateStr( date, (const unsigned char *)buf );  /**/
}

/*************************************************************************/
/*  Date lcd print                                                       */
/*************************************************************************/
static void date_print( const char *src, int x, int y )
{
  char buf[16];

  memcpy( buf, src, 10 );
  buf[10] = '\0';
  lcd.setCursor(x,y);
  lcd.print( buf );
}

/*************************************************************************/
/*  Time lcd print                                                       */
/*************************************************************************/
static void time_print( const char *src, int x, int y )
{
  char buf[16];

  memcpy( buf, &src[11], 8 );
  buf[8] = '\0';
  lcd.setCursor(x,y);
  lcd.print( buf );
}

/*************************************************************************/
/*  Time adjust                                                          */
/*************************************************************************/
static void time_adjust_mode( void )
{
  int pos = 2;
  char copy_date[20];
  boolean loop = true;

  memcpy( copy_date, date, sizeof(copy_date) );
  lcd.clear();
  date_print(copy_date,0,0);
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 10 )
        {
          loop = false;
          break;
        }
        if( pos == 4 || pos == 7 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --copy_date[pos] < date_limit[pos - 2][0] ) copy_date[pos] = date_limit[pos - 2][1];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos] );
        break;
      case 0b00000100:  /*up number*/
        if( ++copy_date[pos] > date_limit[pos - 2][1] ) copy_date[pos] = date_limit[pos - 2][0];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  pos = 0;
  loop = true;
  lcd.clear();
  time_print(copy_date,0,0);
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 8 )
        {
          loop = false;
          break;
        }
        if( pos == 2 || pos == 5 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --copy_date[pos + 11] < time_limit[pos][0] ) copy_date[pos + 11] = time_limit[pos][1];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos + 11] );
        break;
      case 0b00000100:  /*up number*/
        if( ++copy_date[pos + 11] > time_limit[pos][1] ) copy_date[pos + 11] = time_limit[pos][0];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos + 11] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  memcpy( date, copy_date, sizeof(date) );
  RTC8564_CalenderSet( date );  /*update calender.*/
  EIMSK |= 0x01;   /*int0 interrupt enable*/
}

/*************************************************************************/
/*  Alarm set                                                            */
/*************************************************************************/
static void Alarm_set_mode( void )
{
  int pos = 0;
  unsigned char temp;
  boolean loop = true;

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print( alarm_set_time );
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 5 )
        {
          loop = false;
          break;
        }
        if( pos == 2 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --alarm_set_time[pos] < time_limit[pos][0] ) alarm_set_time[pos] = time_limit[pos][1];
        lcd.setCursor(pos,0);
        lcd.print( alarm_set_time[pos] );
        break;
      case 0b00000100:  /*up number*/
        if( ++alarm_set_time[pos] > time_limit[pos][1] ) alarm_set_time[pos] = time_limit[pos][0];
        lcd.setCursor(pos,0);
        lcd.print( alarm_set_time[pos] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  temp = ((alarm_set_time[3] & 0x0f) << 4) + (alarm_set_time[4] & 0x0f);
  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  I2CRTC8564_Write( RTC8564_MIN_ALM, temp );
  EIMSK |= 0x01;   /*int0 interrupt enable*/

  temp = ((alarm_set_time[0] & 0x0f) << 4) + (alarm_set_time[1] & 0x0f);
  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  I2CRTC8564_Write( RTC8564_HOUR_ALM, temp );
  EIMSK |= 0x01;   /*int0 interrupt enable*/
}

/*************************************************************************/
/*  setup                                                                */
/*************************************************************************/
void setup()
{
  char buf[16];
  unsigned char temp;
//  static const char date_time[] = "2010/08/07 02:04:00";

  lcd.begin(16, 2);
  lcd.clear();
  lcd.println( "designed by hamayan." );

#if defined( _SOFT_I2C_ )
  I2C_Init();
#else  /*_SOFT_I2C_*/
  Wire.begin();  /*set i2c master device*/
  TWSR &= 0xfc;  /*baud rate control. prescaler=x1*/
  TWBR = 72;     /*baud rate control. 100khz*/
#endif  /*_SOFT_I2C_*/

  delay( 1000 );
  if( InitRTC8564( 0 ) < 0 )
  {
    lcd.clear();
    lcd.println( "rtc init error." );
    while(1) ;
  }

  I2CRTC8564_Read( RTC8564_MIN_ALM, (char *)&temp );
  if( !(temp & 0x80) )
  {
    alarm_set_time[3] = ((temp >> 4) & 0x07) + '0';
    alarm_set_time[4] = (temp & 0x0f) + '0';
    I2CRTC8564_Read( RTC8564_HOUR_ALM, (char *)&temp );
    alarm_set_time[0] = ((temp >> 4) & 0x03) + '0';
    alarm_set_time[1] = (temp & 0x0f) + '0';
  }

//  RTC8564_CalenderSet( date_time );  /*force setting calender.*/

  pinMode( SW1, INPUT );  /*set port at input mode*/
  pinMode( SW2, INPUT );  /*set port at input mode*/
  pinMode( SW3, INPUT );  /*set port at input mode*/
  pinMode( SW4, INPUT );  /*set port at input mode*/

  /*enable edge trigger interrupt*/
  attachInterrupt(0, di2_int_hdr, FALLING);
  DDRD &= ~0b00000100;  /*direction input*/
  PORTD |= 0b00000100;  /*enable pullup*/

  /*display alarm set time*/
  lcd.clear();
  lcd.setCursor(11,1);
  lcd.print( alarm_set_time );
  clock_disp = true;
  lasttim = millis() + 100;
}

/*************************************************************************/
/*  main loop                                                            */
/*************************************************************************/
void loop()
{
#define  ALARM_PERIOD  (60 * 5)
  unsigned char temp;
  static unsigned long oldsec;
  static int alarm_time;

  if( millis() > lasttim )
  {
    lasttim = millis() + 100;  /*next sample time update.*/
    switch ( detect_sw_down( switches ) )
    {
      case 0b00001010 :  /*time adjust mode*/
        clock_disp = false;
        time_adjust_mode();
        lcd.clear();
        lcd.setCursor(11,1);
        lcd.print( alarm_set_time );
        clock_disp = true;
        break;
      case 0b00001100 :  /*alarm set mode*/
        clock_disp = false;
        Alarm_set_mode();
        lcd.clear();
        lcd.setCursor(11,1);
        lcd.print( alarm_set_time );
        clock_disp = true;
        break;
      case 0b00001000 :  /*stop alarm*/
        alarm_time = 0;
        break;
      default :
        break;
    }
  }

  if( oldsec != sectim )
  {
    oldsec = sectim;

    if( date[18] == '0' &&
        date[17] == '0' &&
        alarm_set_time[4] == date[15] &&
        alarm_set_time[3] == date[14] &&
        alarm_set_time[1] == date[12] &&
        alarm_set_time[0] == date[11] )
      alarm_time = ALARM_PERIOD;  /*? minutes*/

    if( --alarm_time > 0 )
    {
      if( alarm_time % 3 ) tone( DI13, 1000, 800 );
    }
    else alarm_time = 0;
  }
}

/*************************************************************************/
/*  wait functions                                                       */
/*************************************************************************/
#define  wait1u()    delayMicroseconds(1)
#define  wait5u()    delayMicroseconds(5)

/*************************************************************************/
/*  100 clocks function                                                  */
/*************************************************************************/
static void clk100( void )
{
  int i;

  /*i2c lock release*/
  for( i = 0; i < 100; i++ )
  {
    SCL_IS_LOW;
    wait1u();
    SCL_IS_HIGH;
    wait1u();
  }
}

/*************************************************************************/
/*  initialize function                                                  */
/*************************************************************************/
void I2C_Init( void )
{
  int i;

  PORTC |= SDA_BIT | SCL_BIT;
  DDRC |= SDA_BIT | SCL_BIT;  /*pc4=sda,pc5=scl*/

  for( i = 0; i < 100; i++ )
  {
    SCL_IS_LOW;
    wait1u();
    SCL_IS_HIGH;
    wait1u();
  }
  SDA_IS_LOW;

  StopCondition();
  wait5u();
}

/*************************************************************************/
/*  I2C Terminate function                                               */
/*************************************************************************/
static void I2C_Terminate( void )
{
  SCL_OUTPUT;
  SDA_OUTPUT;

  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/

  SDA_IS_HIGH;
}

/*************************************************************************/
/*  start condition                                                      */
/*************************************************************************/
static void StartCondition( void )
{
  I2C_Terminate();
  wait1u();

  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/

  SCL_IS_LOW;
}

/*************************************************************************/
/*  stop condition                                                       */
/*************************************************************************/
static void StopCondition( void )
{
  SCL_OUTPUT;
  SDA_OUTPUT;

  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/

  SDA_IS_HIGH;
}

/*************************************************************************/
/*  ACK confirm function                                                 */
/*************************************************************************/
static int RcvAck( void )
{
  int ret;

  SCL_IS_LOW;  /*about 120ns*/
  SDA_INPUT;
  wait1u();
  SCL_IS_HIGH;
  ret = (PINC & SDA_BIT) ? 1 : 0;
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SDA_OUTPUT;
  SCL_IS_LOW;

  return ret;
}

/*************************************************************************/
/*  ACK responce function                                                */
/*************************************************************************/
static void ResAck( int ack )
{
  SCL_IS_LOW;  /*about 120ns*/
  if(ack) SDA_IS_HIGH;
  else SDA_IS_LOW; 
  wait1u();
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_LOW;
  SDA_IS_LOW;
}

/*************************************************************************/
/*  Bit Write function                                                   */
/*************************************************************************/
static void BitWrite( int data )
{
  SCL_IS_LOW;  /*about 120ns*/
  if(data) SDA_IS_HIGH;
  else SDA_IS_LOW; 
  wait1u();
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_LOW;
  SDA_IS_LOW;
}

/*************************************************************************/
/*  Bit Read function                                                    */
/*************************************************************************/
static int BitRead( void )
{
  int ret;

  SCL_IS_LOW;  /*about 120ns*/
  wait1u();
  SCL_IS_HIGH;
  ret = (PINC & SDA_BIT) ? 1 : 0;
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_LOW;

  return ret;
}

/*************************************************************************/
/*  Byte Write function                                                  */
/*************************************************************************/
static int ByteWrite( int data )
{
  BitWrite( data & 0x80 );
  BitWrite( data & 0x40 );
  BitWrite( data & 0x20 );
  BitWrite( data & 0x10 );
  BitWrite( data & 0x08 );
  BitWrite( data & 0x04 );
  BitWrite( data & 0x02 );
  BitWrite( data & 0x01 );
//  SDA_IS_LOW;

  return ( RcvAck() == 0 ) ? 0 : (-1);
}

/*************************************************************************/
/*  Byte Read function                                                   */
/*************************************************************************/
static int ByteRead( int ack )
{
  int data = 0;

  SDA_INPUT;
  data |= ( BitRead() ) ? 0x80 : 0x00;
  data |= ( BitRead() ) ? 0x40 : 0x00;
  data |= ( BitRead() ) ? 0x20 : 0x00;
  data |= ( BitRead() ) ? 0x10 : 0x00;
  data |= ( BitRead() ) ? 0x08 : 0x00;
  data |= ( BitRead() ) ? 0x04 : 0x00;
  data |= ( BitRead() ) ? 0x02 : 0x00;
  data |= ( BitRead() ) ? 0x01 : 0x00;
  SDA_OUTPUT;
  ResAck( ack );

  return data;
}

/*************************************************************************/
/*  I2C Block Write function                                             */
/*************************************************************************/
int I2C_Block_Write( int addr, const char *data, int size )
{
  StartCondition();

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    return (-1);
  }

  for( ; size > 0; size-- )
  {
    if( ByteWrite( *data++ ) == (-1) )
    {
      I2C_Terminate();

      return (-1);
    }
  }

  StopCondition();

  return 0;
}

/*************************************************************************/
/*  I2C Block Read function                                              */
/*************************************************************************/
int I2C_Block_Read( int addr, char *data, int size )
{
  StartCondition();
  if( ByteWrite( addr | 0x01 ) == (-1) )
  {
    I2C_Terminate();
    return (-1);
  }

  for( ; size > 0; size-- ) *data++ = ByteRead( (size == 1) ? 1 : 0 );

  StopCondition();

  return 0;
}

/*************************************************************************/
/*  I2C Write function                                                   */
/*************************************************************************/
int I2C_Write( int addr, unsigned char data )
{
#if defined( _SOFT_I2C_ )
  StartCondition();

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( data ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  StopCondition();

  return 0;

#else  /*_SOFT_I2C_*/
  Wire.beginTransmission( addr );
  Wire.send( data );
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/*  I2C Read function                                                    */
/*************************************************************************/
int I2C_Read( int addr, unsigned char *data )
{
#if defined( _SOFT_I2C_ )
  StartCondition();

  if( ByteWrite( addr | 0x01 ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  *data = ByteRead( 1 );

  StopCondition();

  return 0;
#else  /*_SOFT_I2C_*/
  Wire.requestFrom( addr, 1 );
  while( Wire.available() == 0 ) ;
  *data = Wire.receive();
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/* I2CRTC8564_Write                                                      */
/*************************************************************************/
int I2CRTC8564_Write( unsigned char addr, char data )
{
#if defined( _SOFT_I2C_ )
  StartCondition();

  if( ByteWrite( RTC_BASE_ADDR ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( data ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  StopCondition();

  return 0;
#else  /*_SOFT_I2C_*/
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );
  Wire.send( data );
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/* I2CRTC8564_Read                                                       */
/*************************************************************************/
int I2CRTC8564_Read( unsigned char addr, char *buff )
{
#if defined( _SOFT_I2C_ )
  StartCondition();

  if( ByteWrite( RTC_BASE_ADDR ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  SDA_IS_HIGH;
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/

  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/

  if( ByteWrite( RTC_BASE_ADDR | 0x01 ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  *buff = ByteRead( 1 );

  StopCondition();

  return 0;

#else  /*_SOFT_I2C_*/
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );

  Wire.requestFrom( RTC_BASE_ADDR, 1 );
  while( Wire.available() == 0 ) ;
  *buff = Wire.receive();
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/* I2CRTC8564_Blk_Read                                                   */
/*************************************************************************/
int I2CRTC8564_Blk_Read( unsigned char addr, char *buff, int size )
{
#if defined( _SOFT_I2C_ )
  char *ptr = buff;
  char *limit = &buff[ size - 1 ];

  StartCondition();

  if( ByteWrite( RTC_BASE_ADDR ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  SDA_IS_HIGH;
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/

  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/

  if( ByteWrite( RTC_BASE_ADDR | 0x01 ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  while( ptr < limit )
  {
    *ptr++ = ByteRead( 0 );
  }
  *ptr = ByteRead( 1 );

  StopCondition();

  return 0;

#else  /*_SOFT_I2C_*/
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );

  Wire.requestFrom( RTC_BASE_ADDR, size );
  while( Wire.available() < size ) ;
  for( ; size > 0; size-- )
  {
    *buff++ = Wire.receive();
  }
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/* I2CRTC8564_Blk_Write                                                  */
/*************************************************************************/
int I2CRTC8564_Blk_Write( unsigned char addr, const char *data, int size )
{
#if defined( _SOFT_I2C_ )
  const char *ptr = data;
  const char *limit = &data[ size ];

  StartCondition();

  if( ByteWrite( RTC_BASE_ADDR ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  while( ptr < limit )
  {
    if( ByteWrite( *ptr++ ) == (-1) )
    {
      I2C_Terminate();
      clk100();
      return (-1);
    }
  }

  StopCondition();
  return 0;

#endif  /*_SOFT_I2C_*/
  return 0;
}

/*************************************************************************/
/* RTC-8564 initialize                                                   */
/*************************************************************************/
int InitRTC8564( int force )
{
  int i,ret;
  char temp,date_time[ 7 ],work[ 8 ];
  unsigned char rtc_adr;
  static const unsigned char RTC8564_Init_Code[] =
    {0x20, 0x11, 0x00,0x10,0x18,0x07,0x04,0x05, 0x10,0x80, 0x80,  0x80, 0x80,  0x00,0x81,63  };
   /*ctrl1,ctrl2,sec, min, hour,day, week,month,year,min_a,hour_a,day_a,week_a,freq,cont,timer*/

  /*RTC8564 confirmed VLbit*/
  if( I2CRTC8564_Read( RTC8564_SEC, &date_time[ SECONDS ] ) != 0 ) return (-1);

  if( date_time[ SECONDS ] & 0x80 || force )  /*VLbit was 1 then detected low voltage*/
  {
    for( rtc_adr = 0; rtc_adr <= sizeof( RTC8564_Init_Code ); rtc_adr++ )
    {
      if( I2CRTC8564_Write( rtc_adr, RTC8564_Init_Code[ rtc_adr ] ) != 0 ) return (-1);
    }
    if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);  /*timer start*/

    for( i = 0; i < 100; i++ )
    {
      if( I2CRTC8564_Read( RTC8564_YEAR, &date_time[ YEARS ] ) != 0 ) return (-1);  /*RTC is not there.*/

      if( date_time[ YEARS ] == RTC8564_Init_Code[ RTC8564_YEAR ] )  /**/
      {
        break;
      }
      else
      {
        for( rtc_adr = 0; rtc_adr <= sizeof( RTC8564_Init_Code ); rtc_adr++ )
        {
          if( I2CRTC8564_Write( rtc_adr, RTC8564_Init_Code[ rtc_adr ] ) != 0 ) return (-1);
        }
        if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);
      }
    }
    if( i != 100 ) ret = 1;  /**/
    else ret = (-2);  /*initialize error*/
  }
  else ret = 0;

  if( ret > (-1) )
  {
    if( I2CRTC8564_Blk_Read( RTC8564_SEC, work, 7 ) != 0 ) return (-1);
    RTC8564Str2DateStr( date, (const unsigned char *)work );  /**/
  }

  return ret;
}

/*************************************************************************/
/*   0123456789012345678                                                 */
/*   2007/11/21 15:12:00                                                 */
/* DateStr2RTC8564Str( (unsigned char *)work, "2007/12/31 23:59:00" );   */
/* I2CRTC8564_Blk_Write( RTC8564_SEC, (const char *)work, 7 );           */
/*************************************************************************/
unsigned char *DateStr2RTC8564Str( unsigned char *dest, const char *source )
{
  dest[ 0 ] = ((source[ 17 ] & 0x07) << 4) | (source[ 18 ] & 0x0f);  /*second*/
  dest[ 1 ] = ((source[ 14 ] & 0x07) << 4) | (source[ 15 ] & 0x0f);  /*minute*/
  dest[ 2 ] = ((source[ 11 ] & 0x03) << 4) | (source[ 12 ] & 0x0f);  /*hour*/
  dest[ 3 ] = ((source[ 8 ] & 0x03) << 4) | (source[ 9 ] & 0x0f);  /*day*/
  dest[ 4 ] = 0;  /*week*/
  dest[ 5 ] = ((source[ 5 ] & 0x01) << 4) | (source[ 6 ] & 0x0f);  /*month*/
  dest[ 6 ] = ((source[ 2 ] & 0x0f) << 4) | (source[ 3 ] & 0x0f);  /*year*/

  return dest;
}

/*************************************************************************/
/*   0123456789012345678                                                 */
/*   2007/11/21 15:12:00                                                 */
/*************************************************************************/
char *RTC8564Str2DateStr( char *dest, const unsigned char source[] )
{
  dest[ 0 ] = '2';
  dest[ 1 ] = '0';
  dest[ 2 ] = (source[YEARS] >> 4) + '0';
  dest[ 3 ] = (source[YEARS] & 0x0f) + '0';
  dest[ 4 ] = '/';
  dest[ 5 ] = ((source[MONTHS] >> 4) & 0x01) + '0';
  dest[ 6 ] = (source[MONTHS] & 0x0f) + '0';
  dest[ 7 ] = '/';
  dest[ 8 ] = ((source[DAYS] >> 4) & 0x03) + '0';
  dest[ 9 ] = (source[DAYS] & 0x0f) + '0';
  dest[ 10 ] = ' ';
  dest[ 11 ] = ((source[HOURS] >> 4) & 0x03) + '0';
  dest[ 12 ] = (source[HOURS] & 0x0f) + '0';
  dest[ 13 ] = ':';
  dest[ 14 ] = ((source[MINUTES] >> 4) & 0x07) + '0';
  dest[ 15 ] = (source[MINUTES] & 0x0f) + '0';
  dest[ 16 ] = ':';
  dest[ 17 ] = ((source[SECONDS] >> 4) & 0x07) + '0';
  dest[ 18 ] = (source[SECONDS] & 0x0f) + '0';
  dest[ 19 ] = '\0';

  return dest;
}

/*************************************************************************/
/* RTC-8564 Calender Set                                                 */
/*************************************************************************/
int RTC8564_CalenderSet( const char *date_time )
{
  int i;
  unsigned char rtc_adr,work[ 8 ];

  DateStr2RTC8564Str( work, date_time );

  /*timer stop*/
  if( I2CRTC8564_Write( RTC8564_CTRL1, 0x20 ) != 0 ) return (-1);

  /*date and time write*/
  for( rtc_adr = RTC8564_SEC, i = 0; rtc_adr <= RTC8564_YEAR; rtc_adr++ )
  {
    if( I2CRTC8564_Write( rtc_adr, work[ i++ ] ) != 0 ) return (-1);
  }

  /*timer start*/
  if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);

  return 0;
}

/***********************************************************************/
/*                                               designed by hamayan   */
/*                                               Copyright(C) hamayan  */
/***********************************************************************/


Arduinoをはじめよう

Arduinoをはじめよう

  • 作者: Massimo Banzi
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2009/03/27
  • メディア: 単行本(ソフトカバー)



ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

  • 作者: 濱原 和明
  • 出版社/メーカー: オーム社
  • 発売日: 2005/04/25
  • メディア: 単行本



Maruduinoの時計機能(リアルタイムクロック)追加パーツの組み立て [組み立て]

※このリアルタイムクロック部品セットはMaruduinoの拡張機能です。実装位置がブレッドボードの位置と重なっていますので、ブレッドボードを外すか、位置をずらす必要があります。

近日中にマルツ電波さんから時計機能モジュールMRX-8564が発売となりますので、RTC(Real Time Clock)周りの実装について解説します。

Img_2076.jpgまず背の低い部品と言う事で2つのダイオードを実装します。極性方向に注意してください。

左のD7はショットキーバリアダイオード(RB441Q-40)。右のD6は一般的なシリコンダイオード(1N4148)です。
どちらも代替品は沢山有ると思います。但しD6にショットキーバリアダイオードは実装しないでくださいね。バックアップ電池があっという間に無くなってしまいますから。



Img_2078.jpgMRX-8564を実装します。写真ではICソケットを使用していますが、実際のパーツセットにはICソケットは含まれていません。

ArduinoとI2CデバイスであるMRX-8564間の通信では信号線にプルアップ抵抗を必要とします。
プルアップを行う方法は2つありまして、MRX-8564上のジャンパーJ1とJ2の半田を盛ってショートするか、Maruduinoの基板上のR62~R64を実装するかです。
どちらかを使って信号線のプルアップを行います。
なおMRX-8564上のジャンパーJ3をショートすると、割込みに合わせてLEDがチカチカしますが、これはお好みで。

R62~R64のカラーコードですが、2KΩの抵抗は赤黒赤金、4.7KΩの抵抗は黄紫赤金です。



Img_2077.jpg基本パーツセットの中の6ピンソケットヘッダーをCN15に実装します。ちょっとやり難い位置にありますので、注意してください。



Img_2086.jpg半田面にコイン電池ホルダーを実装します。この電池でMRX-8564のバックアップを行い、電源が切れても時刻の更新、アラーム時刻の保持が出来るようになります。
※注意!電池を搭載するのは組み立てが完了してからです。



Img_2080.jpg裏から搭載しますので、表から半田付けを行いますが、写真手前の半田付けが結構半田が乗り難いので、しっかり温めて半田付けを行ってください。もう少しサーマルを大きく取ればよかったですね。



Img_2085.jpg必要な配線を行います。基板上の白い文字を参考にして以下を読んでください。

まずMRX-8564への配線です。
AN5(CN2)とSCL(CN15)
AN4(CN2)とSDA(CN15)
DI2(CN5)とINT(CN15)
これでArduinoからMRX-8564にアクセスできるようになります。



Img_2084.jpgLCDへの配線です。
DI8(CN5)とRS(CN14)
DI9(CN5)とE(CN14)
DI4(CN5)とD4(CN14)
DI5(CN5)とD5(CN14)
DI6(CN5)とD6(CN14)
DI7(CN5)とD7(CN14)



Img_2083.jpgスピーカー出力及びスイッチとの接続です。
DI13(CN5)とAUX1(CN11)
DI17(CN3)とSW1(CN11)
DI16(CN3)とSW2(CN11)
DI15(CN3)とSW3(CN11)
DI14(CN3)とSW4(CN11)



ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

  • 作者: 濱原 和明
  • 出版社/メーカー: オーム社
  • 発売日: 2005/04/25
  • メディア: 単行本



Arduinoをはじめよう

Arduinoをはじめよう

  • 作者: Massimo Banzi
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2009/03/27
  • メディア: 単行本(ソフトカバー)



Maruduino(Arduinoベースボード)基本パーツセット実装。おまけ編 [組み立て]

Img_2071.jpgこのタクトスイッチです。リセットスイッチとなっています。

MaruduinoをArduino化するキットには付属していたのですが、どうしても基本パーツセットにも欲しいので、マルツさんに付属すようにお願いしておきました。

安心してバンバンリセット掛けてください。


ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

  • 作者: 濱原 和明
  • 出版社/メーカー: オーム社
  • 発売日: 2005/04/25
  • メディア: 単行本



Arduinoをはじめよう

Arduinoをはじめよう

  • 作者: Massimo Banzi
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2009/03/27
  • メディア: 単行本(ソフトカバー)



Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。